mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-10 11:55:49 +00:00
Bug 1519577 Convert toolbarbutton to a custom element r=surkov
Differential Revision: https://phabricator.services.mozilla.com/D31941 --HG-- extra : rebase_source : 3709ef713f1a7dc9fbc2d0ac97f16bea757fcd2b
This commit is contained in:
parent
b14c25d6ab
commit
a745ec6099
@ -240,7 +240,7 @@ var BrowserPageActions = {
|
||||
"pageAction-panel-button"
|
||||
);
|
||||
if (action.isBadged) {
|
||||
buttonNode.classList.add("badged-button");
|
||||
buttonNode.setAttribute("badged", "true");
|
||||
}
|
||||
buttonNode.setAttribute("actionid", action.id);
|
||||
buttonNode.addEventListener("command", event => {
|
||||
|
@ -1136,8 +1136,7 @@ var LibraryUI = {
|
||||
|
||||
let animatableBox = document.getElementById("library-animatable-box");
|
||||
let navBar = document.getElementById("nav-bar");
|
||||
let libraryIcon = document.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
|
||||
let iconBounds = window.windowUtils.getBoundsWithoutFlushing(libraryIcon);
|
||||
let iconBounds = window.windowUtils.getBoundsWithoutFlushing(libraryButton.icon);
|
||||
let libraryBounds = window.windowUtils.getBoundsWithoutFlushing(libraryButton);
|
||||
|
||||
animatableBox.style.setProperty("--library-button-height", libraryBounds.height + "px");
|
||||
@ -1197,8 +1196,7 @@ var LibraryUI = {
|
||||
}
|
||||
|
||||
let animatableBox = document.getElementById("library-animatable-box");
|
||||
let libraryIcon = document.getAnonymousElementByAttribute(libraryButton, "class", "toolbarbutton-icon");
|
||||
let iconBounds = window.windowUtils.getBoundsWithoutFlushing(libraryIcon);
|
||||
let iconBounds = window.windowUtils.getBoundsWithoutFlushing(libraryButton.icon);
|
||||
|
||||
// Resizing the window will only have the ability to change the X offset of the
|
||||
// library button.
|
||||
|
@ -568,7 +568,7 @@ function UpdateBackForwardCommands(aWebNavigation) {
|
||||
|
||||
/**
|
||||
* Click-and-Hold implementation for the Back and Forward buttons
|
||||
* XXXmano: should this live in toolbarbutton.xml?
|
||||
* XXXmano: should this live in toolbarbutton.js?
|
||||
*/
|
||||
function SetClickAndHoldHandlers() {
|
||||
// Bug 414797: Clone the back/forward buttons' context menu into both buttons.
|
||||
@ -579,13 +579,13 @@ function SetClickAndHoldHandlers() {
|
||||
|
||||
let backButton = document.getElementById("back-button");
|
||||
backButton.setAttribute("type", "menu");
|
||||
backButton.appendChild(popup);
|
||||
backButton.prepend(popup);
|
||||
gClickAndHoldListenersOnElement.add(backButton);
|
||||
|
||||
let forwardButton = document.getElementById("forward-button");
|
||||
popup = popup.cloneNode(true);
|
||||
forwardButton.setAttribute("type", "menu");
|
||||
forwardButton.appendChild(popup);
|
||||
forwardButton.prepend(popup);
|
||||
gClickAndHoldListenersOnElement.add(forwardButton);
|
||||
}
|
||||
|
||||
@ -600,7 +600,7 @@ const gClickAndHoldListenersOnElement = {
|
||||
return;
|
||||
|
||||
// Prevent the menupopup from opening immediately
|
||||
aEvent.currentTarget.firstElementChild.hidden = true;
|
||||
aEvent.currentTarget.menupopup.hidden = true;
|
||||
|
||||
aEvent.currentTarget.addEventListener("mouseout", this);
|
||||
aEvent.currentTarget.addEventListener("mouseup", this);
|
||||
@ -8391,8 +8391,7 @@ var PanicButtonNotifier = {
|
||||
popup.addEventListener("popuphidden", removeListeners);
|
||||
|
||||
let widget = CustomizableUI.getWidget("panic-button").forWindow(window);
|
||||
let anchor = widget.anchor;
|
||||
anchor = document.getAnonymousElementByAttribute(anchor, "class", "toolbarbutton-icon");
|
||||
let anchor = widget.anchor.icon;
|
||||
popup.openPopup(anchor, popup.getAttribute("position"));
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
|
@ -745,7 +745,8 @@
|
||||
removable="true"/>
|
||||
|
||||
<toolbarbutton id="alltabs-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button badged-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional tabs-alltabs-button"
|
||||
badged="true"
|
||||
oncommand="gTabsPanel.showAllTabsPanel();"
|
||||
label="&listAllTabs.label;"
|
||||
tooltiptext="&listAllTabs.label;"
|
||||
@ -1021,7 +1022,8 @@
|
||||
during the customization of the toolbar, in the palette, and before
|
||||
the Downloads Indicator overlay is loaded. -->
|
||||
<toolbarbutton id="downloads-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional badged-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
badged="true"
|
||||
key="key_openDownloads"
|
||||
onmousedown="DownloadsIndicatorView.onCommand(event);"
|
||||
onkeypress="DownloadsIndicatorView.onCommand(event);"
|
||||
@ -1057,7 +1059,8 @@
|
||||
tooltiptext="&libraryButton.tooltip;"
|
||||
label="&places.library.title;"/>
|
||||
|
||||
<toolbarbutton id="fxa-toolbar-menu-button" class="toolbarbutton-1 badged-button chromeclass-toolbar-additional subviewbutton-nav"
|
||||
<toolbarbutton id="fxa-toolbar-menu-button" class="toolbarbutton-1 chromeclass-toolbar-additional subviewbutton-nav"
|
||||
badged="true"
|
||||
onmousedown="gSync.toggleAccountPanel('PanelUI-fxa', event)"
|
||||
onkeypress="gSync.toggleAccountPanel('PanelUI-fxa', event)"
|
||||
consumeanchor="fxa-toolbar-menu-button"
|
||||
@ -1084,7 +1087,8 @@
|
||||
<toolbaritem id="PanelUI-button"
|
||||
removable="false">
|
||||
<toolbarbutton id="PanelUI-menu-button"
|
||||
class="toolbarbutton-1 badged-button"
|
||||
class="toolbarbutton-1"
|
||||
badged="true"
|
||||
consumeanchor="PanelUI-button"
|
||||
label="&brandShortName;"
|
||||
tooltiptext="&appmenu.tooltip;"/>
|
||||
|
@ -210,6 +210,9 @@
|
||||
containersEnabled = false;
|
||||
}
|
||||
|
||||
// There are separate "new tab" buttons for when the tab strip
|
||||
// is overflowed and when it is not. Attach the long click
|
||||
// popup to both of them.
|
||||
const newTab = document.getElementById("new-tab-button");
|
||||
const newTab2 = document.getAnonymousElementByAttribute(this, "anonid", "tabs-newtab-button");
|
||||
|
||||
@ -219,8 +222,8 @@
|
||||
|
||||
gClickAndHoldListenersOnElement.remove(parent);
|
||||
parent.removeAttribute("type");
|
||||
if (parent.firstElementChild) {
|
||||
parent.firstElementChild.remove();
|
||||
if (parent.menupopup) {
|
||||
parent.menupopup.remove();
|
||||
}
|
||||
|
||||
if (containersEnabled) {
|
||||
@ -240,7 +243,7 @@
|
||||
showDefaultTab: Services.prefs.getIntPref("privacy.userContext.longPressBehavior") == 1,
|
||||
});
|
||||
});
|
||||
parent.appendChild(popup);
|
||||
parent.prepend(popup);
|
||||
|
||||
// longPressBehavior == 2 means that the menu is shown after X
|
||||
// millisecs. Otherwise, with 1, the menu is open immediatelly.
|
||||
|
@ -167,8 +167,7 @@ async function test_playing_icon_on_hidden_tab(tab) {
|
||||
];
|
||||
let tabContainer = tab.parentNode;
|
||||
let alltabsButton = document.getElementById("alltabs-button");
|
||||
let alltabsBadge = document.getAnonymousElementByAttribute(
|
||||
alltabsButton, "class", "toolbarbutton-badge");
|
||||
let alltabsBadge = alltabsButton.badgeLabel;
|
||||
|
||||
function assertIconShowing() {
|
||||
is(getComputedStyle(alltabsBadge).backgroundImage,
|
||||
|
@ -4438,7 +4438,7 @@ OverflowableToolbar.prototype = {
|
||||
let mainView = doc.getElementById(mainViewId);
|
||||
let contextMenu = doc.getElementById(mainView.getAttribute("context"));
|
||||
gELS.addSystemEventListener(contextMenu, "command", this, true);
|
||||
let anchor = doc.getAnonymousElementByAttribute(this._chevron, "class", "toolbarbutton-icon");
|
||||
let anchor = this._chevron.icon;
|
||||
// Ensure we update the gEditUIVisible flag when opening the popup, in
|
||||
// case the edit controls are in it.
|
||||
this._panel.addEventListener("popupshowing", () => doc.defaultView.updateEditUIVisibility(), {once: true});
|
||||
|
@ -1348,6 +1348,11 @@ var PanelView = class extends AssociatedToNode {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ignore content inside a <toolbarbutton>
|
||||
if (element.tagName != "toolbarbutton" && element.closest("toolbarbutton")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Take the label for toolbarbuttons; it only exists on those elements.
|
||||
element = element.multilineLabel || element;
|
||||
|
||||
|
@ -866,11 +866,7 @@ const PanelUI = {
|
||||
_getBadgeStatus(notification) { return notification.id; },
|
||||
|
||||
_getPanelAnchor(candidate) {
|
||||
let iconAnchor =
|
||||
document.getAnonymousElementByAttribute(candidate, "class",
|
||||
"toolbarbutton-badge-stack") ||
|
||||
document.getAnonymousElementByAttribute(candidate, "class",
|
||||
"toolbarbutton-icon");
|
||||
let iconAnchor = candidate.badgeStack || candidate.icon;
|
||||
return iconAnchor || candidate;
|
||||
},
|
||||
|
||||
|
@ -30,7 +30,7 @@ const kNSXUL = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
const kForceOverflowWidthPx = 300;
|
||||
|
||||
function createDummyXULButton(id, label, win = window) {
|
||||
let btn = document.createElementNS(kNSXUL, "toolbarbutton");
|
||||
let btn = win.document.createElementNS(kNSXUL, "toolbarbutton");
|
||||
btn.id = id;
|
||||
btn.setAttribute("label", label || id);
|
||||
btn.className = "toolbarbutton-1 chromeclass-toolbar-additional";
|
||||
@ -445,8 +445,7 @@ function checkContextMenu(aContextMenu, aExpectedEntries, aWindow = window) {
|
||||
|
||||
function waitForOverflowButtonShown(win = window) {
|
||||
let ov = win.document.getElementById("nav-bar-overflow-button");
|
||||
let icon = win.document.getAnonymousElementByAttribute(ov, "class", "toolbarbutton-icon");
|
||||
return waitForElementShown(icon);
|
||||
return waitForElementShown(ov.icon);
|
||||
}
|
||||
function waitForElementShown(element) {
|
||||
let win = element.ownerGlobal;
|
||||
|
@ -613,11 +613,10 @@ const DownloadsIndicatorView = {
|
||||
let widgetGroup = CustomizableUI.getWidget("downloads-button");
|
||||
if (widgetGroup.areaType == CustomizableUI.TYPE_MENU_PANEL) {
|
||||
let overflowIcon = widgetGroup.forWindow(window).anchor;
|
||||
return document.getAnonymousElementByAttribute(overflowIcon, "class", "toolbarbutton-icon");
|
||||
return overflowIcon.icon;
|
||||
}
|
||||
|
||||
return document.getAnonymousElementByAttribute(this.indicator, "class",
|
||||
"toolbarbutton-badge-stack");
|
||||
return this.indicator.badgeStack;
|
||||
},
|
||||
|
||||
get _progressIcon() {
|
||||
|
@ -34,9 +34,8 @@ add_task(async function test_overflow_anchor() {
|
||||
|
||||
let panel = DownloadsPanel.panel;
|
||||
let chevron = document.getElementById("nav-bar-overflow-button");
|
||||
let chevronIcon = document.getAnonymousElementByAttribute(chevron,
|
||||
"class", "toolbarbutton-icon");
|
||||
is(panel.anchorNode, chevronIcon, "Panel should be anchored to the chevron`s icon.");
|
||||
|
||||
is(panel.anchorNode, chevron.icon, "Panel should be anchored to the chevron`s icon.");
|
||||
|
||||
DownloadsPanel.hidePanel();
|
||||
|
||||
@ -47,8 +46,7 @@ add_task(async function test_overflow_anchor() {
|
||||
EventUtils.sendMouseEvent({ type: "mousedown", button: 0 }, button.node);
|
||||
await promise;
|
||||
|
||||
let downloadsAnchor = document.getAnonymousElementByAttribute(button.node, "class",
|
||||
"toolbarbutton-badge-stack");
|
||||
let downloadsAnchor = button.node.badgeStack;
|
||||
is(panel.anchorNode, downloadsAnchor);
|
||||
|
||||
DownloadsPanel.hidePanel();
|
||||
|
@ -275,8 +275,7 @@ class ExtensionControlledPopup {
|
||||
// Anchor to a toolbar browserAction if found, otherwise use the menu button.
|
||||
anchorButton = action || doc.getElementById("PanelUI-menu-button");
|
||||
}
|
||||
let anchor = doc.getAnonymousElementByAttribute(
|
||||
anchorButton, "class", "toolbarbutton-icon");
|
||||
let anchor = anchorButton.icon;
|
||||
panel.hidden = false;
|
||||
popupnotification.show();
|
||||
panel.openPopup(anchor);
|
||||
|
@ -165,8 +165,8 @@ this.browserAction = class extends ExtensionAPI {
|
||||
},
|
||||
|
||||
onCreated: node => {
|
||||
node.classList.add("badged-button");
|
||||
node.classList.add("webextension-browser-action");
|
||||
node.setAttribute("badged", "true");
|
||||
node.setAttribute("constrain-size", "true");
|
||||
node.setAttribute("data-extensionid", this.extension.id);
|
||||
|
||||
|
@ -129,8 +129,7 @@ async function runTests(options) {
|
||||
is(button.getAttribute("disabled") == "true", !details.enabled, "disabled state is correct");
|
||||
|
||||
if (details.badge) {
|
||||
let badge = button.ownerDocument.getAnonymousElementByAttribute(
|
||||
button, "class", "toolbarbutton-badge");
|
||||
let badge = button.badgeLabel;
|
||||
let style = window.getComputedStyle(badge);
|
||||
let expected = {
|
||||
backgroundColor: serializeColor(details.badgeBackgroundColor),
|
||||
@ -426,7 +425,7 @@ add_task(async function testBadgeColorPersistence() {
|
||||
|
||||
function getBadgeForWindow(win) {
|
||||
const widget = getBrowserActionWidget(extension).forWindow(win).node;
|
||||
return document.getAnonymousElementByAttribute(widget, "class", "toolbarbutton-badge");
|
||||
return widget.badgeLabel;
|
||||
}
|
||||
|
||||
let badge = getBadgeForWindow(window);
|
||||
|
@ -247,7 +247,7 @@ add_task(async function browseraction_contextmenu_manage_extension() {
|
||||
|
||||
info("Wait until the overflow menu is ready");
|
||||
let overflowButton = win.document.getElementById("nav-bar-overflow-button");
|
||||
let icon = win.document.getAnonymousElementByAttribute(overflowButton, "class", "toolbarbutton-icon");
|
||||
let icon = overflowButton.icon;
|
||||
await waitForElementShown(icon);
|
||||
|
||||
if (!customizing) {
|
||||
@ -326,7 +326,7 @@ async function runTestContextMenu({
|
||||
|
||||
info("Wait until the overflow menu is ready");
|
||||
let overflowButton = win.document.getElementById("nav-bar-overflow-button");
|
||||
let icon = win.document.getAnonymousElementByAttribute(overflowButton, "class", "toolbarbutton-icon");
|
||||
let icon = overflowButton.icon;
|
||||
await waitForElementShown(icon);
|
||||
|
||||
if (!customizing) {
|
||||
|
@ -1519,7 +1519,7 @@ PlacesToolbar.prototype = {
|
||||
|
||||
// If the menu is open, close it.
|
||||
if (draggedElt.open) {
|
||||
draggedElt.lastElementChild.hidePopup();
|
||||
draggedElt.menupopup.hidePopup();
|
||||
draggedElt.open = false;
|
||||
}
|
||||
}
|
||||
|
@ -289,7 +289,7 @@ function getNodeForToolbarItem(itemGuid, validator) {
|
||||
// Don't search in queries, they could contain our item in a
|
||||
// different position. Search only folders
|
||||
if (PlacesUtils.nodeIsFolder(child._placesNode)) {
|
||||
var popup = child.lastElementChild;
|
||||
var popup = child.menupopup;
|
||||
popup.openPopup();
|
||||
var foundNode = findNode(popup);
|
||||
popup.hidePopup();
|
||||
|
@ -37,7 +37,7 @@ add_task(async function test() {
|
||||
Assert.equal(menuButton.type, "menu", "A menu button");
|
||||
|
||||
// Mouse over the menu button to open it.
|
||||
let buttonPopup = menuButton.firstElementChild;
|
||||
let buttonPopup = menuButton.menupopup;
|
||||
promise = promiseEvent(buttonPopup, "popupshown");
|
||||
EventUtils.synthesizeMouse(menuButton, 5, 5, { type: "mousemove" });
|
||||
await promise;
|
||||
|
@ -87,9 +87,7 @@ var UITour = {
|
||||
|
||||
// Otherwise use the sync setup icon.
|
||||
let statusButton = aDocument.getElementById("appMenu-fxa-label");
|
||||
return aDocument.getAnonymousElementByAttribute(statusButton,
|
||||
"class",
|
||||
"toolbarbutton-icon");
|
||||
return statusButton.icon;
|
||||
},
|
||||
// This is a fake widgetName starting with the "appMenu-" prefix so we know
|
||||
// to automatically open the appMenu when annotating this target.
|
||||
|
@ -6,7 +6,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=987230
|
||||
-->
|
||||
<window title="Mozilla Bug 987230"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="SimpleTest.waitForFocus(nextTest, window)">
|
||||
onload="SimpleTest.waitForFocus(startTest, window)">
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
@ -108,9 +108,14 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=987230
|
||||
popup.openPopup(anchor, "bottomcenter topright");
|
||||
}
|
||||
|
||||
let popup = document.getElementById("mypopup");
|
||||
let outerAnchor = document.getElementById("toolbarbutton-anchor");
|
||||
let anchor = document.getAnonymousElementByAttribute(outerAnchor, "class", "toolbarbutton-icon");
|
||||
let popup, outerAnchor, anchor;
|
||||
|
||||
function startTest() {
|
||||
popup = document.getElementById("mypopup");
|
||||
outerAnchor = document.getElementById("toolbarbutton-anchor");
|
||||
anchor = outerAnchor.icon;
|
||||
nextTest();
|
||||
}
|
||||
|
||||
function nextTest(e) {
|
||||
synthesizeMouse(outerAnchor, 5, 5, {});
|
||||
|
@ -32,7 +32,7 @@ add_task(async function test_button_background_properties() {
|
||||
await extension.startup();
|
||||
|
||||
let toolbarButton = document.querySelector("#home-button");
|
||||
let toolbarButtonIcon = document.getAnonymousElementByAttribute(toolbarButton, "class", "toolbarbutton-icon");
|
||||
let toolbarButtonIcon = toolbarButton.icon;
|
||||
let toolbarButtonIconCS = window.getComputedStyle(toolbarButtonIcon);
|
||||
|
||||
InspectorUtils.addPseudoClassLock(toolbarButton, ":hover");
|
||||
|
@ -659,6 +659,7 @@ if (!isDummyDocument) {
|
||||
"chrome://global/content/elements/textbox.js",
|
||||
"chrome://global/content/elements/tabbox.js",
|
||||
"chrome://global/content/elements/text.js",
|
||||
"chrome://global/content/elements/toolbarbutton.js",
|
||||
"chrome://global/content/elements/tree.js",
|
||||
"chrome://global/content/elements/wizard.js",
|
||||
]) {
|
||||
|
@ -62,7 +62,6 @@ toolkit.jar:
|
||||
#endif
|
||||
content/global/widgets.css
|
||||
content/global/bindings/autocomplete.xml (widgets/autocomplete.xml)
|
||||
content/global/bindings/button.xml (widgets/button.xml)
|
||||
content/global/bindings/calendar.js (widgets/calendar.js)
|
||||
content/global/bindings/datekeeper.js (widgets/datekeeper.js)
|
||||
content/global/bindings/datepicker.js (widgets/datepicker.js)
|
||||
@ -77,7 +76,6 @@ toolkit.jar:
|
||||
* content/global/bindings/textbox.xml (widgets/textbox.xml)
|
||||
content/global/bindings/timekeeper.js (widgets/timekeeper.js)
|
||||
content/global/bindings/timepicker.js (widgets/timepicker.js)
|
||||
content/global/bindings/toolbarbutton.xml (widgets/toolbarbutton.xml)
|
||||
content/global/bindings/wizard.xml (widgets/wizard.xml)
|
||||
content/global/elements/autocomplete-popup.js (widgets/autocomplete-popup.js)
|
||||
content/global/elements/autocomplete-richlistitem.js (widgets/autocomplete-richlistitem.js)
|
||||
@ -103,6 +101,7 @@ toolkit.jar:
|
||||
content/global/elements/tabbox.js (widgets/tabbox.js)
|
||||
content/global/elements/text.js (widgets/text.js)
|
||||
content/global/elements/textbox.js (widgets/textbox.js)
|
||||
content/global/elements/toolbarbutton.js (widgets/toolbarbutton.js)
|
||||
content/global/elements/videocontrols.js (widgets/videocontrols.js)
|
||||
content/global/elements/tree.js (widgets/tree.js)
|
||||
content/global/elements/wizard.js (widgets/wizard.js)
|
||||
|
@ -214,6 +214,8 @@
|
||||
|
||||
MozXULElement.implementCustomInterface(MozButtonBase, [Ci.nsIDOMXULButtonElement]);
|
||||
|
||||
MozElements.ButtonBase = MozButtonBase;
|
||||
|
||||
class MozButton extends MozButtonBase {
|
||||
static get inheritedAttributes() {
|
||||
return {
|
||||
|
@ -1,192 +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/. -->
|
||||
|
||||
|
||||
<bindings id="buttonBindings"
|
||||
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="button-base" extends="chrome://global/content/bindings/general.xml#basetext">
|
||||
<implementation implements="nsIDOMXULButtonElement">
|
||||
<property name="type"
|
||||
onget="return this.getAttribute('type');"
|
||||
onset="this.setAttribute('type', val); return val;"/>
|
||||
|
||||
<property name="dlgType"
|
||||
onget="return this.getAttribute('dlgtype');"
|
||||
onset="this.setAttribute('dlgtype', val); return val;"/>
|
||||
|
||||
<property name="group"
|
||||
onget="return this.getAttribute('group');"
|
||||
onset="this.setAttribute('group', val); return val;"/>
|
||||
|
||||
<property name="open" onget="return this.hasAttribute('open');">
|
||||
<setter><![CDATA[
|
||||
if (this.hasMenu()) {
|
||||
this.openMenu(val);
|
||||
} else if (val) {
|
||||
// Fall back to just setting the attribute
|
||||
this.setAttribute("open", "true");
|
||||
} else {
|
||||
this.removeAttribute("open");
|
||||
}
|
||||
return val;
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<property name="checked" onget="return this.hasAttribute('checked');">
|
||||
<setter><![CDATA[
|
||||
if (this.type == "radio" && val) {
|
||||
var sibs = this.parentNode.getElementsByAttribute("group", this.group);
|
||||
for (var i = 0; i < sibs.length; ++i)
|
||||
sibs[i].removeAttribute("checked");
|
||||
}
|
||||
|
||||
if (val)
|
||||
this.setAttribute("checked", "true");
|
||||
else
|
||||
this.removeAttribute("checked");
|
||||
|
||||
return val;
|
||||
]]></setter>
|
||||
</property>
|
||||
|
||||
<method name ="filterButtons">
|
||||
<parameter name="node"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
// if the node isn't visible, don't descend into it.
|
||||
var cs = node.ownerGlobal.getComputedStyle(node);
|
||||
if (cs.visibility != "visible" || cs.display == "none") {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
// but it may be a popup element, in which case we look at "state"...
|
||||
if (cs.display == "-moz-popup" && node.state != "open") {
|
||||
return NodeFilter.FILTER_REJECT;
|
||||
}
|
||||
// OK - the node seems visible, so it is a candidate.
|
||||
if (node.localName == "button" && node.accessKey && !node.disabled)
|
||||
return NodeFilter.FILTER_ACCEPT;
|
||||
return NodeFilter.FILTER_SKIP;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="fireAccessKeyButton">
|
||||
<parameter name="aSubtree"/>
|
||||
<parameter name="aAccessKeyLower"/>
|
||||
<body>
|
||||
<![CDATA[
|
||||
var iterator = aSubtree.ownerDocument.createTreeWalker(aSubtree,
|
||||
NodeFilter.SHOW_ELEMENT,
|
||||
this.filterButtons);
|
||||
while (iterator.nextNode()) {
|
||||
var test = iterator.currentNode;
|
||||
if (test.accessKey.toLowerCase() == aAccessKeyLower &&
|
||||
!test.disabled && !test.collapsed && !test.hidden) {
|
||||
test.focus();
|
||||
test.click();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<method name="_handleClick">
|
||||
<body>
|
||||
<![CDATA[
|
||||
if (!this.disabled) {
|
||||
if (this.type == "checkbox") {
|
||||
this.checked = !this.checked;
|
||||
} else if (this.type == "radio") {
|
||||
this.checked = true;
|
||||
}
|
||||
}
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
<!-- While it would seem we could do this by handling oncommand, we can't
|
||||
because any external oncommand handlers might get called before ours,
|
||||
and then they would see the incorrect value of checked. Additionally
|
||||
a command attribute would redirect the command events anyway.-->
|
||||
<handler event="click" button="0" action="this._handleClick();"/>
|
||||
<handler event="keypress" key=" ">
|
||||
<![CDATA[
|
||||
this._handleClick();
|
||||
// Prevent page from scrolling on the space key.
|
||||
event.preventDefault();
|
||||
]]>
|
||||
</handler>
|
||||
|
||||
<handler event="keypress">
|
||||
<![CDATA[
|
||||
if (this.hasMenu()) {
|
||||
if (this.open)
|
||||
return;
|
||||
} else {
|
||||
if (event.keyCode == KeyEvent.DOM_VK_UP ||
|
||||
(event.keyCode == KeyEvent.DOM_VK_LEFT &&
|
||||
document.defaultView.getComputedStyle(this.parentNode)
|
||||
.direction == "ltr") ||
|
||||
(event.keyCode == KeyEvent.DOM_VK_RIGHT &&
|
||||
document.defaultView.getComputedStyle(this.parentNode)
|
||||
.direction == "rtl")) {
|
||||
event.preventDefault();
|
||||
window.document.commandDispatcher.rewindFocus();
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.keyCode == KeyEvent.DOM_VK_DOWN ||
|
||||
(event.keyCode == KeyEvent.DOM_VK_RIGHT &&
|
||||
document.defaultView.getComputedStyle(this.parentNode)
|
||||
.direction == "ltr") ||
|
||||
(event.keyCode == KeyEvent.DOM_VK_LEFT &&
|
||||
document.defaultView.getComputedStyle(this.parentNode)
|
||||
.direction == "rtl")) {
|
||||
event.preventDefault();
|
||||
window.document.commandDispatcher.advanceFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (event.keyCode || event.charCode <= 32 || event.altKey ||
|
||||
event.ctrlKey || event.metaKey)
|
||||
return; // No printable char pressed, not a potential accesskey
|
||||
|
||||
// Possible accesskey pressed
|
||||
var charPressedLower = String.fromCharCode(event.charCode).toLowerCase();
|
||||
|
||||
// If the accesskey of the current button is pressed, just activate it
|
||||
if (this.accessKey.toLowerCase() == charPressedLower) {
|
||||
this.click();
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for accesskey in the list of buttons for this doc and each subdoc
|
||||
// Get the buttons for the main document and all sub-frames
|
||||
for (var frameCount = -1; frameCount < window.top.frames.length; frameCount++) {
|
||||
var doc = (frameCount == -1) ? window.top.document :
|
||||
window.top.frames[frameCount].document;
|
||||
if (this.fireAccessKeyButton(doc.documentElement, charPressedLower))
|
||||
return;
|
||||
}
|
||||
|
||||
// Test anonymous buttons
|
||||
var dlg = window.top.document;
|
||||
var buttonBox = dlg.getAnonymousElementByAttribute(dlg.documentElement,
|
||||
"anonid", "buttons");
|
||||
if (buttonBox)
|
||||
this.fireAccessKeyButton(buttonBox, charPressedLower);
|
||||
]]>
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
</bindings>
|
153
toolkit/content/widgets/toolbarbutton.js
Normal file
153
toolkit/content/widgets/toolbarbutton.js
Normal file
@ -0,0 +1,153 @@
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// This is loaded into all XUL windows. Wrap in a block to prevent
|
||||
// leaking to window scope.
|
||||
{
|
||||
const KEEP_CHILDREN = new Set(["observes", "template", "menupopup", "panel", "tooltip"]);
|
||||
|
||||
window.addEventListener("popupshowing", (e) => {
|
||||
if (e.originalTarget.ownerDocument != document) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.originalTarget.setAttribute("hasbeenopened", "true");
|
||||
for (let el of e.originalTarget.querySelectorAll("toolbarbutton")) {
|
||||
el.render();
|
||||
}
|
||||
}, {capture: true});
|
||||
|
||||
class MozToolbarbutton extends MozElements.ButtonBase {
|
||||
static get inheritedAttributes() {
|
||||
return {
|
||||
".toolbarbutton-icon": "validate,src=image,label,type,consumeanchor,triggeringprincipal=iconloadingprincipal",
|
||||
".toolbarbutton-text": "value=label,accesskey,crop,dragover-top,wrap",
|
||||
".toolbarbutton-multiline-text": "text=label,accesskey,wrap",
|
||||
".toolbarbutton-menu-dropmarker": "disabled,label",
|
||||
|
||||
".toolbarbutton-badge": "value=badge,style=badgeStyle",
|
||||
};
|
||||
}
|
||||
|
||||
static get fragment() {
|
||||
let frag = document.importNode(MozXULElement.parseXULToFragment(`
|
||||
<image class="toolbarbutton-icon"></image>
|
||||
<label class="toolbarbutton-text" crop="right" flex="1"></label>
|
||||
<label class="toolbarbutton-multiline-text" flex="1"></label>
|
||||
<dropmarker type="menu" class="toolbarbutton-menu-dropmarker"></dropmarker>`), true);
|
||||
Object.defineProperty(this, "fragment", {value: frag});
|
||||
return frag;
|
||||
}
|
||||
|
||||
static get badgedFragment() {
|
||||
let frag = document.importNode(MozXULElement.parseXULToFragment(`
|
||||
<stack class="toolbarbutton-badge-stack">
|
||||
<image class="toolbarbutton-icon"/>
|
||||
<label class="toolbarbutton-badge" top="0" end="0" crop="none"/>
|
||||
</stack>
|
||||
<label class="toolbarbutton-text" crop="right" flex="1"/>
|
||||
<label class="toolbarbutton-multiline-text" flex="1"/>
|
||||
<dropmarker anonid="dropmarker" type="menu"
|
||||
class="toolbarbutton-menu-dropmarker"/>`), true);
|
||||
Object.defineProperty(this, "badgedFragment", {value: frag});
|
||||
return frag;
|
||||
}
|
||||
|
||||
get _hasRendered() {
|
||||
return (this.querySelector(":scope > .toolbarbutton-text") != null);
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
if (this.delayConnectedCallback()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Defer creating DOM elements for content inside popups.
|
||||
// These will be added in the popupshown handler above.
|
||||
let panel = this.closest("panel");
|
||||
if (panel && !panel.hasAttribute("hasbeenopened")) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.render();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this._hasRendered) {
|
||||
return;
|
||||
}
|
||||
|
||||
let badged = (this.getAttribute("badged") == "true");
|
||||
|
||||
if (badged) {
|
||||
let moveChildren = [];
|
||||
for (let child of this.children) {
|
||||
if (!KEEP_CHILDREN.has(child.tagName)) {
|
||||
moveChildren.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
this.appendChild(this.constructor.badgedFragment.cloneNode(true));
|
||||
|
||||
if (moveChildren.length > 0) {
|
||||
let {badgeStack, icon} = this;
|
||||
for (let child of moveChildren) {
|
||||
badgeStack.insertBefore(child, icon);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let moveChildren = [];
|
||||
for (let child of this.children) {
|
||||
if (!KEEP_CHILDREN.has(child.tagName) && child.tagName != "box") {
|
||||
// XBL toolbarbutton doesn't insert any anonymous content
|
||||
// if it has a child of any other type
|
||||
return;
|
||||
}
|
||||
|
||||
if (child.tagName == "box") {
|
||||
moveChildren.push(child);
|
||||
}
|
||||
}
|
||||
|
||||
this.appendChild(this.constructor.fragment.cloneNode(true));
|
||||
|
||||
// XBL toolbarbutton explicitly places any <box> children
|
||||
// right before the menu marker.
|
||||
for (let child of moveChildren) {
|
||||
this.insertBefore(child, this.lastChild);
|
||||
}
|
||||
}
|
||||
|
||||
this.initializeAttributeInheritance();
|
||||
}
|
||||
|
||||
get icon() {
|
||||
return this.querySelector(".toolbarbutton-icon");
|
||||
}
|
||||
|
||||
get badgeLabel() {
|
||||
return this.querySelector(".toolbarbutton-badge");
|
||||
}
|
||||
|
||||
get badgeStack() {
|
||||
return this.querySelector(".toolbarbutton-badge-stack");
|
||||
}
|
||||
|
||||
get multilineLabel() {
|
||||
return this.querySelector(".toolbarbutton-multiline-text");
|
||||
}
|
||||
|
||||
get dropmarker() {
|
||||
return this.querySelector(".toolbarbutton-menu-dropmarker");
|
||||
}
|
||||
|
||||
get menupopup() {
|
||||
return this.querySelector("menupopup");
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define("toolbarbutton", MozToolbarbutton);
|
||||
}
|
@ -1,48 +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/. -->
|
||||
|
||||
|
||||
<bindings id="toolbarbuttonBindings"
|
||||
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="toolbarbutton"
|
||||
extends="chrome://global/content/bindings/button.xml#button-base">
|
||||
<implementation>
|
||||
<property name="multilineLabel"
|
||||
onget="return document.getAnonymousElementByAttribute(this, 'class', 'toolbarbutton-multiline-text');" />
|
||||
</implementation>
|
||||
<content>
|
||||
<children includes="observes|template|menupopup|panel|tooltip"/>
|
||||
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label,type,consumeanchor,triggeringprincipal=iconloadingprincipal"/>
|
||||
<xul:label class="toolbarbutton-text" crop="right" flex="1"
|
||||
xbl:inherits="value=label,accesskey,crop,dragover-top,wrap"/>
|
||||
<xul:label class="toolbarbutton-multiline-text" flex="1"
|
||||
xbl:inherits="xbl:text=label,accesskey,wrap"/>
|
||||
<children includes="box"/>
|
||||
<xul:dropmarker anonid="dropmarker" type="menu"
|
||||
class="toolbarbutton-menu-dropmarker" xbl:inherits="disabled,label"/>
|
||||
</content>
|
||||
</binding>
|
||||
|
||||
<binding id="toolbarbutton-badged"
|
||||
extends="chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton">
|
||||
<content>
|
||||
<children includes="observes|template|menupopup|panel|tooltip"/>
|
||||
<xul:stack class="toolbarbutton-badge-stack">
|
||||
<children/>
|
||||
<xul:image class="toolbarbutton-icon" xbl:inherits="validate,src=image,label,consumeanchor"/>
|
||||
<xul:label class="toolbarbutton-badge" xbl:inherits="value=badge,style=badgeStyle" top="0" end="0" crop="none"/>
|
||||
</xul:stack>
|
||||
<xul:label class="toolbarbutton-text" crop="right" flex="1"
|
||||
xbl:inherits="value=label,accesskey,crop,wrap"/>
|
||||
<xul:label class="toolbarbutton-multiline-text" flex="1"
|
||||
xbl:inherits="xbl:text=label,accesskey,wrap"/>
|
||||
<xul:dropmarker anonid="dropmarker" type="menu"
|
||||
class="toolbarbutton-menu-dropmarker" xbl:inherits="disabled,label"/>
|
||||
</content>
|
||||
</binding>
|
||||
</bindings>
|
@ -107,15 +107,6 @@ label html|span.accesskey {
|
||||
|
||||
/********** toolbarbutton **********/
|
||||
|
||||
toolbarbutton {
|
||||
-moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton");
|
||||
}
|
||||
|
||||
toolbarbutton.badged-button > toolbarbutton,
|
||||
toolbarbutton.badged-button {
|
||||
-moz-binding: url("chrome://global/content/bindings/toolbarbutton.xml#toolbarbutton-badged");
|
||||
}
|
||||
|
||||
.toolbarbutton-badge:not([value]),
|
||||
.toolbarbutton-badge[value=""] {
|
||||
display: none;
|
||||
|
Loading…
Reference in New Issue
Block a user