gecko-dev/toolkit/content/widgets/toolbar.xml

584 строки
20 KiB
XML

<?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("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;
iter:
// 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.
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++;
continue iter; // move on to the next id
}
}
// 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 () !!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>