<?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="toolbarBindings" 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="toolbar-base"> <resources> <stylesheet src="chrome://global/skin/toolbar.css"/> </resources> </binding> <binding id="toolbox" extends="chrome://global/content/bindings/toolbar.xml#toolbar-base"> <implementation> <field name="palette"> null </field> <field name="toolbarset"> null </field> <field name="customToolbarCount"> 0 </field> <field name="externalToolbars"> [] </field> <!-- Set by customizeToolbar.js --> <property name="customizing"> <getter><![CDATA[ return this.getAttribute("customizing") == "true"; ]]></getter> <setter><![CDATA[ if (val) this.setAttribute("customizing", "true"); else this.removeAttribute("customizing"); return val; ]]></setter> </property> <constructor> <![CDATA[ // Look to see if there is a toolbarset. this.toolbarset = this.firstChild; while (this.toolbarset && this.toolbarset.localName != "toolbarset") this.toolbarset = toolbarset.nextSibling; if (this.toolbarset) { // Create each toolbar described by the toolbarset. var index = 0; while (toolbarset.hasAttribute("toolbar"+(++index))) { var toolbarInfo = toolbarset.getAttribute("toolbar"+index); var infoSplit = toolbarInfo.split(":"); this.appendCustomToolbar(infoSplit[0], infoSplit[1]); } } ]]> </constructor> <method name="appendCustomToolbar"> <parameter name="aName"/> <parameter name="aCurrentSet"/> <body> <![CDATA[ if (!this.toolbarset) return null; var toolbar = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "toolbar"); toolbar.id = "__customToolbar_" + aName.replace(" ", "_"); toolbar.setAttribute("customizable", "true"); toolbar.setAttribute("customindex", ++this.customToolbarCount); toolbar.setAttribute("toolbarname", aName); toolbar.setAttribute("currentset", aCurrentSet); toolbar.setAttribute("mode", this.getAttribute("mode")); toolbar.setAttribute("iconsize", this.getAttribute("iconsize")); toolbar.setAttribute("context", this.toolbarset.getAttribute("context")); toolbar.setAttribute("class", "chromeclass-toolbar"); this.insertBefore(toolbar, this.toolbarset); return toolbar; ]]> </body> </method> </implementation> </binding> <binding id="toolbar" role="xul:toolbar" extends="chrome://global/content/bindings/toolbar.xml#toolbar-base"> <implementation> <property name="toolbarName" onget="return this.getAttribute('toolbarname');" onset="this.setAttribute('toolbarname', val); return val;"/> <field name="_toolbox">null</field> <property name="toolbox" readonly="true"> <getter><![CDATA[ if (this._toolbox) return this._toolbox; let toolboxId = this.getAttribute("toolboxid"); if (toolboxId) { let toolbox = document.getElementById(toolboxId); if (!toolbox) { let tbName = this.toolbarName; if (tbName) tbName = " (" + tbName + ")"; else tbName = ""; throw new Error(`toolbar ID ${this.id}${tbName}: toolboxid attribute '${toolboxId}' points to a toolbox that doesn't exist`); } if (toolbox.externalToolbars.indexOf(this) == -1) toolbox.externalToolbars.push(this); return this._toolbox = toolbox; } return this._toolbox = (this.parentNode && this.parentNode.localName == "toolbox") ? this.parentNode : null; ]]></getter> </property> <constructor> <![CDATA[ if (document.readyState == "complete") { this._init(); } else { // Need to wait until XUL overlays are loaded. See bug 554279. let self = this; document.addEventListener("readystatechange", function (event) { if (document.readyState != "complete") return; document.removeEventListener("readystatechange", arguments.callee, false); self._init(); }, false); } ]]> </constructor> <method name="_init"> <body> <![CDATA[ // Searching for the toolbox palette in the toolbar binding because // toolbars are constructed first. var toolbox = this.toolbox; if (!toolbox) return; if (!toolbox.palette) { // Look to see if there is a toolbarpalette. var node = toolbox.firstChild; while (node) { if (node.localName == "toolbarpalette") break; node = node.nextSibling; } if (!node) return; // Hold on to the palette but remove it from the document. toolbox.palette = node; toolbox.removeChild(node); } // Build up our contents from the palette. var currentSet = this.getAttribute("currentset"); if (!currentSet) currentSet = this.getAttribute("defaultset"); if (currentSet) this.currentSet = currentSet; ]]> </body> </method> <method name="_idFromNode"> <parameter name="aNode"/> <body> <![CDATA[ if (aNode.getAttribute("skipintoolbarset") == "true") return ""; switch (aNode.localName) { case "toolbarseparator": return "separator"; case "toolbarspring": return "spring"; case "toolbarspacer": return "spacer"; default: return aNode.id; } ]]> </body> </method> <property name="currentSet"> <getter> <![CDATA[ var node = this.firstChild; var currentSet = []; while (node) { var id = this._idFromNode(node); if (id) { currentSet.push(id); } node = node.nextSibling; } return currentSet.join(",") || "__empty"; ]]> </getter> <setter> <![CDATA[ if (val == this.currentSet) return val; var ids = (val == "__empty") ? [] : val.split(","); var nodeidx = 0; var paletteItems = { }, added = { }; var palette = this.toolbox ? this.toolbox.palette : null; // build a cache of items in the toolbarpalette var paletteChildren = palette ? palette.childNodes : []; for (let c = 0; c < paletteChildren.length; c++) { let curNode = paletteChildren[c]; paletteItems[curNode.id] = curNode; } var children = this.childNodes; // iterate over the ids to use on the toolbar for (let i = 0; i < ids.length; i++) { let id = ids[i]; // iterate over the existing nodes on the toolbar. nodeidx is the // spot where we want to insert items. let found = false; for (let c = nodeidx; c < children.length; c++) { let curNode = children[c]; if (this._idFromNode(curNode) == id) { // the node already exists. If c equals nodeidx, we haven't // iterated yet, so the item is already in the right position. // Otherwise, insert it here. if (c != nodeidx) { this.insertBefore(curNode, children[nodeidx]); } added[curNode.id] = true; nodeidx++; found = true; break; } } if (found) { // move on to the next id continue; } // the node isn't already on the toolbar, so add a new one. var nodeToAdd = paletteItems[id] || this._getToolbarItem(id); if (nodeToAdd && !(nodeToAdd.id in added)) { added[nodeToAdd.id] = true; this.insertBefore(nodeToAdd, children[nodeidx] || null); nodeToAdd.setAttribute("removable", "true"); nodeidx++; } } // remove any leftover removable nodes for (let i = children.length - 1; i >= nodeidx; i--) { let curNode = children[i]; let curNodeId = this._idFromNode(curNode); // skip over fixed items if (curNodeId && curNode.getAttribute("removable") == "true") { if (palette) palette.appendChild(curNode); else this.removeChild(curNode); } } return val; ]]> </setter> </property> <field name="_newElementCount">0</field> <method name="_getToolbarItem"> <parameter name="aId"/> <body> <![CDATA[ const XUL_NS = "http://www.mozilla.org/keymaster/" + "gatekeeper/there.is.only.xul"; var newItem = null; switch (aId) { // Handle special cases case "separator": case "spring": case "spacer": newItem = document.createElementNS(XUL_NS, "toolbar" + aId); // Due to timers resolution Date.now() can be the same for // elements created in small timeframes. So ids are // differentiated through a unique count suffix. newItem.id = aId + Date.now() + (++this._newElementCount); if (aId == "spring") newItem.flex = 1; break; default: var toolbox = this.toolbox; if (!toolbox) break; // look for an item with the same id, as the item may be // in a different toolbar. var item = document.getElementById(aId); if (item && item.parentNode && item.parentNode.localName == "toolbar" && item.parentNode.toolbox == toolbox) { newItem = item; break; } if (toolbox.palette) { // Attempt to locate an item with a matching ID within // the palette. let paletteItem = this.toolbox.palette.firstChild; while (paletteItem) { if (paletteItem.id == aId) { newItem = paletteItem; break; } paletteItem = paletteItem.nextSibling; } } break; } return newItem; ]]> </body> </method> <method name="insertItem"> <parameter name="aId"/> <parameter name="aBeforeElt"/> <parameter name="aWrapper"/> <body> <![CDATA[ var newItem = this._getToolbarItem(aId); if (!newItem) return null; var insertItem = newItem; // make sure added items are removable newItem.setAttribute("removable", "true"); // Wrap the item in another node if so inclined. if (aWrapper) { aWrapper.appendChild(newItem); insertItem = aWrapper; } // Insert the palette item into the toolbar. if (aBeforeElt) this.insertBefore(insertItem, aBeforeElt); else this.appendChild(insertItem); return newItem; ]]> </body> </method> <method name="hasCustomInteractiveItems"> <parameter name="aCurrentSet"/> <body><![CDATA[ if (aCurrentSet == "__empty") return false; var defaultOrNoninteractive = (this.getAttribute("defaultset") || "") .split(",") .concat(["separator", "spacer", "spring"]); return aCurrentSet.split(",").some(function (item) { return defaultOrNoninteractive.indexOf(item) == -1; }); ]]></body> </method> </implementation> </binding> <binding id="toolbar-menubar-autohide" extends="chrome://global/content/bindings/toolbar.xml#toolbar"> <implementation> <constructor> this._setInactive(); </constructor> <destructor> this._setActive(); </destructor> <field name="_inactiveTimeout">null</field> <field name="_contextMenuListener"><![CDATA[({ toolbar: this, contextMenu: null, get active () { return !!this.contextMenu; }, init: function (event) { var node = event.target; while (node != this.toolbar) { if (node.localName == "menupopup") return; node = node.parentNode; } var contextMenuId = this.toolbar.getAttribute("context"); if (!contextMenuId) return; this.contextMenu = document.getElementById(contextMenuId); if (!this.contextMenu) return; this.contextMenu.addEventListener("popupshown", this, false); this.contextMenu.addEventListener("popuphiding", this, false); this.toolbar.addEventListener("mousemove", this, false); }, handleEvent: function (event) { switch (event.type) { case "popupshown": this.toolbar.removeEventListener("mousemove", this, false); break; case "popuphiding": case "mousemove": this.toolbar._setInactiveAsync(); this.toolbar.removeEventListener("mousemove", this, false); this.contextMenu.removeEventListener("popuphiding", this, false); this.contextMenu.removeEventListener("popupshown", this, false); this.contextMenu = null; break; } } })]]></field> <method name="_setInactive"> <body><![CDATA[ this.setAttribute("inactive", "true"); ]]></body> </method> <method name="_setInactiveAsync"> <body><![CDATA[ this._inactiveTimeout = setTimeout(function (self) { if (self.getAttribute("autohide") == "true") { self._inactiveTimeout = null; self._setInactive(); } }, 0, this); ]]></body> </method> <method name="_setActive"> <body><![CDATA[ if (this._inactiveTimeout) { clearTimeout(this._inactiveTimeout); this._inactiveTimeout = null; } this.removeAttribute("inactive"); ]]></body> </method> </implementation> <handlers> <handler event="DOMMenuBarActive" action="this._setActive();"/> <handler event="popupshowing" action="this._setActive();"/> <handler event="mousedown" button="2" action="this._contextMenuListener.init(event);"/> <handler event="DOMMenuBarInactive"><![CDATA[ if (!this._contextMenuListener.active) this._setInactiveAsync(); ]]></handler> </handlers> </binding> <binding id="toolbar-drag" extends="chrome://global/content/bindings/toolbar.xml#toolbar"> <implementation> <field name="_dragBindingAlive">true</field> <constructor><![CDATA[ if (!this._draggableStarted) { this._draggableStarted = true; try { let tmp = {}; Components.utils.import("resource://gre/modules/WindowDraggingUtils.jsm", tmp); let draggableThis = new tmp.WindowDraggingElement(this); draggableThis.mouseDownCheck = function(e) { // Don't move while customizing. return this._dragBindingAlive && this.getAttribute("customizing") != "true"; }; } catch (e) {} } ]]></constructor> </implementation> </binding> <binding id="menubar" role="xul:menubar" extends="chrome://global/content/bindings/toolbar.xml#toolbar-base" display="xul:menubar"> <implementation> <field name="_active">false</field> <field name="_statusbar">null</field> <field name="_originalStatusText">null</field> <property name="statusbar" onget="return this.getAttribute('statusbar');" onset="this.setAttribute('statusbar', val); return val;"/> <method name="_updateStatusText"> <parameter name="itemText"/> <body> <![CDATA[ if (!this._active) return; var newText = itemText ? itemText : this._originalStatusText; if (newText != this._statusbar.label) this._statusbar.label = newText; ]]> </body> </method> </implementation> <handlers> <handler event="DOMMenuBarActive"> <![CDATA[ if (!this.statusbar) return; this._statusbar = document.getElementById(this.statusbar); if (!this._statusbar) return; this._active = true; this._originalStatusText = this._statusbar.label; ]]> </handler> <handler event="DOMMenuBarInactive"> <![CDATA[ if (!this._active) return; this._active = false; this._statusbar.label = this._originalStatusText; ]]> </handler> <handler event="DOMMenuItemActive">this._updateStatusText(event.target.statusText);</handler> <handler event="DOMMenuItemInactive">this._updateStatusText("");</handler> </handlers> </binding> <binding id="toolbardecoration" role="xul:toolbarseparator" extends="chrome://global/content/bindings/toolbar.xml#toolbar-base"> </binding> <binding id="toolbarpaletteitem" extends="chrome://global/content/bindings/toolbar.xml#toolbar-base" display="xul:button"> <content> <xul:hbox class="toolbarpaletteitem-box" flex="1" xbl:inherits="type,place"> <children/> </xul:hbox> </content> </binding> <binding id="toolbarpaletteitem-palette" extends="chrome://global/content/bindings/toolbar.xml#toolbarpaletteitem"> <content> <xul:hbox class="toolbarpaletteitem-box" xbl:inherits="type,place"> <children/> </xul:hbox> <xul:label xbl:inherits="value=title"/> </content> </binding> </bindings>