231 lines
6.4 KiB
JavaScript
231 lines
6.4 KiB
JavaScript
/* 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() {
|
|
// Note: if you remove 'wrap' or 'label' from the inherited attributes,
|
|
// you'll need to add them to observedAttributes.
|
|
return {
|
|
".toolbarbutton-icon":
|
|
"validate,src=image,label,type,consumeanchor,triggeringprincipal=iconloadingprincipal",
|
|
".toolbarbutton-text": "accesskey,crop,dragover-top,wrap",
|
|
".toolbarbutton-menu-dropmarker": "disabled,label",
|
|
|
|
".toolbarbutton-badge": "text=badge,style=badgeStyle",
|
|
};
|
|
}
|
|
|
|
static get fragment() {
|
|
let frag = document.importNode(
|
|
MozXULElement.parseXULToFragment(`
|
|
<image class="toolbarbutton-icon"></image>
|
|
<label class="toolbarbutton-text" crop="end" flex="1"></label>
|
|
`),
|
|
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"/>
|
|
<html:label class="toolbarbutton-badge"/>
|
|
</stack>
|
|
<label class="toolbarbutton-text" crop="end" flex="1"/>
|
|
`),
|
|
true
|
|
);
|
|
Object.defineProperty(this, "badgedFragment", { value: frag });
|
|
return frag;
|
|
}
|
|
|
|
static get dropmarkerFragment() {
|
|
let frag = document.importNode(
|
|
MozXULElement.parseXULToFragment(`
|
|
<dropmarker type="menu" class="toolbarbutton-menu-dropmarker"></dropmarker>
|
|
`),
|
|
true
|
|
);
|
|
Object.defineProperty(this, "dropmarkerFragment", { value: frag });
|
|
return frag;
|
|
}
|
|
|
|
get _hasRendered() {
|
|
return this.querySelector(":scope > .toolbarbutton-text") != null;
|
|
}
|
|
|
|
get _textNode() {
|
|
let node = this.getElementForAttrInheritance(".toolbarbutton-text");
|
|
if (node) {
|
|
Object.defineProperty(this, "_textNode", { value: node });
|
|
}
|
|
return node;
|
|
}
|
|
|
|
_setLabel() {
|
|
let label = this.getAttribute("label") || "";
|
|
let hasLabel = this.hasAttribute("label");
|
|
if (this.getAttribute("wrap") == "true") {
|
|
this._textNode.removeAttribute("value");
|
|
this._textNode.textContent = label;
|
|
} else {
|
|
this._textNode.textContent = "";
|
|
if (hasLabel) {
|
|
this._textNode.setAttribute("value", label);
|
|
} else {
|
|
this._textNode.removeAttribute("value");
|
|
}
|
|
}
|
|
}
|
|
|
|
attributeChangedCallback(name, oldValue, newValue) {
|
|
if (oldValue === newValue || !this.initializedAttributeInheritance) {
|
|
return;
|
|
}
|
|
// Deal with single/multiline label inheritance:
|
|
if (name == "label" || name == "wrap") {
|
|
this._setLabel();
|
|
}
|
|
// The normal implementation will deal with everything else.
|
|
super.attributeChangedCallback(name, oldValue, newValue);
|
|
}
|
|
|
|
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 (this.hasAttribute("wantdropmarker")) {
|
|
this.appendChild(this.constructor.dropmarkerFragment.cloneNode(true));
|
|
}
|
|
|
|
if (moveChildren.length) {
|
|
let { badgeStack, icon } = this;
|
|
for (let child of moveChildren) {
|
|
if (child.getAttribute("move-after-stack") === "true") {
|
|
this.appendChild(child);
|
|
} else {
|
|
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));
|
|
|
|
if (this.hasAttribute("wantdropmarker")) {
|
|
this.appendChild(this.constructor.dropmarkerFragment.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();
|
|
this._setLabel();
|
|
}
|
|
|
|
get icon() {
|
|
return this.querySelector(".toolbarbutton-icon");
|
|
}
|
|
|
|
get badgeLabel() {
|
|
return this.querySelector(".toolbarbutton-badge");
|
|
}
|
|
|
|
get badgeStack() {
|
|
return this.querySelector(".toolbarbutton-badge-stack");
|
|
}
|
|
|
|
get multilineLabel() {
|
|
if (this.getAttribute("wrap") == "true") {
|
|
return this._textNode;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
get dropmarker() {
|
|
return this.querySelector(".toolbarbutton-menu-dropmarker");
|
|
}
|
|
|
|
get menupopup() {
|
|
return this.querySelector("menupopup");
|
|
}
|
|
}
|
|
|
|
customElements.define("toolbarbutton", MozToolbarbutton);
|
|
}
|