зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
3ae00d82b4
Коммит
bd09497378
|
@ -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)
|
||||
|
|
Загрузка…
Ссылка в новой задаче