/* 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);
}