зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1500626 - Convert <menuitem> bindings to a Custom Element r=surkov
Differential Revision: https://phabricator.services.mozilla.com/D9322 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
8f13b0d82f
Коммит
787d9413a8
|
@ -250,8 +250,9 @@ class SortedItemSelectList {
|
|||
|
||||
createItem({label, value, className, disabled}) {
|
||||
let item = document.createElement("menuitem");
|
||||
item.value = value;
|
||||
item.setAttribute("label", label);
|
||||
if (value)
|
||||
item.value = value;
|
||||
if (className)
|
||||
item.classList.add(className);
|
||||
if (disabled)
|
||||
|
|
|
@ -198,11 +198,12 @@ var testMouseInteraction = async function() {
|
|||
click(node, 2);
|
||||
await onPopupShown;
|
||||
|
||||
is(table.menupopup.querySelectorAll("[disabled]").length, 1,
|
||||
is(table.menupopup.querySelectorAll("menuitem[disabled]").length, 1,
|
||||
"Only 1 menuitem is disabled");
|
||||
is(table.menupopup.querySelector("[disabled]"),
|
||||
is(table.menupopup.querySelector("menuitem[disabled]"),
|
||||
table.menupopup.querySelector("[data-id='col1']"),
|
||||
"Which is the unique column");
|
||||
|
||||
// popup should be open now
|
||||
// clicking on second column label
|
||||
let onPopupHidden = once(table.menupopup, "popuphidden");
|
||||
|
@ -226,7 +227,7 @@ var testMouseInteraction = async function() {
|
|||
click(node, 2);
|
||||
await onPopupShown;
|
||||
|
||||
is(table.menupopup.querySelectorAll("[disabled]").length, 1,
|
||||
is(table.menupopup.querySelectorAll("menuitem[disabled]").length, 1,
|
||||
"Only 1 menuitem is disabled");
|
||||
// popup should be open now
|
||||
// clicking on second column label
|
||||
|
@ -251,12 +252,12 @@ var testMouseInteraction = async function() {
|
|||
click(node, 2);
|
||||
await onPopupShown;
|
||||
|
||||
is(table.menupopup.querySelectorAll("[disabled]").length, 2,
|
||||
is(table.menupopup.querySelectorAll("menuitem[disabled]").length, 2,
|
||||
"2 menuitems are disabled now as only 2 columns remain visible");
|
||||
is(table.menupopup.querySelectorAll("[disabled]")[0],
|
||||
is(table.menupopup.querySelectorAll("menuitem[disabled]")[0],
|
||||
table.menupopup.querySelector("[data-id='col1']"),
|
||||
"First is the unique column");
|
||||
is(table.menupopup.querySelectorAll("[disabled]")[1],
|
||||
is(table.menupopup.querySelectorAll("menuitem[disabled]")[1],
|
||||
table.menupopup.querySelector("[data-id='col4']"),
|
||||
"Second is the last column");
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ function testElements(baseid, callback)
|
|||
var element = elements[t];
|
||||
|
||||
// Ignore presentational content inside menus
|
||||
if (element.closest("menu") && element.closest("[aria-hidden=true]")) {
|
||||
if (element.closest("menu, menuitem") && element.closest("[aria-hidden=true]")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
== menuitem-key.xul menuitem-key-ref.xul
|
||||
# these random-if(Android) are due to differences between Android Native & Xul, see bug 732569
|
||||
random-if(Android) == menulist-shrinkwrap-1.xul menulist-shrinkwrap-1-ref.xul
|
||||
random-if(Android) == menulist-shrinkwrap-2.xul menulist-shrinkwrap-2-ref.xul
|
||||
random-if(Android) == chrome://reftest/content/xul/menulist-shrinkwrap-1.xul chrome://reftest/content/xul/menulist-shrinkwrap-1-ref.xul
|
||||
random-if(Android) == chrome://reftest/content/xul/menulist-shrinkwrap-2.xul chrome://reftest/content/xul/menulist-shrinkwrap-2-ref.xul
|
||||
== textbox-overflow-1.xul textbox-overflow-1-ref.xul # for bug 749658
|
||||
# accesskeys are not normally displayed on Mac, so set a pref to enable them
|
||||
pref(ui.key.menuAccessKey,18) == chrome://reftest/content/xul/accesskey.xul accesskey-ref.xul
|
||||
|
|
|
@ -69,7 +69,6 @@ toolkit.jar:
|
|||
content/global/bindings/datetimebox.css (widgets/datetimebox.css)
|
||||
* content/global/bindings/dialog.xml (widgets/dialog.xml)
|
||||
content/global/bindings/general.xml (widgets/general.xml)
|
||||
content/global/bindings/menu.xml (widgets/menu.xml)
|
||||
content/global/bindings/popup.xml (widgets/popup.xml)
|
||||
content/global/bindings/richlistbox.xml (widgets/richlistbox.xml)
|
||||
content/global/bindings/scrollbox.xml (widgets/scrollbox.xml)
|
||||
|
|
|
@ -26,14 +26,23 @@ SimpleTest.waitForExplicitFinish();
|
|||
|
||||
function runTests()
|
||||
{
|
||||
var menu = $("menu");
|
||||
let menu = $("menu");
|
||||
let menuitemAddedWhileHidden = menu.appendItem("Added while hidden");
|
||||
ok(!menuitemAddedWhileHidden.querySelector(".menu-text"), "hidden menuitem hasn't rendered yet.");
|
||||
|
||||
menu.menupopup.addEventListener("popupshown", () => {
|
||||
var submenu = $("submenu");
|
||||
is(menuitemAddedWhileHidden.querySelector(".menu-text").value, "Added while hidden",
|
||||
"menuitemAddedWhileHidden item has rendered after shown.");
|
||||
let menuitemAddedWhileShown = menu.appendItem("Added while shown");
|
||||
is(menuitemAddedWhileShown.querySelector(".menu-text").value, "Added while shown",
|
||||
"menuitemAddedWhileShown item has eagerly rendered.");
|
||||
|
||||
let submenu = $("submenu");
|
||||
is(submenu.querySelector(".menu-text").value, "One", "submenu has rendered.");
|
||||
|
||||
var submenuDynamic = document.createXULElement("menu");
|
||||
let submenuDynamic = document.createXULElement("menu");
|
||||
submenuDynamic.setAttribute("label", "Dynamic");
|
||||
ok(!submenuDynamic.querySelector(".menu-text"), "dynamic subment hasn't rendered yet.");
|
||||
ok(!submenuDynamic.querySelector(".menu-text"), "dynamic submenu hasn't rendered yet.");
|
||||
menu.menupopup.append(submenuDynamic);
|
||||
is(submenuDynamic.querySelector(".menu-text").value, "Dynamic", "dynamic submenu has rendered.");
|
||||
|
||||
|
@ -44,7 +53,7 @@ function runTests()
|
|||
|
||||
function submenuOpened()
|
||||
{
|
||||
var submenu = $("submenu");
|
||||
let submenu = $("submenu");
|
||||
is(submenu.getAttribute('_moz-menuactive'), "true", "menu highlighted");
|
||||
submenu.hidden = true;
|
||||
$("menu").open = false;
|
||||
|
|
|
@ -49,6 +49,9 @@ function test_crash(when, andThen) {
|
|||
menuitem.addEventListener("mouseup", function (e) {
|
||||
menuitem.removeEventListener("mouseup", arguments.callee, true);
|
||||
menuitem.addEventListener("DOMAttrModified", function (e) {
|
||||
if (e.target != e.currentTarget) {
|
||||
return;
|
||||
}
|
||||
if (e.attrName == "_moz-menuactive") {
|
||||
if (!attrChanges[e.attrChange])
|
||||
attrChanges[e.attrChange] = 1;
|
||||
|
|
|
@ -42,7 +42,7 @@ function popupShown()
|
|||
let index = menulist.selectedIndex;
|
||||
if (menulist.selectedItem && navigator.platform.includes("Mac")) {
|
||||
let menulistlabel = menulist.querySelector(".menulist-label");
|
||||
let mitemlabel = document.getAnonymousElementByAttribute(menulist.selectedItem, "class", "menu-iconic-text");
|
||||
let mitemlabel = menulist.selectedItem.querySelector(".menu-iconic-text");
|
||||
|
||||
ok(isWithinHalfPixel(menulistlabel.getBoundingClientRect().left,
|
||||
mitemlabel.getBoundingClientRect().left),
|
||||
|
|
|
@ -139,17 +139,113 @@ class MozMenuCaption extends MozMenuBaseMixin(MozXULElement) {
|
|||
|
||||
customElements.define("menucaption", MozMenuCaption);
|
||||
|
||||
// In general, wait to render menus inside menupopups until they are going to be visible:
|
||||
// In general, wait to render menus and menuitems inside menupopups
|
||||
// until they are going to be visible:
|
||||
window.addEventListener("popupshowing", (e) => {
|
||||
if (e.originalTarget.ownerDocument != document) {
|
||||
return;
|
||||
}
|
||||
e.originalTarget.setAttribute("hasbeenopened", "true");
|
||||
for (let menu of e.originalTarget.querySelectorAll("menu")) {
|
||||
menu.render();
|
||||
for (let el of e.originalTarget.querySelectorAll("menuitem, menu")) {
|
||||
el.render();
|
||||
}
|
||||
}, { capture: true });
|
||||
|
||||
class MozMenuItem extends MozMenuItemBaseMixin(MozXULElement) {
|
||||
static get inheritedAttributes() {
|
||||
return {
|
||||
".menu-iconic-text": "value=label,crop,accesskey,highlightable",
|
||||
".menu-text": "value=label,crop,accesskey,highlightable",
|
||||
".menu-iconic-highlightable-text": "text=label,crop,accesskey,highlightable",
|
||||
".menu-iconic-left": "selected,_moz-menuactive,disabled,checked",
|
||||
".menu-iconic-icon": "src=image,validate,triggeringprincipal=iconloadingprincipal",
|
||||
".menu-iconic-accel": "value=acceltext",
|
||||
".menu-accel": "value=acceltext",
|
||||
};
|
||||
}
|
||||
|
||||
static get iconicNoAccelFragment() {
|
||||
// Add aria-hidden="true" on all DOM, since XULMenuAccessible handles accessibility here.
|
||||
let frag = document.importNode(MozXULElement.parseXULToFragment(`
|
||||
<hbox class="menu-iconic-left" align="center" pack="center" aria-hidden="true">
|
||||
<image class="menu-iconic-icon"/>
|
||||
</hbox>
|
||||
<label class="menu-iconic-text" flex="1" crop="right" aria-hidden="true"/>
|
||||
<label class="menu-iconic-highlightable-text" crop="right" aria-hidden="true"/>
|
||||
`), true);
|
||||
Object.defineProperty(this, "iconicNoAccelFragment", {value: frag});
|
||||
return frag;
|
||||
}
|
||||
|
||||
static get iconicFragment() {
|
||||
let frag = document.importNode(MozXULElement.parseXULToFragment(`
|
||||
<hbox class="menu-iconic-left" align="center" pack="center" aria-hidden="true">
|
||||
<image class="menu-iconic-icon"/>
|
||||
</hbox>
|
||||
<label class="menu-iconic-text" flex="1" crop="right" aria-hidden="true"/>
|
||||
<label class="menu-iconic-highlightable-text" crop="right" aria-hidden="true"/>
|
||||
<hbox class="menu-accel-container" aria-hidden="true">
|
||||
<label class="menu-iconic-accel"/>
|
||||
</hbox>
|
||||
`), true);
|
||||
Object.defineProperty(this, "iconicFragment", {value: frag});
|
||||
return frag;
|
||||
}
|
||||
|
||||
static get plainFragment() {
|
||||
let frag = document.importNode(MozXULElement.parseXULToFragment(`
|
||||
<label class="menu-text" crop="right" aria-hidden="true"/>
|
||||
<hbox class="menu-accel-container" aria-hidden="true">
|
||||
<label class="menu-accel"/>
|
||||
</hbox>
|
||||
`), true);
|
||||
Object.defineProperty(this, "plainFragment", {value: frag});
|
||||
return frag;
|
||||
}
|
||||
|
||||
get isIconic() {
|
||||
let type = this.getAttribute("type");
|
||||
return type == "checkbox" || type == "radio" || this.classList.contains("menuitem-iconic");
|
||||
}
|
||||
|
||||
get isMenulistChild() {
|
||||
return this.matches("menulist > menupopup > menuitem");
|
||||
}
|
||||
|
||||
get isInHiddenMenupopup() {
|
||||
return this.matches("menupopup:not([hasbeenopened]) menuitem");
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.renderedOnce) {
|
||||
return;
|
||||
}
|
||||
this.renderedOnce = true;
|
||||
this.textContent = "";
|
||||
if (this.isMenulistChild) {
|
||||
this.append(this.constructor.iconicNoAccelFragment.cloneNode(true));
|
||||
} else if (this.isIconic) {
|
||||
this.append(this.constructor.iconicFragment.cloneNode(true));
|
||||
} else {
|
||||
this.append(this.constructor.plainFragment.cloneNode(true));
|
||||
}
|
||||
|
||||
this.initializeAttributeInheritance();
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
// Eagerly render if we are being inserted into a menulist (since we likely need to
|
||||
// size it), or into an already-opened menupopup (since we are already visible).
|
||||
// Checking isConnectedAndReady is an optimization that will let us quickly skip
|
||||
// non-menulists that are being connected during parse.
|
||||
if (this.isMenulistChild || (this.isConnectedAndReady && !this.isInHiddenMenupopup)) {
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("menuitem", MozMenuItem);
|
||||
|
||||
const isHiddenWindow = document.documentURI == "chrome://browser/content/hiddenWindow.xul";
|
||||
|
||||
class MozMenu extends MozMenuBaseMixin(MozElements.MozElementMixin(XULMenuElement)) {
|
||||
|
@ -168,15 +264,15 @@ class MozMenu extends MozMenuBaseMixin(MozElements.MozElementMixin(XULMenuElemen
|
|||
}
|
||||
|
||||
get needsEagerRender() {
|
||||
return this.isMenubarChild || this.isSizingPopup || !this.isInHiddenMenupopup;
|
||||
return this.isMenubarChild || this.isMenulistChild || !this.isInHiddenMenupopup;
|
||||
}
|
||||
|
||||
get isMenubarChild() {
|
||||
return this.matches("menubar > menu");
|
||||
}
|
||||
|
||||
get isSizingPopup() {
|
||||
return this.matches("[sizetopopup] menu") || this.matches("menulist menu");
|
||||
get isMenulistChild() {
|
||||
return this.matches("menulist > menupopup > menu");
|
||||
}
|
||||
|
||||
get isInHiddenMenupopup() {
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
<?xml version="1.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/. -->
|
||||
<!-- globals XULMenuElement -->
|
||||
|
||||
<bindings id="menuitemBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl">
|
||||
|
||||
<binding id="menuitem-base"
|
||||
extends="chrome://global/content/bindings/general.xml#basetext">
|
||||
<implementation implements="nsIDOMXULSelectControlItemElement, nsIDOMXULContainerItemElement">
|
||||
<property name="value" onset="this.setAttribute('value', val); return val;"
|
||||
onget="return this.getAttribute('value');"/>
|
||||
<!-- nsIDOMXULSelectControlItemElement -->
|
||||
<property name="selected" readonly="true"
|
||||
onget="return this.getAttribute('selected') == 'true';"/>
|
||||
<property name="control" readonly="true">
|
||||
<getter>
|
||||
<![CDATA[
|
||||
var parent = this.parentNode;
|
||||
// Return the parent if it is a menu or menulist.
|
||||
if (parent && parent.parentNode instanceof XULMenuElement) {
|
||||
return parent.parentNode;
|
||||
}
|
||||
return null;
|
||||
]]>
|
||||
</getter>
|
||||
</property>
|
||||
|
||||
<!-- nsIDOMXULContainerItemElement -->
|
||||
<property name="parentContainer" readonly="true">
|
||||
<getter>
|
||||
for (var parent = this.parentNode; parent; parent = parent.parentNode) {
|
||||
if (parent instanceof XULMenuElement) {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
</getter>
|
||||
</property>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
<binding id="menuitem" extends="chrome://global/content/bindings/menu.xml#menuitem-base">
|
||||
<content>
|
||||
<xul:label class="menu-text" xbl:inherits="value=label,accesskey,crop,highlightable" crop="right"/>
|
||||
<xul:hbox class="menu-accel-container" anonid="accel">
|
||||
<xul:label class="menu-accel" xbl:inherits="value=acceltext"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="menuitem-iconic" extends="chrome://global/content/bindings/menu.xml#menuitem">
|
||||
<content>
|
||||
<xul:hbox class="menu-iconic-left" align="center" pack="center"
|
||||
xbl:inherits="selected,_moz-menuactive,disabled,checked">
|
||||
<xul:image class="menu-iconic-icon" xbl:inherits="src=image,triggeringprincipal=iconloadingprincipal,validate"/>
|
||||
</xul:hbox>
|
||||
<xul:label class="menu-iconic-text" flex="1" xbl:inherits="value=label,accesskey,crop,highlightable" crop="right"/>
|
||||
<xul:label class="menu-iconic-highlightable-text" xbl:inherits="xbl:text=label,crop,accesskey,highlightable" crop="right"/>
|
||||
<xul:hbox class="menu-accel-container" anonid="accel">
|
||||
<xul:label class="menu-iconic-accel" xbl:inherits="value=acceltext"/>
|
||||
</xul:hbox>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="menuitem-iconic-noaccel" extends="chrome://global/content/bindings/menu.xml#menuitem">
|
||||
<content>
|
||||
<xul:hbox class="menu-iconic-left" align="center" pack="center"
|
||||
xbl:inherits="selected,disabled,checked">
|
||||
<xul:image class="menu-iconic-icon" xbl:inherits="src=image,validate"/>
|
||||
</xul:hbox>
|
||||
<xul:label class="menu-iconic-text" flex="1" xbl:inherits="value=label,accesskey,crop,highlightable" crop="right"/>
|
||||
<xul:label class="menu-iconic-highlightable-text" xbl:inherits="xbl:text=label,crop,accesskey,highlightable" crop="right"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
</bindings>
|
|
@ -156,7 +156,7 @@
|
|||
var width = 0;
|
||||
for (var menuitem = this.firstElementChild; menuitem; menuitem = menuitem.nextElementSibling) {
|
||||
if (menuitem.localName == "menuitem" && menuitem.hasAttribute("acceltext")) {
|
||||
var accel = document.getAnonymousElementByAttribute(menuitem, "anonid", "accel");
|
||||
var accel = menuitem.menuAccel;
|
||||
if (accel) {
|
||||
array.push(accel);
|
||||
let accelWidth = accel.getBoundingClientRect().width;
|
||||
|
|
|
@ -225,21 +225,6 @@ menubar > menu:empty {
|
|||
visibility: collapse;
|
||||
}
|
||||
|
||||
/********* menuitem ***********/
|
||||
|
||||
menuitem {
|
||||
-moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem");
|
||||
}
|
||||
|
||||
menuitem.menuitem-iconic {
|
||||
-moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic");
|
||||
}
|
||||
|
||||
menuitem[type="checkbox"],
|
||||
menuitem[type="radio"] {
|
||||
-moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic");
|
||||
}
|
||||
|
||||
.menu-text {
|
||||
-moz-box-flex: 1;
|
||||
}
|
||||
|
@ -543,10 +528,6 @@ menulist[popuponly="true"] {
|
|||
border: 0 !important;
|
||||
}
|
||||
|
||||
menulist > menupopup > menuitem {
|
||||
-moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic-noaccel");
|
||||
}
|
||||
|
||||
menulist > menupopup > .popup-internal-box > .scrollbutton-up,
|
||||
menulist > menupopup > .popup-internal-box > .arrowscrollbox-overflow-start-indicator,
|
||||
menulist > menupopup > .popup-internal-box > .arrowscrollbox-overflow-end-indicator,
|
||||
|
|
|
@ -694,6 +694,9 @@
|
|||
window.customElements.upgrade(this._stateMenulist);
|
||||
window.customElements.upgrade(this._enableBtn);
|
||||
window.customElements.upgrade(this._disableBtn);
|
||||
window.customElements.upgrade(this._askToActivateMenuitem);
|
||||
window.customElements.upgrade(this._alwaysActivateMenuitem);
|
||||
window.customElements.upgrade(this._neverActivateMenuitem);
|
||||
|
||||
this._installStatus = document.getAnonymousElementByAttribute(this, "anonid", "install-status");
|
||||
this._installStatus.mControl = this;
|
||||
|
|
|
@ -2,11 +2,6 @@
|
|||
* 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/. */
|
||||
|
||||
/* Stock icons for the menu bar items */
|
||||
menuitem:not([type]) {
|
||||
-moz-binding: url("chrome://global/content/bindings/menu.xml#menuitem-iconic");
|
||||
}
|
||||
|
||||
#menu_savePage {
|
||||
list-style-image: url("moz-icon://stock/gtk-save-as?size=menu");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче