Bug 1372276 - Remove HTML menuitem. r=smaug,mconley,agi

This removes HTMLMenuItemElement and all the code and tests preffed off
by dom.menuitem.enabled.

The HTML parser changes are the result of applying the previous patch.

Differential Revision: https://phabricator.services.mozilla.com/D149979
This commit is contained in:
Emilio Cobos Álvarez 2022-06-22 22:31:42 +00:00
Родитель 3ae00d82b4
Коммит bd09497378
53 изменённых файлов: 153 добавлений и 2312 удалений

Просмотреть файл

@ -27,11 +27,6 @@ XPCOMUtils.defineLazyModuleGetters(lazy, {
ContentDOMReference: "resource://gre/modules/ContentDOMReference.jsm",
});
XPCOMUtils.defineLazyGetter(lazy, "PageMenuChild", () => {
let pageMenu = ChromeUtils.import("resource://gre/modules/PageMenu.jsm");
return new pageMenu.PageMenuChild();
});
let contextMenus = new WeakMap();
class ContextMenuChild extends JSWindowActorChild {
@ -82,15 +77,6 @@ class ContextMenuChild extends JSWindowActorChild {
});
}
case "ContextMenu:DoCustomCommand": {
lazy.E10SUtils.wrapHandlingUserInput(
this.contentWindow,
message.data.handlingUserInput,
() => lazy.PageMenuChild.executeMenu(message.data.generatedItemId)
);
break;
}
case "ContextMenu:Hiding": {
this.context = null;
this.target = null;
@ -639,7 +625,6 @@ class ContextMenuChild extends JSWindowActorChild {
let spellInfo = null;
let editFlags = null;
let principal = null;
let customMenuItems = null;
let referrerInfo = Cc["@mozilla.org/referrer-info;1"].createInstance(
Ci.nsIReferrerInfo
@ -695,7 +680,6 @@ class ContextMenuChild extends JSWindowActorChild {
loginFillInfo,
selectionInfo,
userContextId,
customMenuItems,
contentDisposition,
frameID,
frameBrowsingContextID,
@ -714,10 +698,6 @@ class ContextMenuChild extends JSWindowActorChild {
);
}
if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT) {
data.customMenuItems = lazy.PageMenuChild.build(aEvent.composedTarget);
}
Services.obs.notifyObservers(
{ wrappedJSObject: data },
"on-prepare-contextmenu"

Просмотреть файл

@ -93,11 +93,4 @@ class ContextMenuParent extends JSWindowActorParent {
targetIdentifier,
});
}
doCustomCommand(generatedItemId, handlingUserInput) {
this.sendAsyncMessage("ContextMenu:DoCustomCommand", {
generatedItemId,
handlingUserInput,
});
}
}

Просмотреть файл

@ -47,7 +47,6 @@
</menugroup>
#endif
<menuseparator id="context-sep-navigation"/>
<menuseparator id="page-menu-separator"/>
<menuitem id="context-viewsource-goToLine"
oncommand="gViewSourceUtils.getPageActor(gContextMenu.browser).promptAndGoToLine()"/>
<menuitem id="context-viewsource-wrapLongLines"

Просмотреть файл

@ -417,14 +417,6 @@ XPCOMUtils.defineLazyGetter(this, "InlineSpellCheckerUI", () => {
return new InlineSpellChecker();
});
XPCOMUtils.defineLazyGetter(this, "PageMenuParent", () => {
// eslint-disable-next-line no-shadow
let { PageMenuParent } = ChromeUtils.import(
"resource://gre/modules/PageMenu.jsm"
);
return new PageMenuParent();
});
XPCOMUtils.defineLazyGetter(this, "PopupNotifications", () => {
// eslint-disable-next-line no-shadow
let { PopupNotifications } = ChromeUtils.import(

Просмотреть файл

@ -419,7 +419,7 @@
<menuseparator id="blockedPopupsSeparator"/>
</menupopup>
<menupopup id="contentAreaContextMenu" pagemenu="#page-menu-separator"
<menupopup id="contentAreaContextMenu"
onpopupshowing="if (event.target != this)
return true;
gContextMenu = new nsContextMenu(this, event.shiftKey);

Просмотреть файл

@ -43,7 +43,6 @@ function openContextMenu(aMessage, aBrowser, aActor) {
spellInfo,
principal,
storagePrincipal,
customMenuItems: data.customMenuItems,
documentURIObject,
docLocation: data.docLocation,
charSet: data.charSet,
@ -105,15 +104,8 @@ class nsContextMenu {
return;
}
this.hasPageMenu = false;
this.isContentSelected = !this.selectionInfo.docSelectionIsCollapsed;
if (!aIsShift) {
this.hasPageMenu = PageMenuParent.addToPopup(
this.contentData.customMenuItems,
this.browser,
aXulMenu
);
let tab =
gBrowser && gBrowser.getTabForBrowser
? gBrowser.getTabForBrowser(this.browser)
@ -329,7 +321,6 @@ class nsContextMenu {
}
initItems(aXulMenu) {
this.initPageMenuSeparator();
this.initOpenItems();
this.initNavigationItems();
this.initViewItems();
@ -359,10 +350,6 @@ class nsContextMenu {
}
}
initPageMenuSeparator() {
this.showItem("page-menu-separator", this.hasPageMenu);
}
initOpenItems() {
var isMailtoInternal = false;
if (this.onMailtoLink) {
@ -2351,10 +2338,6 @@ class nsContextMenu {
};
return createUserContextMenu(aEvent, createMenuOptions);
}
doCustomCommand(generatedItemId, handlingUserInput) {
this.actor.doCustomCommand(generatedItemId, handlingUserInput);
}
}
XPCOMUtils.defineLazyModuleGetters(nsContextMenu, {

Просмотреть файл

@ -47,8 +47,6 @@ skip-if = os == 'linux' && socketprocess_networking
support-files =
test_contextmenu_iframe.html
skip-if = os == 'linux' && socketprocess_networking
[browser_contextmenu_childprocess.js]
skip-if = os == 'linux' && socketprocess_networking
[browser_contextmenu.js]
tags = fullscreen
skip-if =

Просмотреть файл

@ -118,10 +118,6 @@ add_task(async function test_xul_text_link_label() {
add_task(async function test_setup_html() {
let url = example_base + "subtst_contextmenu.html";
await SpecialPowers.pushPrefEnv({
set: [["dom.menuitem.enabled", true]],
});
await BrowserTestUtils.openNewForegroundTab(gBrowser, url);
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
@ -1182,90 +1178,6 @@ add_task(async function test_copylinkcommand() {
});
});
add_task(async function test_pagemenu() {
let pagemenuItems = [
"+Plain item",
{ type: "", icon: "", checked: false, disabled: false },
"+Disabled item",
{ type: "", icon: "", checked: false, disabled: true },
"+Item w/ textContent",
{ type: "", icon: "", checked: false, disabled: false },
"---",
null,
"+Checkbox",
{ type: "checkbox", icon: "", checked: true, disabled: false },
"---",
null,
"+Radio1",
{ type: "checkbox", icon: "", checked: true, disabled: false },
"+Radio2",
{ type: "checkbox", icon: "", checked: false, disabled: false },
"+Radio3",
{ type: "checkbox", icon: "", checked: false, disabled: false },
"---",
null,
"+Item w/ icon",
{ type: "", icon: "favicon.ico", checked: false, disabled: false },
"+Item w/ bad icon",
{ type: "", icon: "", checked: false, disabled: false },
"---",
null,
"generated-submenu-1",
true,
[
"+Radio1",
{ type: "checkbox", icon: "", checked: false, disabled: false },
"+Radio2",
{ type: "checkbox", icon: "", checked: true, disabled: false },
"+Radio3",
{ type: "checkbox", icon: "", checked: false, disabled: false },
"---",
null,
"+Checkbox",
{ type: "checkbox", icon: "", checked: false, disabled: false },
],
null,
"---",
null,
"context-savepage",
true,
...(hasPocket ? ["context-pocket", true] : []),
"context-selectall",
true,
"---",
null,
"context-take-screenshot",
true,
"---",
null,
"context-viewsource",
true,
];
pagemenuItems = NAVIGATION_ITEMS.concat(pagemenuItems);
if (AppConstants.platform == "macosx") {
// Take out the bookmarks page menu:
let bookmarkItemIndex = pagemenuItems.indexOf("context-bookmarkpage");
let bookmarksItemAndSeparator = pagemenuItems.splice(bookmarkItemIndex, 2);
// Put it back before the save page item:
pagemenuItems.splice(
pagemenuItems.indexOf("context-savepage"),
0,
...bookmarksItemAndSeparator
);
}
await test_contextmenu("#test-pagemenu", pagemenuItems, {
async postCheckContextMenuFn() {
let item = contextMenu.getElementsByAttribute("generateditemid", "1")[0];
ok(item, "Got generated XUL menu item");
item.doCommand();
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function() {
let pagemenu = content.document.getElementById("test-pagemenu");
Assert.ok(!pagemenu.hasAttribute("hopeless"), "attribute got removed");
});
},
});
});
add_task(async function test_dom_full_screen() {
let fullscreenItems = NAVIGATION_ITEMS.concat([
"context-leave-dom-fullscreen",

Просмотреть файл

@ -1,133 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
const gBaseURL =
"https://example.com/browser/browser/base/content/test/contextMenu/";
add_task(async function() {
await SpecialPowers.pushPrefEnv({
set: [["dom.menuitem.enabled", true]],
});
let tab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
gBaseURL + "subtst_contextmenu.html"
);
let contextMenu = document.getElementById("contentAreaContextMenu");
// Get the point of the element with the page menu (test-pagemenu) and
// synthesize a right mouse click there.
let popupShownPromise = BrowserTestUtils.waitForEvent(
contextMenu,
"popupshown"
);
await BrowserTestUtils.synthesizeMouse(
"#test-pagemenu",
5,
5,
{ type: "contextmenu", button: 2 },
tab.linkedBrowser
);
await popupShownPromise;
checkMenu(contextMenu);
let popupHiddenPromise = BrowserTestUtils.waitForEvent(
contextMenu,
"popuphidden"
);
contextMenu.hidePopup();
await popupHiddenPromise;
BrowserTestUtils.removeTab(tab);
});
function checkItems(menuitem, arr) {
for (let i = 0; i < arr.length; i += 2) {
let str = arr[i];
let details = arr[i + 1];
if (str == "---") {
is(menuitem.localName, "menuseparator", "menuseparator");
} else if ("children" in details) {
is(menuitem.localName, "menu", "submenu");
is(menuitem.getAttribute("label"), str, str + " label");
checkItems(menuitem.menupopup.firstElementChild, details.children);
} else {
is(menuitem.localName, "menuitem", str + " menuitem");
is(menuitem.getAttribute("label"), str, str + " label");
is(menuitem.getAttribute("type"), details.type, str + " type");
is(
menuitem.getAttribute("image"),
details.icon ? gBaseURL + details.icon : "",
str + " icon"
);
if (details.checked) {
is(menuitem.getAttribute("checked"), "true", str + " checked");
} else {
ok(!menuitem.hasAttribute("checked"), str + " checked");
}
if (details.disabled) {
is(menuitem.getAttribute("disabled"), "true", str + " disabled");
} else {
ok(!menuitem.hasAttribute("disabled"), str + " disabled");
}
}
menuitem = menuitem.nextElementSibling;
}
}
function checkMenu(contextMenu) {
let items = [
"Plain item",
{ type: "", icon: "", checked: false, disabled: false },
"Disabled item",
{ type: "", icon: "", checked: false, disabled: true },
"Item w/ textContent",
{ type: "", icon: "", checked: false, disabled: false },
"---",
null,
"Checkbox",
{ type: "checkbox", icon: "", checked: true, disabled: false },
"---",
null,
"Radio1",
{ type: "checkbox", icon: "", checked: true, disabled: false },
"Radio2",
{ type: "checkbox", icon: "", checked: false, disabled: false },
"Radio3",
{ type: "checkbox", icon: "", checked: false, disabled: false },
"---",
null,
"Item w/ icon",
{ type: "", icon: "favicon.ico", checked: false, disabled: false },
"Item w/ bad icon",
{ type: "", icon: "", checked: false, disabled: false },
"---",
null,
"Submenu",
{
children: [
"Radio1",
{ type: "checkbox", icon: "", checked: false, disabled: false },
"Radio2",
{ type: "checkbox", icon: "", checked: true, disabled: false },
"Radio3",
{ type: "checkbox", icon: "", checked: false, disabled: false },
"---",
null,
"Checkbox",
{ type: "checkbox", icon: "", checked: false, disabled: false },
],
},
];
let startIndex =
Array.from(contextMenu.children).findIndex(
node => node.id == "context-sep-navigation"
) + 1;
checkItems(contextMenu.children[startIndex], items);
}

Просмотреть файл

@ -53,20 +53,12 @@ function getVisibleMenuItems(aMenu, aData) {
key = key.toLowerCase();
}
var isPageMenuItem = item.hasAttribute("generateditemid");
if (item.nodeName == "menuitem") {
var isGenerated =
item.classList.contains("spell-suggestion") ||
item.classList.contains("sendtab-target");
if (isGenerated) {
is(item.id, "", "child menuitem #" + i + " is generated");
} else if (isPageMenuItem) {
is(
item.id,
"",
"child menuitem #" + i + " is a generated page menu item"
);
} else {
ok(item.id, "child menuitem #" + i + " has an ID");
}
@ -75,8 +67,6 @@ function getVisibleMenuItems(aMenu, aData) {
if (isGenerated) {
is(key, "", "Generated items shouldn't have an access key");
items.push("*" + label);
} else if (isPageMenuItem) {
items.push("+" + label);
} else if (
item.id.indexOf("spell-check-dictionary-") != 0 &&
item.id != "spell-no-suggestions" &&
@ -100,38 +90,24 @@ function getVisibleMenuItems(aMenu, aData) {
accessKeys[key] = item.id;
}
}
if (!isGenerated && !isPageMenuItem) {
if (!isGenerated) {
items.push(item.id);
}
if (isPageMenuItem) {
var p = {};
p.type = item.getAttribute("type");
p.icon = item.getAttribute("image");
p.checked = item.hasAttribute("checked");
p.disabled = item.hasAttribute("disabled");
items.push(p);
} else {
items.push(!item.disabled);
}
items.push(!item.disabled);
} else if (item.nodeName == "menuseparator") {
ok(true, "--- seperator id is " + item.id);
items.push("---");
items.push(null);
} else if (item.nodeName == "menu") {
if (isPageMenuItem) {
item.id = "generated-submenu-" + aData.generatedSubmenuId++;
}
ok(item.id, "child menu #" + i + " has an ID");
if (!isPageMenuItem) {
ok(key, "menu has an access key");
if (accessKeys[key]) {
ok(
false,
"menu " + item.id + " has same accesskey as " + accessKeys[key]
);
} else {
accessKeys[key] = item.id;
}
ok(key, "menu has an access key");
if (accessKeys[key]) {
ok(
false,
"menu " + item.id + " has same accesskey as " + accessKeys[key]
);
} else {
accessKeys[key] = item.id;
}
items.push(item.id);
items.push(!item.disabled);

Просмотреть файл

@ -41,41 +41,6 @@ document.getElementById("shadow-host-in-link").attachShadow({ mode: "closed" }).
<div id="test-contenteditable" contenteditable="true">chssseefsbbbie</div> <!-- a more weird word which generates no suggestions -->
<div id="test-contenteditable-spellcheck-false" contenteditable="true" spellcheck="false">test</div> <!-- No Check Spelling menu item -->
<div id="test-dom-full-screen">DOM full screen FTW</div>
<div contextmenu="myMenu">
<p id="test-pagemenu" hopeless="true">I've got a context menu!</p>
<menu id="myMenu" type="context">
<menuitem label="Plain item" onclick="document.getElementById('test-pagemenu').removeAttribute('hopeless');"></menuitem>
<menuitem label="Disabled item" disabled></menuitem>
<menuitem> Item w/ textContent</menuitem>
<menu>
<menuitem type="checkbox" label="Checkbox" checked></menuitem>
</menu>
<menu>
<menuitem type="radio" label="Radio1" checked></menuitem>
<menuitem type="radio" label="Radio2"></menuitem>
<menuitem type="radio" label="Radio3"></menuitem>
</menu>
<menu>
<menuitem label="Item w/ icon" icon="favicon.ico"></menuitem>
<menuitem label="Item w/ bad icon" icon="http://example.com%0a%23.google.com/"></menuitem>
</menu>
<menu label="Submenu">
<menuitem type="radio" label="Radio1" radiogroup="rg"></menuitem>
<menuitem type="radio" label="Radio2" checked radiogroup="rg"></menuitem>
<menuitem type="radio" label="Radio3" radiogroup="rg"></menuitem>
<menu>
<menuitem type="checkbox" label="Checkbox"></menuitem>
</menu>
</menu>
<menu hidden>
<menuitem label="Bogus item"></menuitem>
</menu>
<menu>
</menu>
<menuitem label="Hidden item" hidden></menuitem>
<menuitem></menuitem>
</menu>
</div>
<div id="test-select-text">Lorem ipsum dolor sit amet, consectetuer adipiscing elit.</div>
<div id="test-select-text-link">http://mozilla.com</div>
<a id="test-image-link" href="#"><img src="ctxmenu-image.png"></a>

Просмотреть файл

@ -48,7 +48,7 @@
overflowpadding="4"
norolluponanchor="true" />
<menupopup id="contentAreaContextMenu" pagemenu="start"
<menupopup id="contentAreaContextMenu"
onpopupshowing="if (event.target != this)
return true;
gContextMenu = new nsContextMenu(this, event.shiftKey);

Просмотреть файл

@ -471,8 +471,7 @@ class nsIContent : public nsINode {
nsAtom* aName) {
if (aNamespace == kNameSpaceID_XHTML &&
(aName == nsGkAtoms::input || aName == nsGkAtoms::button ||
aName == nsGkAtoms::menuitem || aName == nsGkAtoms::audio ||
aName == nsGkAtoms::video)) {
aName == nsGkAtoms::audio || aName == nsGkAtoms::video)) {
MOZ_ASSERT(
!RequiresDoneAddingChildren(aNamespace, aName),
"Both DoneCreatingElement and DoneAddingChildren on a same element "

Просмотреть файл

@ -2051,7 +2051,6 @@ addExternalIface('imgIRequest', nativeType='imgIRequest', notflattened=True)
addExternalIface('LoadContext', nativeType='nsILoadContext', notflattened=True)
addExternalIface('LoadInfo', nativeType='nsILoadInfo',
headerFile='nsILoadInfo.h', notflattened=True)
addExternalIface('MenuBuilder', nativeType='nsIMenuBuilder', notflattened=True)
addExternalIface('XULControllers', nativeType='nsIControllers', notflattened=True)
addExternalIface('MozObserver', nativeType='nsIObserver', notflattened=True)
addExternalIface('MozTreeView', nativeType='nsITreeView',

Просмотреть файл

@ -238,7 +238,6 @@ EVENT(securitypolicyviolation, eSecurityPolicyViolation, EventNameType_All,
EVENT(seeked, eSeeked, EventNameType_HTML, eBasicEventClass)
EVENT(seeking, eSeeking, EventNameType_HTML, eBasicEventClass)
EVENT(select, eFormSelect, EventNameType_HTMLXUL, eBasicEventClass)
EVENT(show, eShow, EventNameType_HTML, eBasicEventClass)
EVENT(slotchange, eSlotChange, EventNameType_All, eBasicEventClass)
EVENT(stalled, eStalled, EventNameType_HTML, eBasicEventClass)
EVENT(start, eMarqueeStart, EventNameType_HTMLMarqueeOnly, eBasicEventClass)

Просмотреть файл

@ -1,132 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This component is used to build the menus for the HTML contextmenu attribute.
// A global value that is used to identify each menu item. It is
// incremented with each one that is found.
var gGeneratedId = 1;
function HTMLMenuBuilder() {
this.currentNode = null;
this.root = null;
this.items = {};
this.nestedStack = [];
}
// Building is done in two steps:
// The first generates a hierarchical JS object that contains the menu structure.
// This object is returned by toJSONString.
//
// The second step can take this structure and generate a XUL menu hierarchy or
// other UI from this object. The default UI is done in PageMenu.jsm.
//
// When a multi-process browser is used, the first step is performed by the child
// process and the second step is performed by the parent process.
HTMLMenuBuilder.prototype = {
classID: Components.ID("{51c65f5d-0de5-4edc-9058-60e50cef77f8}"),
QueryInterface: ChromeUtils.generateQI(["nsIMenuBuilder"]),
currentNode: null,
root: null,
items: {},
nestedStack: [],
toJSONString() {
return JSON.stringify(this.root);
},
openContainer(aLabel) {
if (!this.currentNode) {
this.root = {
type: "menu",
children: [],
};
this.currentNode = this.root;
} else {
let parent = this.currentNode;
this.currentNode = {
type: "menu",
label: aLabel,
children: [],
};
parent.children.push(this.currentNode);
this.nestedStack.push(parent);
}
},
addItemFor(aElement, aCanLoadIcon) {
// Since we no longer type check this at the IDL level, make sure we've got
// the right element type here.
if (ChromeUtils.getClassName(aElement) !== "HTMLMenuItemElement") {
return;
}
if (!("children" in this.currentNode)) {
return;
}
let item = {
type: "menuitem",
label: aElement.label,
};
let elementType = aElement.type;
if (elementType == "checkbox" || elementType == "radio") {
item.checkbox = true;
if (aElement.checked) {
item.checked = true;
}
}
let icon = aElement.icon;
if (icon.length > 0 && aCanLoadIcon) {
item.icon = icon;
}
if (aElement.disabled) {
item.disabled = true;
}
item.id = gGeneratedId++;
this.currentNode.children.push(item);
this.items[item.id] = aElement;
},
addSeparator() {
if (!("children" in this.currentNode)) {
return;
}
this.currentNode.children.push({ type: "separator" });
},
undoAddSeparator() {
if (!("children" in this.currentNode)) {
return;
}
let children = this.currentNode.children;
if (children.length && children[children.length - 1].type == "separator") {
children.pop();
}
},
closeContainer() {
this.currentNode = this.nestedStack.length
? this.nestedStack.pop()
: this.root;
},
click(id) {
let item = this.items[id];
if (item) {
item.click();
}
},
};
var EXPORTED_SYMBOLS = ["HTMLMenuBuilder"];

Просмотреть файл

@ -6,210 +6,20 @@
#include "mozilla/dom/HTMLMenuElement.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/HTMLMenuElementBinding.h"
#include "mozilla/dom/HTMLMenuItemElement.h"
#include "nsIMenuBuilder.h"
#include "nsAttrValueInlines.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsIURI.h"
#define HTMLMENUBUILDER_CONTRACTID "@mozilla.org/content/html-menu-builder;1"
NS_IMPL_NS_NEW_HTML_ELEMENT(Menu)
namespace mozilla::dom {
enum MenuType : uint8_t { MENU_TYPE_CONTEXT = 1, MENU_TYPE_TOOLBAR };
static const nsAttrValue::EnumTable kMenuTypeTable[] = {
{"context", MENU_TYPE_CONTEXT},
{"toolbar", MENU_TYPE_TOOLBAR},
{nullptr, 0}};
static const nsAttrValue::EnumTable* kMenuDefaultType = &kMenuTypeTable[1];
enum SeparatorType { ST_TRUE_INIT = -1, ST_FALSE = 0, ST_TRUE = 1 };
HTMLMenuElement::HTMLMenuElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
: nsGenericHTMLElement(std::move(aNodeInfo)), mType(MENU_TYPE_TOOLBAR) {}
: nsGenericHTMLElement(std::move(aNodeInfo)) {}
HTMLMenuElement::~HTMLMenuElement() = default;
NS_IMPL_ELEMENT_CLONE(HTMLMenuElement)
void HTMLMenuElement::SendShowEvent() {
nsCOMPtr<Document> document = GetComposedDoc();
if (!document) {
return;
}
WidgetEvent event(true, eShow);
event.mFlags.mBubbles = false;
event.mFlags.mCancelable = false;
RefPtr<nsPresContext> presContext = document->GetPresContext();
if (!presContext) {
return;
}
nsEventStatus status = nsEventStatus_eIgnore;
EventDispatcher::Dispatch(static_cast<nsIContent*>(this), presContext, &event,
nullptr, &status);
}
already_AddRefed<nsIMenuBuilder> HTMLMenuElement::CreateBuilder() const {
if (mType != MENU_TYPE_CONTEXT) {
return nullptr;
}
nsCOMPtr<nsIMenuBuilder> builder =
do_CreateInstance(HTMLMENUBUILDER_CONTRACTID);
NS_WARNING_ASSERTION(builder, "No builder available");
return builder.forget();
}
void HTMLMenuElement::Build(nsIMenuBuilder* aBuilder) {
if (!aBuilder) {
return;
}
BuildSubmenu(u""_ns, this, aBuilder);
}
nsresult HTMLMenuElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
const nsAttrValue* aValue,
const nsAttrValue* aOldValue,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) {
if (aNameSpaceID == kNameSpaceID_None && aName == nsGkAtoms::type &&
StaticPrefs::dom_menuitem_enabled()) {
if (aValue) {
mType = aValue->GetEnumValue();
} else {
mType = kMenuDefaultType->value;
}
}
return nsGenericHTMLElement::AfterSetAttr(
aNameSpaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
}
bool HTMLMenuElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
const nsAString& aValue,
nsIPrincipal* aMaybeScriptedPrincipal,
nsAttrValue& aResult) {
if (aNamespaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::type &&
StaticPrefs::dom_menuitem_enabled()) {
return aResult.ParseEnumValue(aValue, kMenuTypeTable, false,
kMenuDefaultType);
}
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
aMaybeScriptedPrincipal, aResult);
}
void HTMLMenuElement::BuildSubmenu(const nsAString& aLabel,
nsIContent* aContent,
nsIMenuBuilder* aBuilder) {
aBuilder->OpenContainer(aLabel);
int8_t separator = ST_TRUE_INIT;
TraverseContent(aContent, aBuilder, separator);
if (separator == ST_TRUE) {
aBuilder->UndoAddSeparator();
}
aBuilder->CloseContainer();
}
// static
bool HTMLMenuElement::CanLoadIcon(nsIContent* aContent,
const nsAString& aIcon) {
if (aIcon.IsEmpty()) {
return false;
}
Document* doc = aContent->OwnerDoc();
nsCOMPtr<nsIURI> uri;
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(uri), aIcon, doc,
aContent->GetBaseURI());
if (!uri) {
return false;
}
return nsContentUtils::CanLoadImage(uri, aContent, doc,
aContent->NodePrincipal());
}
void HTMLMenuElement::TraverseContent(nsIContent* aContent,
nsIMenuBuilder* aBuilder,
int8_t& aSeparator) {
nsCOMPtr<nsIContent> child;
for (child = aContent->GetFirstChild(); child;
child = child->GetNextSibling()) {
nsGenericHTMLElement* element = nsGenericHTMLElement::FromNode(child);
if (!element) {
continue;
}
if (child->IsHTMLElement(nsGkAtoms::menuitem)) {
HTMLMenuItemElement* menuitem = HTMLMenuItemElement::FromNode(child);
if (menuitem->IsHidden()) {
continue;
}
nsAutoString label;
menuitem->GetLabel(label);
if (label.IsEmpty()) {
continue;
}
nsAutoString icon;
menuitem->GetIcon(icon);
aBuilder->AddItemFor(menuitem, CanLoadIcon(child, icon));
aSeparator = ST_FALSE;
} else if (child->IsHTMLElement(nsGkAtoms::hr)) {
aBuilder->AddSeparator();
} else if (child->IsHTMLElement(nsGkAtoms::menu) && !element->IsHidden()) {
if (child->AsElement()->HasAttr(kNameSpaceID_None, nsGkAtoms::label)) {
nsAutoString label;
child->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::label, label);
BuildSubmenu(label, child, aBuilder);
aSeparator = ST_FALSE;
} else {
AddSeparator(aBuilder, aSeparator);
TraverseContent(child, aBuilder, aSeparator);
AddSeparator(aBuilder, aSeparator);
}
}
}
}
inline void HTMLMenuElement::AddSeparator(nsIMenuBuilder* aBuilder,
int8_t& aSeparator) {
if (aSeparator) {
return;
}
aBuilder->AddSeparator();
aSeparator = ST_TRUE;
}
JSObject* HTMLMenuElement::WrapNode(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return HTMLMenuElement_Binding::Wrap(aCx, this, aGivenProto);

Просмотреть файл

@ -10,8 +10,6 @@
#include "mozilla/Attributes.h"
#include "nsGenericHTMLElement.h"
class nsIMenuBuilder;
namespace mozilla::dom {
class HTMLMenuElement final : public nsGenericHTMLElement {
@ -24,61 +22,19 @@ class HTMLMenuElement final : public nsGenericHTMLElement {
// nsISupports
NS_INLINE_DECL_REFCOUNTING_INHERITED(HTMLMenuElement, nsGenericHTMLElement)
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
const nsAttrValue* aValue,
const nsAttrValue* aOldValue,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) override;
virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
const nsAString& aValue,
nsIPrincipal* aMaybeScriptedPrincipal,
nsAttrValue& aResult) override;
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
uint8_t GetType() const { return mType; }
nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
// WebIDL
void GetType(nsAString& aValue) { GetHTMLAttr(nsGkAtoms::type, aValue); }
void SetType(const nsAString& aType, ErrorResult& aError) {
SetHTMLAttr(nsGkAtoms::type, aType, aError);
}
void GetLabel(nsAString& aValue) { GetHTMLAttr(nsGkAtoms::label, aValue); }
void SetLabel(const nsAString& aLabel, ErrorResult& aError) {
SetHTMLAttr(nsGkAtoms::label, aLabel, aError);
}
bool Compact() const { return GetBoolAttr(nsGkAtoms::compact); }
void SetCompact(bool aCompact, ErrorResult& aError) {
SetHTMLBoolAttr(nsGkAtoms::compact, aCompact, aError);
}
MOZ_CAN_RUN_SCRIPT void SendShowEvent();
already_AddRefed<nsIMenuBuilder> CreateBuilder() const;
void Build(nsIMenuBuilder* aBuilder);
protected:
virtual ~HTMLMenuElement();
virtual JSObject* WrapNode(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
protected:
static bool CanLoadIcon(nsIContent* aContent, const nsAString& aIcon);
void BuildSubmenu(const nsAString& aLabel, nsIContent* aContent,
nsIMenuBuilder* aBuilder);
void TraverseContent(nsIContent* aContent, nsIMenuBuilder* aBuilder,
int8_t& aSeparator);
void AddSeparator(nsIMenuBuilder* aBuilder, int8_t& aSeparator);
uint8_t mType;
JSObject* WrapNode(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
};
} // namespace mozilla::dom

Просмотреть файл

@ -1,443 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/HTMLMenuItemElement.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/EventDispatcher.h"
#include "mozilla/dom/HTMLMenuItemElementBinding.h"
#include "mozilla/dom/HTMLUnknownElement.h"
#include "nsAttrValueInlines.h"
#include "nsContentUtils.h"
nsGenericHTMLElement* NS_NewHTMLMenuItemElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser) {
RefPtr<mozilla::dom::NodeInfo> nodeInfo(aNodeInfo);
auto* nim = nodeInfo->NodeInfoManager();
MOZ_ASSERT(nim);
if (mozilla::StaticPrefs::dom_menuitem_enabled()) {
return new (nim)
mozilla::dom::HTMLMenuItemElement(nodeInfo.forget(), aFromParser);
}
return new (nim) mozilla::dom::HTMLUnknownElement(nodeInfo.forget());
}
namespace mozilla::dom {
// First bits are needed for the menuitem type.
#define NS_CHECKED_IS_TOGGLED (1 << 2)
#define NS_ORIGINAL_CHECKED_VALUE (1 << 3)
#define NS_MENUITEM_TYPE(bits) \
((bits) & ~(NS_CHECKED_IS_TOGGLED | NS_ORIGINAL_CHECKED_VALUE))
enum CmdType : uint8_t {
CMD_TYPE_MENUITEM = 1,
CMD_TYPE_CHECKBOX,
CMD_TYPE_RADIO
};
static const nsAttrValue::EnumTable kMenuItemTypeTable[] = {
{"menuitem", CMD_TYPE_MENUITEM},
{"checkbox", CMD_TYPE_CHECKBOX},
{"radio", CMD_TYPE_RADIO},
{nullptr, 0}};
static const nsAttrValue::EnumTable* kMenuItemDefaultType =
&kMenuItemTypeTable[0];
// A base class inherited by all radio visitors.
class Visitor {
public:
Visitor() = default;
virtual ~Visitor() = default;
/**
* Visit a node in the tree. This is meant to be called on all radios in a
* group, sequentially. If the method returns false then the iteration is
* stopped.
*/
virtual bool Visit(HTMLMenuItemElement* aMenuItem) = 0;
};
// Find the selected radio, see GetSelectedRadio().
class GetCheckedVisitor : public Visitor {
public:
explicit GetCheckedVisitor(HTMLMenuItemElement** aResult)
: mResult(aResult) {}
virtual bool Visit(HTMLMenuItemElement* aMenuItem) override {
if (aMenuItem->IsChecked()) {
*mResult = aMenuItem;
return false;
}
return true;
}
protected:
HTMLMenuItemElement** mResult;
};
// Deselect all radios except the one passed to the constructor.
class ClearCheckedVisitor : public Visitor {
public:
explicit ClearCheckedVisitor(HTMLMenuItemElement* aExcludeMenuItem)
: mExcludeMenuItem(aExcludeMenuItem) {}
virtual bool Visit(HTMLMenuItemElement* aMenuItem) override {
if (aMenuItem != mExcludeMenuItem && aMenuItem->IsChecked()) {
aMenuItem->ClearChecked();
}
return true;
}
protected:
HTMLMenuItemElement* mExcludeMenuItem;
};
// Get current value of the checked dirty flag. The same value is stored on all
// radios in the group, so we need to check only the first one.
class GetCheckedDirtyVisitor : public Visitor {
public:
GetCheckedDirtyVisitor(bool* aCheckedDirty,
HTMLMenuItemElement* aExcludeMenuItem)
: mCheckedDirty(aCheckedDirty), mExcludeMenuItem(aExcludeMenuItem) {}
virtual bool Visit(HTMLMenuItemElement* aMenuItem) override {
if (aMenuItem == mExcludeMenuItem) {
return true;
}
*mCheckedDirty = aMenuItem->IsCheckedDirty();
return false;
}
protected:
bool* mCheckedDirty;
HTMLMenuItemElement* mExcludeMenuItem;
};
// Set checked dirty to true on all radios in the group.
class SetCheckedDirtyVisitor : public Visitor {
public:
SetCheckedDirtyVisitor() = default;
virtual bool Visit(HTMLMenuItemElement* aMenuItem) override {
aMenuItem->SetCheckedDirty();
return true;
}
};
// A helper visitor that is used to combine two operations (visitors) to avoid
// iterating over radios twice.
class CombinedVisitor : public Visitor {
public:
CombinedVisitor(Visitor* aVisitor1, Visitor* aVisitor2)
: mVisitor1(aVisitor1),
mVisitor2(aVisitor2),
mContinue1(true),
mContinue2(true) {}
virtual bool Visit(HTMLMenuItemElement* aMenuItem) override {
if (mContinue1) {
mContinue1 = mVisitor1->Visit(aMenuItem);
}
if (mContinue2) {
mContinue2 = mVisitor2->Visit(aMenuItem);
}
return mContinue1 || mContinue2;
}
protected:
Visitor* mVisitor1;
Visitor* mVisitor2;
bool mContinue1;
bool mContinue2;
};
HTMLMenuItemElement::HTMLMenuItemElement(
already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
FromParser aFromParser)
: nsGenericHTMLElement(std::move(aNodeInfo)),
mType(kMenuItemDefaultType->value),
mParserCreating(false),
mShouldInitChecked(false),
mCheckedDirty(false),
mChecked(false) {
mParserCreating = aFromParser;
}
HTMLMenuItemElement::~HTMLMenuItemElement() = default;
// NS_IMPL_ELEMENT_CLONE(HTMLMenuItemElement)
nsresult HTMLMenuItemElement::Clone(dom::NodeInfo* aNodeInfo,
nsINode** aResult) const {
*aResult = nullptr;
RefPtr<HTMLMenuItemElement> it = new (aNodeInfo->NodeInfoManager())
HTMLMenuItemElement(do_AddRef(aNodeInfo), NOT_FROM_PARSER);
nsresult rv = const_cast<HTMLMenuItemElement*>(this)->CopyInnerTo(it);
if (NS_SUCCEEDED(rv)) {
switch (mType) {
case CMD_TYPE_CHECKBOX:
case CMD_TYPE_RADIO:
if (mCheckedDirty) {
// We no longer have our original checked state. Set our
// checked state on the clone.
it->mCheckedDirty = true;
it->mChecked = mChecked;
}
break;
}
it.forget(aResult);
}
return rv;
}
void HTMLMenuItemElement::GetType(DOMString& aValue) {
GetEnumAttr(nsGkAtoms::type, kMenuItemDefaultType->tag, aValue);
}
void HTMLMenuItemElement::SetChecked(bool aChecked) {
bool checkedChanged = mChecked != aChecked;
mChecked = aChecked;
if (mType == CMD_TYPE_RADIO) {
if (checkedChanged) {
if (mCheckedDirty) {
ClearCheckedVisitor visitor(this);
WalkRadioGroup(&visitor);
} else {
ClearCheckedVisitor visitor1(this);
SetCheckedDirtyVisitor visitor2;
CombinedVisitor visitor(&visitor1, &visitor2);
WalkRadioGroup(&visitor);
}
} else if (!mCheckedDirty) {
SetCheckedDirtyVisitor visitor;
WalkRadioGroup(&visitor);
}
} else {
mCheckedDirty = true;
}
}
void HTMLMenuItemElement::GetEventTargetParent(EventChainPreVisitor& aVisitor) {
if (aVisitor.mEvent->mMessage == eMouseClick) {
bool originalCheckedValue = false;
switch (mType) {
case CMD_TYPE_CHECKBOX:
originalCheckedValue = mChecked;
SetChecked(!originalCheckedValue);
aVisitor.mItemFlags |= NS_CHECKED_IS_TOGGLED;
break;
case CMD_TYPE_RADIO:
// casting back to Element* here to resolve nsISupports ambiguity.
Element* supports = GetSelectedRadio();
aVisitor.mItemData = supports;
originalCheckedValue = mChecked;
if (!originalCheckedValue) {
SetChecked(true);
aVisitor.mItemFlags |= NS_CHECKED_IS_TOGGLED;
}
break;
}
if (originalCheckedValue) {
aVisitor.mItemFlags |= NS_ORIGINAL_CHECKED_VALUE;
}
// We must cache type because mType may change during JS event.
aVisitor.mItemFlags |= mType;
}
nsGenericHTMLElement::GetEventTargetParent(aVisitor);
}
nsresult HTMLMenuItemElement::PostHandleEvent(EventChainPostVisitor& aVisitor) {
// Check to see if the event was cancelled.
if (aVisitor.mEvent->mMessage == eMouseClick &&
aVisitor.mItemFlags & NS_CHECKED_IS_TOGGLED &&
aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
bool originalCheckedValue =
!!(aVisitor.mItemFlags & NS_ORIGINAL_CHECKED_VALUE);
uint8_t oldType = NS_MENUITEM_TYPE(aVisitor.mItemFlags);
nsCOMPtr<nsIContent> content(do_QueryInterface(aVisitor.mItemData));
RefPtr<HTMLMenuItemElement> selectedRadio =
HTMLMenuItemElement::FromNodeOrNull(content);
if (selectedRadio) {
selectedRadio->SetChecked(true);
if (mType != CMD_TYPE_RADIO) {
SetChecked(false);
}
} else if (oldType == CMD_TYPE_CHECKBOX) {
SetChecked(originalCheckedValue);
}
}
return NS_OK;
}
nsresult HTMLMenuItemElement::BindToTree(BindContext& aContext,
nsINode& aParent) {
nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
NS_ENSURE_SUCCESS(rv, rv);
if (IsInUncomposedDoc() && mType == CMD_TYPE_RADIO) {
AddedToRadioGroup();
}
return rv;
}
bool HTMLMenuItemElement::ParseAttribute(int32_t aNamespaceID,
nsAtom* aAttribute,
const nsAString& aValue,
nsIPrincipal* aMaybeScriptedPrincipal,
nsAttrValue& aResult) {
if (aNamespaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::type) {
return aResult.ParseEnumValue(aValue, kMenuItemTypeTable, false,
kMenuItemDefaultType);
}
if (aAttribute == nsGkAtoms::radiogroup) {
aResult.ParseAtom(aValue);
return true;
}
}
return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
aMaybeScriptedPrincipal, aResult);
}
void HTMLMenuItemElement::DoneCreatingElement() {
mParserCreating = false;
if (mShouldInitChecked) {
InitChecked();
mShouldInitChecked = false;
}
}
void HTMLMenuItemElement::GetText(nsAString& aText) {
nsAutoString text;
nsContentUtils::GetNodeTextContent(this, false, text);
text.CompressWhitespace(true, true);
aText = text;
}
nsresult HTMLMenuItemElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
const nsAttrValue* aValue,
const nsAttrValue* aOldValue,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) {
if (aNameSpaceID == kNameSpaceID_None) {
// Handle type changes first, since some of the later conditions in this
// method look at mType and want to see the new value.
if (aName == nsGkAtoms::type) {
if (aValue) {
mType = aValue->GetEnumValue();
} else {
mType = kMenuItemDefaultType->value;
}
}
if ((aName == nsGkAtoms::radiogroup || aName == nsGkAtoms::type) &&
mType == CMD_TYPE_RADIO && !mParserCreating) {
if (IsInUncomposedDoc() && GetParent()) {
AddedToRadioGroup();
}
}
// Checked must be set no matter what type of menuitem it is, since
// GetChecked() must reflect the new value
if (aName == nsGkAtoms::checked && !mCheckedDirty) {
if (mParserCreating) {
mShouldInitChecked = true;
} else {
InitChecked();
}
}
}
return nsGenericHTMLElement::AfterSetAttr(
aNameSpaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
}
void HTMLMenuItemElement::WalkRadioGroup(Visitor* aVisitor) {
nsIContent* parent = GetParent();
if (!parent) {
aVisitor->Visit(this);
return;
}
BorrowedAttrInfo info1(GetAttrInfo(kNameSpaceID_None, nsGkAtoms::radiogroup));
bool info1Empty = !info1.mValue || info1.mValue->IsEmptyString();
for (nsIContent* cur = parent->GetFirstChild(); cur;
cur = cur->GetNextSibling()) {
HTMLMenuItemElement* menuitem = HTMLMenuItemElement::FromNode(cur);
if (!menuitem || menuitem->GetType() != CMD_TYPE_RADIO) {
continue;
}
BorrowedAttrInfo info2(
menuitem->GetAttrInfo(kNameSpaceID_None, nsGkAtoms::radiogroup));
bool info2Empty = !info2.mValue || info2.mValue->IsEmptyString();
if (info1Empty != info2Empty || (info1.mValue && info2.mValue &&
!info1.mValue->Equals(*info2.mValue))) {
continue;
}
if (!aVisitor->Visit(menuitem)) {
break;
}
}
}
HTMLMenuItemElement* HTMLMenuItemElement::GetSelectedRadio() {
HTMLMenuItemElement* result = nullptr;
GetCheckedVisitor visitor(&result);
WalkRadioGroup(&visitor);
return result;
}
void HTMLMenuItemElement::AddedToRadioGroup() {
bool checkedDirty = mCheckedDirty;
if (mChecked) {
ClearCheckedVisitor visitor1(this);
GetCheckedDirtyVisitor visitor2(&checkedDirty, this);
CombinedVisitor visitor(&visitor1, &visitor2);
WalkRadioGroup(&visitor);
} else {
GetCheckedDirtyVisitor visitor(&checkedDirty, this);
WalkRadioGroup(&visitor);
}
mCheckedDirty = checkedDirty;
}
void HTMLMenuItemElement::InitChecked() {
bool defaultChecked = DefaultChecked();
mChecked = defaultChecked;
if (mType == CMD_TYPE_RADIO) {
ClearCheckedVisitor visitor(this);
WalkRadioGroup(&visitor);
}
}
JSObject* HTMLMenuItemElement::WrapNode(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return HTMLMenuItemElement_Binding::Wrap(aCx, this, aGivenProto);
}
} // namespace mozilla::dom
#undef NS_ORIGINAL_CHECKED_VALUE

Просмотреть файл

@ -1,141 +0,0 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_HTMLMenuItemElement_h
#define mozilla_dom_HTMLMenuItemElement_h
#include "mozilla/Attributes.h"
#include "nsGenericHTMLElement.h"
namespace mozilla {
class EventChainPreVisitor;
namespace dom {
class Visitor;
class HTMLMenuItemElement final : public nsGenericHTMLElement {
public:
using mozilla::dom::Element::GetText;
HTMLMenuItemElement(already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
mozilla::dom::FromParser aFromParser);
NS_IMPL_FROMNODE_HTML_WITH_TAG(HTMLMenuItemElement, menuitem)
// nsISupports
NS_INLINE_DECL_REFCOUNTING_INHERITED(HTMLMenuItemElement,
nsGenericHTMLElement)
void GetEventTargetParent(EventChainPreVisitor& aVisitor) override;
virtual nsresult PostHandleEvent(EventChainPostVisitor& aVisitor) override;
virtual nsresult BindToTree(BindContext&, nsINode& aParent) override;
virtual bool ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
const nsAString& aValue,
nsIPrincipal* aMaybeScriptedPrincipal,
nsAttrValue& aResult) override;
virtual void DoneCreatingElement() override;
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
uint8_t GetType() const { return mType; }
/**
* Syntax sugar to make it easier to check for checked and checked dirty
*/
bool IsChecked() const { return mChecked; }
bool IsCheckedDirty() const { return mCheckedDirty; }
void GetText(nsAString& aText);
// WebIDL
void GetType(DOMString& aValue);
void SetType(const nsAString& aType, ErrorResult& aError) {
SetHTMLAttr(nsGkAtoms::type, aType, aError);
}
// nsAString needed for HTMLMenuElement
void GetLabel(nsAString& aValue) {
if (!GetAttr(kNameSpaceID_None, nsGkAtoms::label, aValue)) {
GetText(aValue);
}
}
void SetLabel(const nsAString& aLabel, ErrorResult& aError) {
SetHTMLAttr(nsGkAtoms::label, aLabel, aError);
}
// nsAString needed for HTMLMenuElement
void GetIcon(nsAString& aValue) {
GetURIAttr(nsGkAtoms::icon, nullptr, aValue);
}
void SetIcon(const nsAString& aIcon, ErrorResult& aError) {
SetHTMLAttr(nsGkAtoms::icon, aIcon, aError);
}
bool Disabled() const { return GetBoolAttr(nsGkAtoms::disabled); }
void SetDisabled(bool aDisabled, ErrorResult& aError) {
SetHTMLBoolAttr(nsGkAtoms::disabled, aDisabled, aError);
}
bool Checked() const { return mChecked; }
void SetChecked(bool aChecked);
void GetRadiogroup(DOMString& aValue) {
GetHTMLAttr(nsGkAtoms::radiogroup, aValue);
}
void SetRadiogroup(const nsAString& aRadiogroup, ErrorResult& aError) {
SetHTMLAttr(nsGkAtoms::radiogroup, aRadiogroup, aError);
}
bool DefaultChecked() const { return GetBoolAttr(nsGkAtoms::checked); }
void SetDefaultChecked(bool aDefault, ErrorResult& aError) {
SetHTMLBoolAttr(nsGkAtoms::checked, aDefault, aError);
}
protected:
virtual ~HTMLMenuItemElement();
virtual JSObject* WrapNode(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
protected:
virtual nsresult AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
const nsAttrValue* aValue,
const nsAttrValue* aOldValue,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) override;
void WalkRadioGroup(Visitor* aVisitor);
HTMLMenuItemElement* GetSelectedRadio();
void AddedToRadioGroup();
void InitChecked();
friend class ClearCheckedVisitor;
friend class SetCheckedDirtyVisitor;
void ClearChecked() { mChecked = false; }
void SetCheckedDirty() { mCheckedDirty = true; }
private:
uint8_t mType : 2;
bool mParserCreating : 1;
bool mShouldInitChecked : 1;
bool mCheckedDirty : 1;
bool mChecked : 1;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_HTMLMenuItemElement_h

Просмотреть файл

@ -23,12 +23,6 @@ MOCHITEST_CHROME_MANIFESTS += [
BROWSER_CHROME_MANIFESTS += ["test/browser.ini"]
XPIDL_SOURCES += [
"nsIMenuBuilder.idl",
]
XPIDL_MODULE = "content_html"
EXPORTS += [
"nsGenericHTMLElement.h",
"nsGenericHTMLFrameElement.h",
@ -85,7 +79,6 @@ EXPORTS.mozilla.dom += [
"HTMLMarqueeElement.h",
"HTMLMediaElement.h",
"HTMLMenuElement.h",
"HTMLMenuItemElement.h",
"HTMLMetaElement.h",
"HTMLMeterElement.h",
"HTMLModElement.h",
@ -169,7 +162,6 @@ UNIFIED_SOURCES += [
"HTMLMarqueeElement.cpp",
"HTMLMediaElement.cpp",
"HTMLMenuElement.cpp",
"HTMLMenuItemElement.cpp",
"HTMLMetaElement.cpp",
"HTMLMeterElement.cpp",
"HTMLModElement.cpp",
@ -224,10 +216,6 @@ UNIFIED_SOURCES += [
"VideoDocument.cpp",
]
EXTRA_JS_MODULES += [
"HTMLMenuBuilder.jsm",
]
XPCOM_MANIFESTS += [
"components.conf",
]

Просмотреть файл

@ -79,7 +79,6 @@
#include "HTMLFieldSetElement.h"
#include "nsTextNode.h"
#include "HTMLBRElement.h"
#include "HTMLMenuElement.h"
#include "nsDOMMutationObserver.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/FromParser.h"
@ -1592,19 +1591,6 @@ bool nsGenericHTMLElement::GetURIAttr(nsAtom* aAttr, nsAtom* aBaseAttr,
return true;
}
HTMLMenuElement* nsGenericHTMLElement::GetContextMenu() const {
nsAutoString value;
GetHTMLAttr(nsGkAtoms::contextmenu, value);
if (!value.IsEmpty()) {
// XXXsmaug How should this work in Shadow DOM?
Document* doc = GetUncomposedDoc();
if (doc) {
return HTMLMenuElement::FromNodeOrNull(doc->GetElementById(value));
}
}
return nullptr;
}
bool nsGenericHTMLElement::IsLabelable() const {
return IsAnyOfHTMLElements(nsGkAtoms::progress, nsGkAtoms::meter);
}

Просмотреть файл

@ -36,7 +36,6 @@ class PresState;
namespace dom {
class ElementInternals;
class HTMLFormElement;
class HTMLMenuElement;
} // namespace dom
} // namespace mozilla
@ -160,7 +159,6 @@ class nsGenericHTMLElement : public nsGenericHTMLElementBase {
*/
uint32_t EditableInclusiveDescendantCount();
mozilla::dom::HTMLMenuElement* GetContextMenu() const;
bool Spellcheck();
void SetSpellcheck(bool aSpellcheck, mozilla::ErrorResult& aError) {
SetHTMLAttr(nsGkAtoms::spellcheck, aSpellcheck ? u"true"_ns : u"false"_ns,
@ -1361,7 +1359,6 @@ NS_DECLARE_NS_NEW_HTML_ELEMENT(Link)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Marquee)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Map)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Menu)
NS_DECLARE_NS_NEW_HTML_ELEMENT(MenuItem)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Meta)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Meter)
NS_DECLARE_NS_NEW_HTML_ELEMENT(Object)

Просмотреть файл

@ -1,76 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
webidl Element;
/**
* An interface used to construct native toolbar or context menus from <menu>
*/
[scriptable, uuid(93F4A48F-D043-4F45-97FD-9771EA1AF976)]
interface nsIMenuBuilder : nsISupports
{
/**
* Create the top level menu or a submenu. The implementation should create
* a new context for this menu, so all subsequent methods will add new items
* to this newly created menu.
*/
void openContainer(in AString aLabel);
/**
* Add a new menu item. All menu item details can be obtained from
* the element. This method is not called for hidden elements or elements
* with no or empty label. The icon should be loaded only if aCanLoadIcon
* is true.
*/
void addItemFor(in Element aElement,
in boolean aCanLoadIcon);
/**
* Create a new separator.
*/
void addSeparator();
/**
* Remove last added separator.
* Sometimes it's needed to remove last added separator, otherwise it's not
* possible to implement the postprocessing in one pass.
* See http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#building-menus-and-toolbars
*/
void undoAddSeparator();
/**
* Set the context to the parent menu.
*/
void closeContainer();
/**
* Returns a JSON string representing the menu hierarchy. For a context menu,
* it will be of the form:
* {
* type: "menu",
* children: [
* {
* type: "menuitem",
* label: "label",
* icon: "image.png"
* },
* {
* type: "separator",
* },
* ];
*/
AString toJSONString();
/**
* Invoke the action of the menuitem with assigned id aGeneratedItemId.
*
* @param aGeneratedItemId the menuitem id
*/
void click(in AString aGeneratedItemId);
};

Просмотреть файл

@ -3,7 +3,6 @@ support-files =
bug592641_img.jpg
dummy_page.html
file_fullscreen-api-keys.html
file_content_contextmenu.html
submission_flush.html
post_action_page.html
form_data_file.bin
@ -21,7 +20,6 @@ support-files =
[browser_bug436200.js]
support-files =
bug436200.html
[browser_content_contextmenu_userinput.js]
[browser_DOMDocElementInserted.js]
skip-if = bits == 64 && (os == "mac" || os == "linux") #Bug 1646862
[browser_form_post_from_file_to_http.js]

Просмотреть файл

@ -1,72 +0,0 @@
"use strict";
const kPage =
"http://example.org/browser/" + "dom/html/test/file_content_contextmenu.html";
add_task(async function() {
await SpecialPowers.pushPrefEnv({
set: [["dom.menuitem.enabled", true]],
});
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: kPage,
},
async function(aBrowser) {
let contextMenu = document.getElementById("contentAreaContextMenu");
ok(contextMenu, "Got context menu");
info("Open context menu");
is(contextMenu.state, "closed", "Should not have opened context menu");
let popupShownPromise = promiseWaitForEvent(window, "popupshown");
EventUtils.synthesizeMouse(
aBrowser,
window.innerWidth / 3,
window.innerHeight / 3,
{ type: "contextmenu", button: 2 },
window
);
await popupShownPromise;
is(contextMenu.state, "open", "Should have opened context menu");
let pageMenuSep = document.getElementById("page-menu-separator");
ok(
pageMenuSep && !pageMenuSep.hidden,
"Page menu separator should be shown"
);
let testMenuSep = pageMenuSep.previousElementSibling;
ok(
testMenuSep && !testMenuSep.hidden,
"User-added menu separator should be shown"
);
let testMenuItem = testMenuSep.previousElementSibling;
is(
testMenuItem.label,
"Test Context Menu Click",
"Got context menu item"
);
let promiseCtxMenuClick = SpecialPowers.spawn(
aBrowser,
[],
async function() {
await new Promise(resolve => {
let windowUtils = content.windowUtils;
let menuitem = content.document.getElementById("menuitem");
menuitem.addEventListener("click", function() {
Assert.ok(
windowUtils.isHandlingUserInput,
"Content menu click should be a user input"
);
resolve();
});
});
}
);
contextMenu.activateItem(testMenuItem);
await promiseCtxMenuClick;
}
);
});

Просмотреть файл

@ -1,20 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
body {
margin: 0;
width: 100vw;
height: 100vh;
}
</style>
</head>
<body contextmenu="testmenu">
<menu type="context" id="testmenu">
<menuitem label="Test Context Menu Click" id="menuitem"></menuitem>
<hr>
</menu>
</body>
</html>

Просмотреть файл

@ -1,6 +1,5 @@
[DEFAULT]
prefs =
dom.menuitem.enabled=true # only for test_bug617528.html
dom.forms.inputmode=true # only for test_inputmode.html
support-files =
347174transform.xsl
@ -347,7 +346,6 @@ fail-if = xorigin
[test_bug615833.html]
skip-if = toolkit == 'android'
os == 'mac' #TIMED_OUT # form control not selected/checked with synthesizeMouse, osx(bug 1275664)
[test_bug617528.html]
[test_bug618948.html]
[test_bug619278.html]
[test_bug622558.html]
@ -384,7 +382,6 @@ support-files =
[test_bug669012.html]
[test_bug674558.html]
[test_bug674927.html]
[test_bug677463.html]
[test_bug677658.html]
[test_bug682886.html]
[test_bug691.html]

Просмотреть файл

@ -1,73 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=617528
-->
<head>
<title>Test for Bug 617528</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=617528">Mozilla Bug 617528</a>
<p id="display"></p>
<div id="content">
<menu>
<menuitem id="checkbox" type="checkbox" label="Checkbox" checked></menuitem>
<menuitem id="radio1" type="radio" label="Radio1" checked></menuitem>
<menuitem id="radio2" type="radio" label="Radio2"></menuitem>
</menu>
</div>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 617528 **/
SimpleTest.waitForExplicitFinish();
addLoadEvent(function() {
function click(element, preventDefault, checked) {
function handleClick(event) {
is(this.checked, checked,
"checking .checked (" + this.id + ")");
if (preventDefault)
event.preventDefault();
}
element.addEventListener("click", handleClick);
element.click();
element.removeEventListener("click", handleClick);
}
function verify(elements, data) {
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
is(element.checked, data[i*2],
"checking .checked (" + element.id + ")");
is(element.defaultChecked, data[i*2+1],
'checking .defaultChecked (' + element.id + ")");
}
}
var checkbox = document.getElementById("checkbox");
click(checkbox, false, false);
verify([checkbox], [false, true]);
click(checkbox, true, true);
verify([checkbox], [false, true]);
var radio1 = document.getElementById("radio1");
var radio2 = document.getElementById("radio2");
click(radio2, false, true);
verify([radio1, radio2], [false, true,
true, false]);
click(radio1, true, true);
verify([radio1, radio2], [false, true,
true, false]);
SimpleTest.finish();
});
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1,38 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=677463
-->
<head>
<title>Test for Bug 677463</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=677463">Mozilla Bug 677463</a>
<p id="display"></p>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 677463 **/
var o = document.createElement("option");
var m = document.createElement("menuitem");
is(o.label, m.label, "Should have same labels");
o.textContent = " ";
is(o.label, m.label, "Should have same labels");
m.textContent = " ";
is(o.label, m.label, "Should have same labels");
o.textContent = " foo";
isnot(o.label, m.label, "Shouldn't have same labels");
m.textContent = "foo ";
is(o.label, m.label, "Should have same labels");
m.label = "bar";
isnot(o.label, m.label, "Shouldn't have same labels");
o.label = "bar";
is(o.label, m.label, "Should have same labels");
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -2,40 +2,30 @@
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=418756
https://bugzilla.mozilla.org/show_bug.cgi?id=617528
-->
<head>
<title>Test for Bug 418756 and 617528</title>
<title>Test for Bug 418756</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
Mozilla bug
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=418756">418756</a>
and
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=617528">617528</a>
<p id="display"></p>
<div id="content">
<form id="f1">
</form>
<form id="f2">
</form>
<menu id="m1">
</menu>
<menu id="m2">
</menu>
</div>
<pre id="test">
<script class="testbody" type="text/javascript">
/** Test for Bug 418756 and 617528 **/
/** Test for Bug 418756 **/
var group1;
var group2;
var group3;
var tags = ["input", "menuitem"];
for (let tag of tags) {
function bounce(node) {
let n = node.nextSibling;
let p = node.parentNode;
@ -64,13 +54,13 @@ var id = 0;
// type can be 'c' for 'checkbox' and 'r' for 'radio'
function createNode(type, name, checked) {
let node = document.createElement(tag);
let node = document.createElement("input");
node.setAttribute("type", typeMapper[type]);
if (checked) {
node.setAttribute("checked", "checked");
}
node.setAttribute("id", type + (++id));
node.setAttribute(tag == "input" ? "name" : "radiogroup", name);
node.setAttribute("name", name);
createdNodes.push(node);
return node;
}
@ -111,7 +101,7 @@ cleanup();
// effect
for (let type of types) {
let n = createNode(type, 'test1', true);
$(tag == "input" ? "f1" : "m1").appendChild(n);
$("f1").appendChild(n);
n.checked = false;
n.defaultChecked = false;
bounce(n);
@ -133,13 +123,13 @@ group3 = [ createNode('r', 'g1', false),
createNode('r', 'g1', false),
createNode('r', 'g1', false) ];
for (let g of group1) {
$(tag == "input" ? "f1" : "m1").appendChild(g);
$("f1").appendChild(g);
}
for (let g of group2) {
$(tag == "input" ? "f1" : "m1").appendChild(g);
$("f1").appendChild(g);
}
for (let g of group3) {
$(tag == "input" ? "f2" : "m2").appendChild(g);
$("f2").appendChild(g);
}
for (let n of [1, 2, 3]) {
@ -342,7 +332,7 @@ for (let n of [1, 2, 3]) {
"] defaultChecked wrong pass 15");
is(g.checked, (n == 1 && (group1.indexOf(g) == 1 ||
group1.indexOf(g) == 0)) ||
(n == 2 && group2.indexOf(g) == 0),
(n == 2 && group2.indexOf(g) == 0),
"group" + n + "[" + window["group"+n].indexOf(g) +
"] checked wrong pass 15");
}
@ -350,7 +340,6 @@ for (let n of [1, 2, 3]) {
cleanup();
}
</script>
</pre>
</body>

Просмотреть файл

@ -84,8 +84,6 @@ interface mixin GlobalEventHandlers {
attribute EventHandler onseeked;
attribute EventHandler onseeking;
attribute EventHandler onselect;
[Pref="dom.menuitem.enabled"]
attribute EventHandler onshow;
attribute EventHandler onslotchange;
//(Not implemented)attribute EventHandler onsort;
attribute EventHandler onstalled;

Просмотреть файл

@ -48,8 +48,6 @@ interface HTMLElement : Element {
attribute DOMString contentEditable;
[Pure]
readonly attribute boolean isContentEditable;
[Pure, Pref="dom.menuitem.enabled"]
readonly attribute HTMLMenuElement? contextMenu;
[CEReactions, SetterThrows, Pure]
attribute boolean spellcheck;
[CEReactions, Pure, SetterThrows, Pref="dom.forms.inputmode"]

Просмотреть файл

@ -12,17 +12,10 @@
* and create derivative works of this document.
*/
interface MenuBuilder;
// https://html.spec.whatwg.org/multipage/grouping-content.html#the-menu-element
[Exposed=Window]
interface HTMLMenuElement : HTMLElement {
[HTMLConstructor] constructor();
[CEReactions, SetterThrows, Pref="dom.menuitem.enabled"]
attribute DOMString type;
[CEReactions, SetterThrows, Pref="dom.menuitem.enabled"]
attribute DOMString label;
};
// https://html.spec.whatwg.org/multipage/obsolete.html#HTMLMenuElement-partial
@ -30,33 +23,3 @@ partial interface HTMLMenuElement {
[CEReactions, SetterThrows]
attribute boolean compact;
};
// Mozilla specific stuff
partial interface HTMLMenuElement {
/**
* Creates and dispatches a trusted event named "show".
* The event is not cancelable and does not bubble.
* See http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#context-menus
*/
[ChromeOnly]
void sendShowEvent();
/**
* Creates a native menu builder. The builder type is dependent on menu type.
* Currently, it returns the @mozilla.org/content/html-menu-builder;1
* component. Toolbar menus are not yet supported (the method returns null).
*/
[ChromeOnly]
MenuBuilder? createBuilder();
/*
* Builds a menu by iterating over menu children.
* See http://www.whatwg.org/specs/web-apps/current-work/multipage/interactive-elements.html#building-menus-and-toolbars
* The caller can use a native builder by calling createBuilder() or provide
* a custom builder that implements the nsIMenuBuilder interface.
* A custom builder can be used for example to build native context menus
* that are not defined using <menupopup>.
*/
[ChromeOnly]
void build(MenuBuilder aBuilder);
};

Просмотреть файл

@ -1,39 +0,0 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* http://www.whatwg.org/specs/web-apps/current-work/#the-menuitem-element
*
* © Copyright 2004-2011 Apple Computer, Inc., Mozilla Foundation, and
* Opera Software ASA. You are granted a license to use, reproduce
* and create derivative works of this document.
*/
// http://www.whatwg.org/specs/web-apps/current-work/#the-menuitem-element
[Exposed=Window, Pref="dom.menuitem.enabled"]
interface HTMLMenuItemElement : HTMLElement {
[HTMLConstructor] constructor();
[CEReactions, SetterThrows]
attribute DOMString type;
[CEReactions, SetterThrows]
attribute DOMString label;
[CEReactions, SetterThrows]
attribute DOMString icon;
[CEReactions, SetterThrows]
attribute boolean disabled;
[CEReactions]
attribute boolean checked;
[CEReactions, SetterThrows]
attribute DOMString radiogroup;
// This should be 'default' but in the IDL implementation
// this has been renamed 'defaultChecked'.
[CEReactions, SetterThrows]
attribute boolean defaultChecked;
// Currently not implemented.
// readonly attribute HTMLElement? command;
};

Просмотреть файл

@ -622,7 +622,6 @@ WEBIDL_FILES = [
"HTMLMarqueeElement.webidl",
"HTMLMediaElement.webidl",
"HTMLMenuElement.webidl",
"HTMLMenuItemElement.webidl",
"HTMLMetaElement.webidl",
"HTMLMeterElement.webidl",
"HTMLModElement.webidl",

Просмотреть файл

@ -906,7 +906,6 @@ static const ElementInfo kElements[eHTMLTag_userdefined] = {
ELEM(mark, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
ELEM(marquee, true, false, GROUP_NONE, GROUP_NONE),
ELEM(menu, true, true, GROUP_BLOCK, GROUP_LI | GROUP_FLOW_ELEMENT),
ELEM(menuitem, false, false, GROUP_NONE, GROUP_NONE),
ELEM(meta, false, false, GROUP_HEAD_CONTENT, GROUP_NONE),
ELEM(meter, true, false, GROUP_SPECIAL, GROUP_FLOW_ELEMENT),
ELEM(multicol, false, false, GROUP_NONE, GROUP_NONE),

Просмотреть файл

@ -581,12 +581,6 @@ ul, menu, dir {
padding-inline-start: 40px;
}
@supports -moz-bool-pref("dom.menuitem.enabled") {
menu[type="context"] {
display: none !important;
}
}
ul, ol, menu {
counter-reset: list-item;
}

Просмотреть файл

@ -45,9 +45,6 @@ class PromptFactory {
case "click":
this._handleClick(aEvent);
break;
case "contextmenu":
this._handleContextMenu(aEvent);
break;
case "DOMPopupBlocked":
this._handlePopupBlocked(aEvent);
break;
@ -311,127 +308,6 @@ class PromptFactory {
);
}
_handleContextMenu(aEvent) {
const target = aEvent.composedTarget;
if (aEvent.defaultPrevented || target.isContentEditable) {
return;
}
// Look through all ancestors for a context menu per spec.
let parent = target;
let menu = target.contextMenu;
while (!menu && parent) {
menu = parent.contextMenu;
parent = parent.parentElement;
}
if (!menu) {
return;
}
const builder = {
_cursor: undefined,
_id: 0,
_map: {},
_stack: [],
items: [],
// nsIMenuBuilder
openContainer(aLabel) {
if (!this._cursor) {
// Top-level
this._cursor = this;
return;
}
const newCursor = {
id: String(this._id++),
items: [],
label: aLabel,
};
this._cursor.items.push(newCursor);
this._stack.push(this._cursor);
this._cursor = newCursor;
},
addItemFor(aElement, aCanLoadIcon) {
this._cursor.items.push({
disabled: aElement.disabled,
icon:
aCanLoadIcon && aElement.icon && aElement.icon.length
? aElement.icon
: null,
id: String(this._id),
label: aElement.label,
selected: aElement.checked,
});
this._map[this._id++] = aElement;
},
addSeparator() {
this._cursor.items.push({
disabled: true,
id: String(this._id++),
separator: true,
});
},
undoAddSeparator() {
const sep = this._cursor.items[this._cursor.items.length - 1];
if (sep && sep.separator) {
this._cursor.items.pop();
}
},
closeContainer() {
const childItems =
this._cursor.label === "" ? this._cursor.items : null;
this._cursor = this._stack.pop();
if (
childItems !== null &&
this._cursor &&
this._cursor.items.length === 1
) {
// Merge a single nameless child container into the parent container.
// This lets us build an HTML contextmenu within a submenu.
this._cursor.items = childItems;
}
},
toJSONString() {
return JSON.stringify(this.items);
},
click(aId) {
const item = this._map[aId];
if (item) {
item.click();
}
},
};
// XXX the "show" event is not cancelable but spec says it should be.
menu.sendShowEvent();
menu.build(builder);
const prompt = new lazy.GeckoViewPrompter(target.ownerGlobal);
prompt.asyncShowPrompt(
{
type: "choice",
mode: "menu",
choices: builder.items,
},
result => {
// OK: result
// Cancel: !result
if (result && result.choices !== undefined) {
builder.click(result.choices[0]);
}
}
);
aEvent.preventDefault();
}
_handlePopupBlocked(aEvent) {
const dwi = aEvent.requestingWindow;
const popupWindowURISpec = aEvent.popupWindowURI

Просмотреть файл

@ -2794,11 +2794,6 @@
value: 2.0f
mirror: always
- name: dom.menuitem.enabled
type: bool
value: false
mirror: always
# Enable meta-viewport support in remote APZ-enabled frames.
- name: dom.meta-viewport.enabled
type: RelaxedAtomicBool

Просмотреть файл

@ -557,8 +557,6 @@ public final class ElementName
// return "ANNOTATION_XML";
// case TreeBuilder.FOREIGNOBJECT_OR_DESC:
// return "FOREIGNOBJECT_OR_DESC";
// case TreeBuilder.MENUITEM:
// return "MENUITEM";
// }
// return null;
// }
@ -1143,10 +1141,6 @@ public static final ElementName FORM = new ElementName("form", "form",
// CPPONLY: NS_NewHTMLFormElement,
// CPPONLY: NS_NewSVGUnknownElement,
TreeBuilder.FORM | SPECIAL);
public static final ElementName MENUITEM = new ElementName("menuitem", "menuitem",
// CPPONLY: NS_NewHTMLMenuItemElement,
// CPPONLY: NS_NewSVGUnknownElement,
TreeBuilder.MENUITEM);
public static final ElementName PARAM = new ElementName("param", "param",
// CPPONLY: NS_NewHTMLSharedElement,
// CPPONLY: NS_NewSVGUnknownElement,
@ -1484,7 +1478,7 @@ public static final ElementName TBODY = new ElementName("tbody", "tbody",
// CPPONLY: NS_NewSVGUnknownElement,
TreeBuilder.TBODY_OR_THEAD_OR_TFOOT | SPECIAL | FOSTER_PARENTING | OPTIONAL_END_TAG);
private final static @NoLength ElementName[] ELEMENT_NAMES = {
FIGCAPTION,
MN,
CITE,
FRAMESET,
H1,
@ -1495,7 +1489,7 @@ B,
BGSOUND,
SOURCE,
HTML,
RP,
OPTGROUP,
NOFRAMES,
MTEXT,
VIEW,
@ -1507,8 +1501,8 @@ FIGURE,
GLYPHREF,
LI,
ACRONYM,
SECTION,
HR,
TSPAN,
FEFUNCR,
CANVAS,
BASEFONT,
FEDISTANTLIGHT,
@ -1530,11 +1524,11 @@ FESPECULARLIGHTING,
PATH,
MALIGNMARK,
SMALL,
PARAM,
OPTION,
VIDEO,
BR,
FOOTER,
ANIMATEMOTION,
POLYGON,
COLGROUP,
ABBR,
FEGAUSSIANBLUR,
TR,
DETAILS,
DT,
@ -1578,15 +1572,15 @@ TRACK,
LABEL,
ALTGLYPHITEM,
FORM,
BUTTON,
KEYGEN,
PATTERN,
AUDIO,
FEDISPLACEMENTMAP,
SAMP,
ANIMATECOLOR,
FECOMPONENTTRANSFER,
HEADER,
CAPTION,
MAIN,
SPAN,
MO,
HGROUP,
STOP,
CENTER,
FILTER,
MARKER,
NOBR,
ADDRESS,
DEFS,
@ -1672,28 +1666,27 @@ UL,
SYMBOL,
ANIMATETRANSFORM,
EM,
MENUITEM,
ANIMATEMOTION,
CAPTION,
MN,
MAIN,
POLYGON,
SPAN,
TSPAN,
MO,
COLGROUP,
HGROUP,
OPTGROUP,
STOP,
ABBR,
CENTER,
FEFUNCR,
FILTER,
FEGAUSSIANBLUR,
MARKER,
PARAM,
BUTTON,
FIGCAPTION,
KEYGEN,
OPTION,
PATTERN,
SECTION,
AUDIO,
VIDEO,
FEDISPLACEMENTMAP,
RP,
SAMP,
BR,
ANIMATECOLOR,
HR,
FECOMPONENTTRANSFER,
FOOTER,
HEADER,
};
private final static int[] ELEMENT_HASHES = {
1900845386,
1902641154,
1748359220,
2001349720,
876609538,
@ -1704,7 +1697,7 @@ private final static int[] ELEMENT_HASHES = {
1730965751,
1756474198,
1868312196,
1938817026,
1939219752,
1988763672,
2005324101,
2060065124,
@ -1716,8 +1709,8 @@ private final static int[] ELEMENT_HASHES = {
1766992520,
1818230786,
1881613047,
1907661127,
1967128578,
1907959605,
1967760215,
1982935782,
1999397992,
2001392798,
@ -1739,11 +1732,11 @@ private final static int[] ELEMENT_HASHES = {
1805502724,
1854228698,
1874053333,
1889085973,
1905563974,
1925844629,
1963982850,
1967795958,
1898223949,
1906087319,
1932928296,
1965115924,
1968053806,
1973420034,
1983633431,
1998585858,
@ -1787,15 +1780,15 @@ private final static int[] ELEMENT_HASHES = {
1870268949,
1881288348,
1884120164,
1898753862,
1903302038,
1906135367,
1914900309,
1934172497,
1941178676,
1965334268,
1967788867,
1968836118,
1899272519,
1904412884,
1907435316,
1919418370,
1935549734,
1941221172,
1966223078,
1967795910,
1971461414,
1971938532,
1982173479,
1983533124,
@ -1881,24 +1874,23 @@ private final static int[] ELEMENT_HASHES = {
1874102998,
1881498736,
1881669634,
1887579800,
1898223949,
1899272519,
1902641154,
1904412884,
1906087319,
1907435316,
1907959605,
1919418370,
1932928296,
1935549734,
1939219752,
1941221172,
1965115924,
1966223078,
1967760215,
1967795910,
1968053806,
1971461414,
1889085973,
1898753862,
1900845386,
1903302038,
1905563974,
1906135367,
1907661127,
1914900309,
1925844629,
1934172497,
1938817026,
1941178676,
1963982850,
1965334268,
1967128578,
1967788867,
1967795958,
1968836118,
};
}

Просмотреть файл

@ -3673,7 +3673,7 @@ public class Tokenizer implements Locator, Locator2 {
*/
reconsume = true;
state = transition(state, Tokenizer.DECIMAL_NRC_LOOP, reconsume, pos);
// `break` optimizes; `continue stateloop;` would be valid
// `break` optimizes; `continue stateloop;` would be valid
break;
}
// CPPONLY: MOZ_FALLTHROUGH;

Просмотреть файл

@ -196,11 +196,9 @@ public abstract class TreeBuilder<T> implements TokenHandler,
final static int KEYGEN = 65;
final static int MENUITEM = 66;
final static int TEMPLATE = 66;
final static int TEMPLATE = 67;
final static int IMG = 68;
final static int IMG = 67;
// start insertion modes
@ -2121,7 +2119,6 @@ public abstract class TreeBuilder<T> implements TokenHandler,
reconstructTheActiveFormattingElements();
// FALL THROUGH to PARAM_OR_SOURCE_OR_TRACK
// CPPONLY: MOZ_FALLTHROUGH;
// CPPONLY: case MENUITEM:
case PARAM_OR_SOURCE_OR_TRACK:
appendVoidElementToCurrentMayFoster(
elementName,
@ -3570,7 +3567,6 @@ public abstract class TreeBuilder<T> implements TokenHandler,
break;
case AREA_OR_WBR:
case KEYGEN: // XXX??
// CPPONLY: case MENUITEM:
case PARAM_OR_SOURCE_OR_TRACK:
case EMBED:
case IMG:

Просмотреть файл

@ -87,8 +87,6 @@ UNIFIED_SOURCES += [
FINAL_LIBRARY = "xul"
# DEFINES['ENABLE_VOID_MENUITEM'] = True
LOCAL_INCLUDES += [
"/dom/base",
]

Просмотреть файл

@ -201,7 +201,6 @@ nsHtml5ElementName* nsHtml5ElementName::ELT_ANIMATETRANSFORM = nullptr;
nsHtml5ElementName* nsHtml5ElementName::ELT_ACRONYM = nullptr;
nsHtml5ElementName* nsHtml5ElementName::ELT_EM = nullptr;
nsHtml5ElementName* nsHtml5ElementName::ELT_FORM = nullptr;
nsHtml5ElementName* nsHtml5ElementName::ELT_MENUITEM = nullptr;
nsHtml5ElementName* nsHtml5ElementName::ELT_PARAM = nullptr;
nsHtml5ElementName* nsHtml5ElementName::ELT_ANIMATEMOTION = nullptr;
nsHtml5ElementName* nsHtml5ElementName::ELT_BUTTON = nullptr;
@ -288,24 +287,24 @@ nsHtml5ElementName* nsHtml5ElementName::ELT_SUMMARY = nullptr;
nsHtml5ElementName* nsHtml5ElementName::ELT_TBODY = nullptr;
nsHtml5ElementName** nsHtml5ElementName::ELEMENT_NAMES = 0;
static int32_t const ELEMENT_HASHES_DATA[] = {
1900845386, 1748359220, 2001349720, 876609538, 1798686984, 1971465813,
2007781534, 59768833, 1730965751, 1756474198, 1868312196, 1938817026,
1902641154, 1748359220, 2001349720, 876609538, 1798686984, 1971465813,
2007781534, 59768833, 1730965751, 1756474198, 1868312196, 1939219752,
1988763672, 2005324101, 2060065124, 52490899, 62390273, 1682547543,
1740181637, 1749905526, 1766992520, 1818230786, 1881613047, 1907661127,
1967128578, 1982935782, 1999397992, 2001392798, 2006329158, 2008851557,
1740181637, 1749905526, 1766992520, 1818230786, 1881613047, 1907959605,
1967760215, 1982935782, 1999397992, 2001392798, 2006329158, 2008851557,
2085266636, 51961587, 57206291, 60352339, 67108865, 943718402,
1699324759, 1733890180, 1747814436, 1749715159, 1752979652, 1757146773,
1783388498, 1805502724, 1854228698, 1874053333, 1889085973, 1905563974,
1925844629, 1963982850, 1967795958, 1973420034, 1983633431, 1998585858,
1783388498, 1805502724, 1854228698, 1874053333, 1898223949, 1906087319,
1932928296, 1965115924, 1968053806, 1973420034, 1983633431, 1998585858,
2001309869, 2001392795, 2003183333, 2005925890, 2006974466, 2008325940,
2021937364, 2068523856, 2092255447, 51435587, 52486755, 55110883,
58773795, 60345171, 61395251, 62973651, 68681729, 910163970,
1679960596, 1686491348, 1715310660, 1733054663, 1737099991, 1747176599,
1748100148, 1749656156, 1749801286, 1751288021, 1755076808, 1756625221,
1757268168, 1783210839, 1790207270, 1803929812, 1806806678, 1853642948,
1857653029, 1870268949, 1881288348, 1884120164, 1898753862, 1903302038,
1906135367, 1914900309, 1934172497, 1941178676, 1965334268, 1967788867,
1968836118, 1971938532, 1982173479, 1983533124, 1986527234, 1990037800,
1857653029, 1870268949, 1881288348, 1884120164, 1899272519, 1904412884,
1907435316, 1919418370, 1935549734, 1941221172, 1966223078, 1967795910,
1971461414, 1971938532, 1982173479, 1983533124, 1986527234, 1990037800,
1998724870, 2000525512, 2001349704, 2001349736, 2001392796, 2001495140,
2004635806, 2005719336, 2006028454, 2006896969, 2007601444, 2008125638,
2008340774, 2008994116, 2051837468, 2068523853, 2083120164, 2091479332,
@ -319,10 +318,10 @@ static int32_t const ELEMENT_HASHES_DATA[] = {
1757137429, 1757157700, 1763839627, 1782357526, 1783388497, 1786534215,
1797585096, 1803876550, 1803929861, 1805647874, 1807599880, 1818755074,
1854228692, 1854245076, 1864368130, 1870135298, 1873281026, 1874102998,
1881498736, 1881669634, 1887579800, 1898223949, 1899272519, 1902641154,
1904412884, 1906087319, 1907435316, 1907959605, 1919418370, 1932928296,
1935549734, 1939219752, 1941221172, 1965115924, 1966223078, 1967760215,
1967795910, 1968053806, 1971461414};
1881498736, 1881669634, 1889085973, 1898753862, 1900845386, 1903302038,
1905563974, 1906135367, 1907661127, 1914900309, 1925844629, 1934172497,
1938817026, 1941178676, 1963982850, 1965334268, 1967128578, 1967788867,
1967795958, 1968836118};
staticJArray<int32_t, int32_t> nsHtml5ElementName::ELEMENT_HASHES = {
ELEMENT_HASHES_DATA, MOZ_ARRAY_LENGTH(ELEMENT_HASHES_DATA)};
void nsHtml5ElementName::initializeStatics() {
@ -763,9 +762,6 @@ void nsHtml5ElementName::initializeStatics() {
ELT_FORM = new nsHtml5ElementName(
nsGkAtoms::form, nsGkAtoms::form, NS_NewHTMLFormElement,
NS_NewSVGUnknownElement, nsHtml5TreeBuilder::FORM | SPECIAL);
ELT_MENUITEM = new nsHtml5ElementName(
nsGkAtoms::menuitem, nsGkAtoms::menuitem, NS_NewHTMLMenuItemElement,
NS_NewSVGUnknownElement, nsHtml5TreeBuilder::MENUITEM);
ELT_PARAM = new nsHtml5ElementName(
nsGkAtoms::param, nsGkAtoms::param, NS_NewHTMLSharedElement,
NS_NewSVGUnknownElement,
@ -1078,8 +1074,8 @@ void nsHtml5ElementName::initializeStatics() {
NS_NewSVGUnknownElement,
nsHtml5TreeBuilder::TBODY_OR_THEAD_OR_TFOOT | SPECIAL | FOSTER_PARENTING |
OPTIONAL_END_TAG);
ELEMENT_NAMES = new nsHtml5ElementName*[207];
ELEMENT_NAMES[0] = ELT_FIGCAPTION;
ELEMENT_NAMES = new nsHtml5ElementName*[206];
ELEMENT_NAMES[0] = ELT_MN;
ELEMENT_NAMES[1] = ELT_CITE;
ELEMENT_NAMES[2] = ELT_FRAMESET;
ELEMENT_NAMES[3] = ELT_H1;
@ -1090,7 +1086,7 @@ void nsHtml5ElementName::initializeStatics() {
ELEMENT_NAMES[8] = ELT_BGSOUND;
ELEMENT_NAMES[9] = ELT_SOURCE;
ELEMENT_NAMES[10] = ELT_HTML;
ELEMENT_NAMES[11] = ELT_RP;
ELEMENT_NAMES[11] = ELT_OPTGROUP;
ELEMENT_NAMES[12] = ELT_NOFRAMES;
ELEMENT_NAMES[13] = ELT_MTEXT;
ELEMENT_NAMES[14] = ELT_VIEW;
@ -1102,8 +1098,8 @@ void nsHtml5ElementName::initializeStatics() {
ELEMENT_NAMES[20] = ELT_GLYPHREF;
ELEMENT_NAMES[21] = ELT_LI;
ELEMENT_NAMES[22] = ELT_ACRONYM;
ELEMENT_NAMES[23] = ELT_SECTION;
ELEMENT_NAMES[24] = ELT_HR;
ELEMENT_NAMES[23] = ELT_TSPAN;
ELEMENT_NAMES[24] = ELT_FEFUNCR;
ELEMENT_NAMES[25] = ELT_CANVAS;
ELEMENT_NAMES[26] = ELT_BASEFONT;
ELEMENT_NAMES[27] = ELT_FEDISTANTLIGHT;
@ -1125,11 +1121,11 @@ void nsHtml5ElementName::initializeStatics() {
ELEMENT_NAMES[43] = ELT_PATH;
ELEMENT_NAMES[44] = ELT_MALIGNMARK;
ELEMENT_NAMES[45] = ELT_SMALL;
ELEMENT_NAMES[46] = ELT_PARAM;
ELEMENT_NAMES[47] = ELT_OPTION;
ELEMENT_NAMES[48] = ELT_VIDEO;
ELEMENT_NAMES[49] = ELT_BR;
ELEMENT_NAMES[50] = ELT_FOOTER;
ELEMENT_NAMES[46] = ELT_ANIMATEMOTION;
ELEMENT_NAMES[47] = ELT_POLYGON;
ELEMENT_NAMES[48] = ELT_COLGROUP;
ELEMENT_NAMES[49] = ELT_ABBR;
ELEMENT_NAMES[50] = ELT_FEGAUSSIANBLUR;
ELEMENT_NAMES[51] = ELT_TR;
ELEMENT_NAMES[52] = ELT_DETAILS;
ELEMENT_NAMES[53] = ELT_DT;
@ -1173,15 +1169,15 @@ void nsHtml5ElementName::initializeStatics() {
ELEMENT_NAMES[91] = ELT_LABEL;
ELEMENT_NAMES[92] = ELT_ALTGLYPHITEM;
ELEMENT_NAMES[93] = ELT_FORM;
ELEMENT_NAMES[94] = ELT_BUTTON;
ELEMENT_NAMES[95] = ELT_KEYGEN;
ELEMENT_NAMES[96] = ELT_PATTERN;
ELEMENT_NAMES[97] = ELT_AUDIO;
ELEMENT_NAMES[98] = ELT_FEDISPLACEMENTMAP;
ELEMENT_NAMES[99] = ELT_SAMP;
ELEMENT_NAMES[100] = ELT_ANIMATECOLOR;
ELEMENT_NAMES[101] = ELT_FECOMPONENTTRANSFER;
ELEMENT_NAMES[102] = ELT_HEADER;
ELEMENT_NAMES[94] = ELT_CAPTION;
ELEMENT_NAMES[95] = ELT_MAIN;
ELEMENT_NAMES[96] = ELT_SPAN;
ELEMENT_NAMES[97] = ELT_MO;
ELEMENT_NAMES[98] = ELT_HGROUP;
ELEMENT_NAMES[99] = ELT_STOP;
ELEMENT_NAMES[100] = ELT_CENTER;
ELEMENT_NAMES[101] = ELT_FILTER;
ELEMENT_NAMES[102] = ELT_MARKER;
ELEMENT_NAMES[103] = ELT_NOBR;
ELEMENT_NAMES[104] = ELT_ADDRESS;
ELEMENT_NAMES[105] = ELT_DEFS;
@ -1267,25 +1263,24 @@ void nsHtml5ElementName::initializeStatics() {
ELEMENT_NAMES[185] = ELT_SYMBOL;
ELEMENT_NAMES[186] = ELT_ANIMATETRANSFORM;
ELEMENT_NAMES[187] = ELT_EM;
ELEMENT_NAMES[188] = ELT_MENUITEM;
ELEMENT_NAMES[189] = ELT_ANIMATEMOTION;
ELEMENT_NAMES[190] = ELT_CAPTION;
ELEMENT_NAMES[191] = ELT_MN;
ELEMENT_NAMES[192] = ELT_MAIN;
ELEMENT_NAMES[193] = ELT_POLYGON;
ELEMENT_NAMES[194] = ELT_SPAN;
ELEMENT_NAMES[195] = ELT_TSPAN;
ELEMENT_NAMES[196] = ELT_MO;
ELEMENT_NAMES[197] = ELT_COLGROUP;
ELEMENT_NAMES[198] = ELT_HGROUP;
ELEMENT_NAMES[199] = ELT_OPTGROUP;
ELEMENT_NAMES[200] = ELT_STOP;
ELEMENT_NAMES[201] = ELT_ABBR;
ELEMENT_NAMES[202] = ELT_CENTER;
ELEMENT_NAMES[203] = ELT_FEFUNCR;
ELEMENT_NAMES[204] = ELT_FILTER;
ELEMENT_NAMES[205] = ELT_FEGAUSSIANBLUR;
ELEMENT_NAMES[206] = ELT_MARKER;
ELEMENT_NAMES[188] = ELT_PARAM;
ELEMENT_NAMES[189] = ELT_BUTTON;
ELEMENT_NAMES[190] = ELT_FIGCAPTION;
ELEMENT_NAMES[191] = ELT_KEYGEN;
ELEMENT_NAMES[192] = ELT_OPTION;
ELEMENT_NAMES[193] = ELT_PATTERN;
ELEMENT_NAMES[194] = ELT_SECTION;
ELEMENT_NAMES[195] = ELT_AUDIO;
ELEMENT_NAMES[196] = ELT_VIDEO;
ELEMENT_NAMES[197] = ELT_FEDISPLACEMENTMAP;
ELEMENT_NAMES[198] = ELT_RP;
ELEMENT_NAMES[199] = ELT_SAMP;
ELEMENT_NAMES[200] = ELT_BR;
ELEMENT_NAMES[201] = ELT_ANIMATECOLOR;
ELEMENT_NAMES[202] = ELT_HR;
ELEMENT_NAMES[203] = ELT_FECOMPONENTTRANSFER;
ELEMENT_NAMES[204] = ELT_FOOTER;
ELEMENT_NAMES[205] = ELT_HEADER;
}
void nsHtml5ElementName::releaseStatics() {
@ -1412,7 +1407,6 @@ void nsHtml5ElementName::releaseStatics() {
delete ELT_ACRONYM;
delete ELT_EM;
delete ELT_FORM;
delete ELT_MENUITEM;
delete ELT_PARAM;
delete ELT_ANIMATEMOTION;
delete ELT_BUTTON;

Просмотреть файл

@ -311,7 +311,6 @@ class nsHtml5ElementName {
static nsHtml5ElementName* ELT_ACRONYM;
static nsHtml5ElementName* ELT_EM;
static nsHtml5ElementName* ELT_FORM;
static nsHtml5ElementName* ELT_MENUITEM;
static nsHtml5ElementName* ELT_PARAM;
static nsHtml5ElementName* ELT_ANIMATEMOTION;
static nsHtml5ElementName* ELT_BUTTON;

Просмотреть файл

@ -1347,9 +1347,6 @@ starttagloop:
reconstructTheActiveFormattingElements();
[[fallthrough]];
}
#ifdef ENABLE_VOID_MENUITEM
case MENUITEM:
#endif
case PARAM_OR_SOURCE_OR_TRACK: {
appendVoidElementToCurrentMayFoster(elementName, attributes);
selfClosing = false;
@ -2838,9 +2835,6 @@ void nsHtml5TreeBuilder::endTag(nsHtml5ElementName* elementName) {
}
case AREA_OR_WBR:
case KEYGEN:
#ifdef ENABLE_VOID_MENUITEM
case MENUITEM:
#endif
case PARAM_OR_SOURCE_OR_TRACK:
case EMBED:
case IMG:

Просмотреть файл

@ -203,11 +203,9 @@ class nsHtml5TreeBuilder : public nsAHtml5TreeBuilderState {
static const int32_t KEYGEN = 65;
static const int32_t MENUITEM = 66;
static const int32_t TEMPLATE = 66;
static const int32_t TEMPLATE = 67;
static const int32_t IMG = 68;
static const int32_t IMG = 67;
private:
static const int32_t IN_ROW = 0;

Просмотреть файл

@ -112,7 +112,6 @@ static const HTMLElement gHTMLElements[] = {
ELEM(mark, ____, true)
ELEM(marquee, ____, true)
ELEM(menu, true, true)
ELEM(menuitem, ____, true)
ELEM(meta, ____, ____)
ELEM(meter, ____, true)
ELEM(multicol, true, true)

Просмотреть файл

@ -123,7 +123,6 @@ HTML_TAG(map, Map, Map)
HTML_HTMLELEMENT_TAG(mark)
HTML_TAG(marquee, Marquee, Marquee)
HTML_TAG(menu, Menu, Menu)
HTML_TAG(menuitem, MenuItem, MenuItem)
HTML_TAG(meta, Meta, Meta)
HTML_TAG(meter, Meter, Meter)
HTML_TAG(multicol, Unknown, Unknown)

Просмотреть файл

@ -1,293 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
var EXPORTED_SYMBOLS = ["PageMenuParent", "PageMenuChild"];
function PageMenu() {}
PageMenu.prototype = {
PAGEMENU_ATTR: "pagemenu",
GENERATEDITEMID_ATTR: "generateditemid",
_popup: null,
// Only one of builder or browser will end up getting set.
_builder: null,
_browser: null,
// Given a target node, get the context menu for it or its ancestor.
getContextMenu(aTarget) {
let target = aTarget;
while (target) {
let contextMenu = target.contextMenu;
if (contextMenu) {
return contextMenu;
}
target = target.parentNode;
}
return null;
},
// Given a target node, generate a JSON object for any context menu
// associated with it, or null if there is no context menu.
maybeBuild(aTarget) {
let pageMenu = this.getContextMenu(aTarget);
if (!pageMenu) {
return null;
}
pageMenu.sendShowEvent();
// the show event is not cancelable, so no need to check a result here
this._builder = pageMenu.createBuilder();
if (!this._builder) {
return null;
}
pageMenu.build(this._builder);
// This serializes then parses again, however this could be avoided in
// the single-process case with further improvement.
let menuString = this._builder.toJSONString();
if (!menuString) {
return null;
}
return JSON.parse(menuString);
},
// Given a JSON menu object and popup, add the context menu to the popup.
buildAndAttachMenuWithObject(aMenu, aBrowser, aPopup) {
if (!aMenu) {
return false;
}
let insertionPoint = this.getInsertionPoint(aPopup);
if (!insertionPoint) {
return false;
}
let fragment = aPopup.ownerDocument.createDocumentFragment();
this.buildXULMenu(aMenu, fragment);
let pos = insertionPoint.getAttribute(this.PAGEMENU_ATTR);
if (pos == "start") {
insertionPoint.insertBefore(fragment, insertionPoint.firstElementChild);
} else if (pos.startsWith("#")) {
insertionPoint.insertBefore(fragment, insertionPoint.querySelector(pos));
} else {
insertionPoint.appendChild(fragment);
}
this._browser = aBrowser;
this._popup = aPopup;
this._popup.addEventListener("command", this);
this._popup.addEventListener("popuphidden", this);
return true;
},
// Construct the XUL menu structure for a given JSON object.
buildXULMenu(aNode, aElementForAppending) {
let document = aElementForAppending.ownerDocument;
let children = aNode.children;
for (let child of children) {
let menuitem;
switch (child.type) {
case "menuitem":
if (!child.id) {
continue; // Ignore children without ids
}
menuitem = document.createXULElement("menuitem");
if (child.checkbox) {
menuitem.setAttribute("type", "checkbox");
if (child.checked) {
menuitem.setAttribute("checked", "true");
}
}
if (child.label) {
menuitem.setAttribute("label", child.label);
}
if (child.icon) {
menuitem.setAttribute("image", child.icon);
menuitem.className = "menuitem-iconic";
}
if (child.disabled) {
menuitem.setAttribute("disabled", true);
}
break;
case "separator":
menuitem = document.createXULElement("menuseparator");
break;
case "menu":
menuitem = document.createXULElement("menu");
if (child.label) {
menuitem.setAttribute("label", child.label);
}
let menupopup = document.createXULElement("menupopup");
menuitem.appendChild(menupopup);
this.buildXULMenu(child, menupopup);
break;
}
menuitem.setAttribute(this.GENERATEDITEMID_ATTR, child.id ? child.id : 0);
aElementForAppending.appendChild(menuitem);
}
},
// Called when the generated menuitem is executed.
handleEvent(event) {
let type = event.type;
let target = event.target;
if (type == "command" && target.hasAttribute(this.GENERATEDITEMID_ATTR)) {
// If a builder is assigned, call click on it directly. Otherwise, this is
// likely a menu with data from another process, so send a message to the
// browser to execute the menuitem.
if (this._builder) {
this._builder.click(target.getAttribute(this.GENERATEDITEMID_ATTR));
} else if (this._browser) {
let win = target.ownerGlobal;
let windowUtils = win.windowUtils;
win.gContextMenu.doCustomCommand(
target.getAttribute(this.GENERATEDITEMID_ATTR),
windowUtils.isHandlingUserInput
);
}
} else if (type == "popuphidden" && this._popup == target) {
this.removeGeneratedContent(this._popup);
this._popup.removeEventListener("popuphidden", this);
this._popup.removeEventListener("command", this);
this._popup = null;
this._builder = null;
this._browser = null;
}
},
// Get the first child of the given element with the given tag name.
getImmediateChild(element, tag) {
let child = element.firstElementChild;
while (child) {
if (child.localName == tag) {
return child;
}
child = child.nextElementSibling;
}
return null;
},
// Return the location where the generated items should be inserted into the
// given popup. They should be inserted as the next sibling of the returned
// element.
getInsertionPoint(aPopup) {
if (aPopup.hasAttribute(this.PAGEMENU_ATTR)) {
return aPopup;
}
let element = aPopup.firstElementChild;
while (element) {
if (element.localName == "menu") {
let popup = this.getImmediateChild(element, "menupopup");
if (popup) {
let result = this.getInsertionPoint(popup);
if (result) {
return result;
}
}
}
element = element.nextElementSibling;
}
return null;
},
// Remove the generated content from the given popup.
removeGeneratedContent(aPopup) {
let ungenerated = [];
ungenerated.push(aPopup);
let count;
while (0 != (count = ungenerated.length)) {
let last = count - 1;
let element = ungenerated[last];
ungenerated.splice(last, 1);
let i = element.children.length;
while (i-- > 0) {
let child = element.children[i];
if (!child.hasAttribute(this.GENERATEDITEMID_ATTR)) {
ungenerated.push(child);
continue;
}
element.removeChild(child);
}
}
},
};
// This object is expected to be used from a parent process.
function PageMenuParent() {}
PageMenuParent.prototype = {
__proto__: PageMenu.prototype,
/*
* Given a JSON menu object and popup, add the context menu to the popup.
* aBrowser should be the browser containing the page the context menu is
* displayed for, which may be null.
*
* Returns true if custom menu items were present.
*/
addToPopup(aMenu, aBrowser, aPopup) {
return this.buildAndAttachMenuWithObject(aMenu, aBrowser, aPopup);
},
};
// This object is expected to be used from a child process.
function PageMenuChild() {}
PageMenuChild.prototype = {
__proto__: PageMenu.prototype,
/*
* Given a target node, return a JSON object for the custom menu commands. The
* object will consist of a hierarchical structure of menus, menuitems or
* separators. Supported properties of each are:
* Menu: children, label, type="menu"
* Menuitems: checkbox, checked, disabled, icon, label, type="menuitem"
* Separators: type="separator"
*
* In addition, the id of each item will be used to identify the item
* when it is executed. The type will either be 'menu', 'menuitem' or
* 'separator'. The toplevel node will be a menu with a children property. The
* children property of a menu is an array of zero or more other items.
*
* If there is no menu associated with aTarget, null will be returned.
*/
build(aTarget) {
return this.maybeBuild(aTarget);
},
/*
* Given the id of a menu, execute the command associated with that menu. It
* is assumed that only one command will be executed so the builder is
* cleared afterwards.
*/
executeMenu(aId) {
if (this._builder) {
this._builder.click(aId);
this._builder = null;
}
},
};

Просмотреть файл

@ -99,9 +99,6 @@ with Files("NewTabUtils.jsm"):
with Files("ObjectUtils.jsm"):
BUG_COMPONENT = ("Toolkit", "Telemetry")
with Files("PageMenu.jsm"):
BUG_COMPONENT = ("Firefox", "Menus")
with Files("PermissionsUtils.jsm"):
BUG_COMPONENT = ("Toolkit", "Add-ons Manager")
@ -195,7 +192,6 @@ EXTRA_JS_MODULES += [
"ObjectUtils.jsm",
"OsEnvironment.jsm",
"OSKeyStore.jsm",
"PageMenu.jsm",
"PermissionsUtils.jsm",
"PopupNotifications.jsm",
"Preferences.jsm",

Просмотреть файл

@ -378,8 +378,6 @@ NS_EVENT_MESSAGE(eVRDisplayConnect)
NS_EVENT_MESSAGE(eVRDisplayDisconnect)
NS_EVENT_MESSAGE(eVRDisplayPresentChange)
NS_EVENT_MESSAGE(eShow)
// Fullscreen DOM API
NS_EVENT_MESSAGE(eFullscreenChange)
NS_EVENT_MESSAGE(eFullscreenError)