diff options
Diffstat (limited to 'toolkit/content/widgets/toolbar.xml')
-rw-r--r-- | toolkit/content/widgets/toolbar.xml | 590 |
1 files changed, 590 insertions, 0 deletions
diff --git a/toolkit/content/widgets/toolbar.xml b/toolkit/content/widgets/toolbar.xml new file mode 100644 index 000000000..548504e24 --- /dev/null +++ b/toolkit/content/widgets/toolbar.xml @@ -0,0 +1,590 @@ +<?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> + |