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

630 lines
21 KiB
XML

<?xml version="1.0"?>
<!DOCTYPE bindings [
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
]>
<bindings id="tabBindings"
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="tab-base">
<resources>
<stylesheet src="chrome://global/skin/tabbox.css"/>
</resources>
</binding>
<binding id="tabbox" display="xul:box"
extends="chrome://global/content/bindings/tabbox.xml#tab-base">
<implementation implements="nsIAccessibleProvider">
<property name="accessible">
<getter>
<![CDATA[
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
return accService.createXULTabBoxAccessible(this);
]]>
</getter>
</property>
<property name="handleCtrlTab">
<setter>
<![CDATA[
this.setAttribute("handleCtrlTab", val);
return val;
]]>
</setter>
<getter>
<![CDATA[
return (this.getAttribute("handleCtrlTab") != "false");
]]>
</getter>
</property>
<property name="handleCtrlPageUpDown">
<setter>
<![CDATA[
this.setAttribute("handleCtrlPageUpDown", val);
return val;
]]>
</setter>
<getter>
<![CDATA[
return (this.getAttribute("handleCtrlPageUpDown") != "false");
]]>
</getter>
</property>
<field name="_handleMetaAltArrows" readonly="true">
#ifdef XP_MACOSX
true
#else
false
#endif
</field>
<property name="_tabs">
<getter>
<![CDATA[
var tabs = this.getElementsByTagNameNS(
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"tabs");
return tabs.length ? tabs[0] : null;
]]>
</getter>
</property>
<property name="_tabpanels">
<getter>
<![CDATA[
var tabpanels = this.getElementsByTagNameNS(
"http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
"tabpanels");
return tabpanels.length ? tabpanels[0] : null;
]]>
</getter>
</property>
<property name="selectedIndex"
onget="return this._tabs ? this._tabs.selectedIndex : null;">
<setter>
<![CDATA[
if (this._tabs)
this._tabs.selectedIndex = val;
this.setAttribute("selectedIndex", val);
return val;
]]>
</setter>
</property>
<property name="selectedTab"
onget="return this._tabs ? this._tabs.selectedItem : null;">
<setter>
<![CDATA[
if (!val)
throw Components.results.NS_ERROR_NULL_POINTER;
if (this._tabs)
this._tabs.selectedItem = val;
return val;
]]>
</setter>
</property>
<property name="selectedPanel"
onget="return this._tabpanels ? this._tabpanels.selectedPanel : null;">
<setter>
<![CDATA[
if (!val)
throw Components.results.NS_ERROR_NULL_POINTER;
if (this._tabpanels)
this._tabpanels.selectedPanel = val;
return val;
]]>
</setter>
</property>
<field name="_keyEventHandler" readonly="true">
<![CDATA[({
tabbox: this,
handleEvent: function handleEvent(event) {
if (!event.isTrusted) {
// Don't let untrusted events mess with tabs.
return;
}
switch (event.keyCode) {
case event.DOM_VK_TAB:
if (event.ctrlKey && !event.altKey && !event.metaKey)
if (this.tabbox._tabs && this.tabbox.handleCtrlTab) {
this.tabbox._tabs.advanceSelectedTab(event.shiftKey ? -1 : 1, true);
event.stopPropagation();
event.preventDefault();
}
break;
case event.DOM_VK_PAGE_UP:
if (event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey)
if (this.tabbox._tabs && this.tabbox.handleCtrlPageUpDown) {
this.tabbox._tabs.advanceSelectedTab(-1, true);
event.stopPropagation();
event.preventDefault();
}
break;
case event.DOM_VK_PAGE_DOWN:
if (event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey)
if (this.tabbox._tabs && this.tabbox.handleCtrlPageUpDown) {
this.tabbox._tabs.advanceSelectedTab(1, true);
event.stopPropagation();
event.preventDefault();
}
break;
case event.DOM_VK_LEFT:
if (event.metaKey && event.altKey && !event.shiftKey && !event.ctrlKey)
if (this.tabbox._tabs && this.tabbox._handleMetaAltArrows) {
var offset = window.getComputedStyle(this.tabbox, "")
.direction == "ltr" ? -1 : 1;
this.tabbox._tabs.advanceSelectedTab(offset, true);
event.stopPropagation();
event.preventDefault();
}
break;
case event.DOM_VK_RIGHT:
if (event.metaKey && event.altKey && !event.shiftKey && !event.ctrlKey)
if (this.tabbox._tabs && this.tabbox._handleMetaAltArrows) {
var offset = window.getComputedStyle(this.tabbox, "")
.direction == "ltr" ? 1 : -1;
this.tabbox._tabs.advanceSelectedTab(offset, true);
event.stopPropagation();
event.preventDefault();
}
break;
}
}
})]]>
</field>
<field name="_eventNode">this</field>
<property name="eventNode" onget="return this._eventNode;">
<setter>
<![CDATA[
if (val != this._eventNode) {
val.addEventListener("keypress", this._keyEventHandler, false);
this._eventNode.removeEventListener("keypress", this._keyEventHandler, false);
this._eventNode = val;
}
return val;
]]>
</setter>
</property>
<constructor>
switch (this.getAttribute("eventnode")) {
case "parent": this._eventNode = this.parentNode; break;
case "window": this._eventNode = window; break;
case "document": this._eventNode = document; break;
}
this._eventNode.addEventListener("keypress", this._keyEventHandler, false);
</constructor>
<destructor>
this._eventNode.removeEventListener("keypress", this._keyEventHandler, false);
</destructor>
</implementation>
</binding>
<binding id="tabs" display="xul:box"
extends="chrome://global/content/bindings/tabbox.xml#tab-base">
<content>
<xul:spacer class="tabs-left"/>
<children/>
<xul:spacer class="tabs-right" flex="1"/>
</content>
<implementation implements="nsIDOMXULSelectControlElement, nsIAccessibleProvider">
<constructor>
<![CDATA[
// first and last tabs need to be able to have unique styles
// and also need to select first tab on startup.
if (this.firstChild)
this.firstChild.setAttribute("first-tab", "true");
if (this.lastChild)
this.lastChild.setAttribute("last-tab", "true");
var selectedIndex = -1;
for (var parent = this.parentNode; parent; parent = parent.parentNode) {
if (parent.localName == "tabbox" && parent.hasAttribute("selectedIndex"))
selectedIndex = parseInt(parent.getAttribute("selectedIndex"));
}
this.selectedIndex = selectedIndex > 0 ? selectedIndex : 0;
var o = this.getAttribute("orient");
if (!o)
this.setAttribute("orient", "horizontal");
]]>
</constructor>
<property name="accessible">
<getter>
<![CDATA[
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
return accService.createXULTabsAccessible(this);
]]>
</getter>
</property>
<property name="selectedIndex">
<getter>
<![CDATA[
const tabs = this.childNodes;
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].selected)
return i;
}
// throw an exception when no tab is selected (we shouldn't get here)
throw Components.results.NS_ERROR_FAILURE;
]]>
</getter>
<setter>
<![CDATA[
const tabs = this.childNodes;
if (0 <= val && val < tabs.length && !tabs[val].selected) {
for (var i = 0; i < tabs.length; i++)
if (i != val && tabs[i].selected)
tabs[i].selected = false;
tabs[val].selected = true;
for (var parent = this.parentNode; parent; parent = parent.parentNode) {
if (parent.localName == 'tabbox') {
var tabpanels = parent._tabpanels;
// This will cause an onselect event to fire for the tabpanel element.
if (tabpanels) {
// find an id
var linkedPanelId = tabs[val].linkedPanel;
var linkedPanel = linkedPanelId ? document.getElementById(linkedPanelId) : null;
if (linkedPanel)
tabpanels.selectedPanel = linkedPanel;
else
tabpanels.selectedIndex = val;
}
break;
}
}
// Fire an onselect event for the tabs element.
var event = document.createEvent('Events');
event.initEvent('select', false, true);
this.dispatchEvent(event);
}
return val;
]]>
</setter>
</property>
<property name="selectedItem">
<getter>
<![CDATA[
const tabs = this.childNodes;
for (var i = 0; i < tabs.length; i++) {
if (tabs[i].selected)
return tabs[i];
}
// throw an exception when no tab is selected (we shouldn't get here)
throw Components.results.NS_ERROR_FAILURE;
]]>
</getter>
<setter>
<![CDATA[
if (!val)
throw Components.results.NS_ERROR_NULL_POINTER;
if (!val.selected) {
const tabs = this.childNodes;
for (var i = 0; i < tabs.length; i++)
if (tabs[i] == val)
this.selectedIndex = i;
}
return val;
]]>
</setter>
</property>
<method name="selectNewTab">
<parameter name="aNewTab"/>
<parameter name="aFallbackDir"/>
<parameter name="aWrap"/>
<body>
<![CDATA[
while (aNewTab.getAttribute("hidden")) {
aNewTab = aFallbackDir == -1 ? aNewTab.previousSibling : aNewTab.nextSibling;
if (!aNewTab && aWrap)
aNewTab = aFallbackDir == -1 ? this.childNodes[this.childNodes.length - 1] :
this.childNodes[0];
}
var isTabFocused =
(document.commandDispatcher.focusedElement == this.selectedItem);
this.selectedItem = aNewTab;
if (isTabFocused) {
aNewTab.focus();
}
else if (this.getAttribute("setfocus") != "false") {
document.commandDispatcher.advanceFocusIntoSubtree(aNewTab);
}
]]>
</body>
</method>
<method name="advanceSelectedTab">
<parameter name="aDir"/>
<parameter name="aWrap"/>
<body>
<![CDATA[
var startTab = this.selectedItem;
var next = startTab[aDir == -1 ? "previousSibling" : "nextSibling"];
if (!next && aWrap) {
next = aDir == -1 ? this.childNodes[this.childNodes.length - 1] :
this.childNodes[0];
}
if (next && next != startTab) {
this.selectNewTab(next, aDir, aWrap);
}
]]>
</body>
</method>
<method name="appendItem">
<parameter name="label"/>
<parameter name="value"/>
<body>
<![CDATA[
var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var tab = document.createElementNS(XULNS, "tab");
tab.setAttribute("label", label);
tab.setAttribute("value", value);
this.appendChild(tab);
return tab;
]]>
</body>
</method>
<method name="insertItemAt">
<parameter name="index"/>
<parameter name="label"/>
<parameter name="value"/>
<body>
<![CDATA[
var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
var tab = document.createElementNS(XULNS, "tab");
tab.setAttribute("label", label);
tab.setAttribute("value", value);
var before = this.childNodes[index];
if (before)
this.insertBefore(tab, before);
else
this.appendChild(tab);
return tab;
]]>
</body>
</method>
<method name="removeItemAt">
<parameter name="index"/>
<body>
<![CDATA[
var remove = this.childNodes[index];
if (remove)
this.removeChild(remove);
return remove;
]]>
</body>
</method>
</implementation>
</binding>
<binding id="tabs-closebutton"
extends="chrome://global/content/bindings/tabbox.xml#tabs">
<content>
<xul:hbox flex="1" style="min-width: 1px;">
<children/>
<xul:spacer class="tabs-right" flex="1"/>
</xul:hbox>
<xul:stack>
<xul:spacer class="tabs-right"/>
<xul:hbox class="tabs-closebutton-box" align="center" pack="end">
<xul:toolbarbutton ondblclick="event.preventBubble();" class="tabs-closebutton close-button" xbl:inherits="disabled=disableclose,oncommand=onclosetab"/>
</xul:hbox>
</xul:stack>
</content>
</binding>
<binding id="tabpanels"
extends="chrome://global/content/bindings/tabbox.xml#tab-base">
<implementation implements="nsIAccessibleProvider">
<property name="accessible">
<getter>
<![CDATA[
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
return accService.createXULTabPanelsAccessible(this);
]]>
</getter>
</property>
<field name="_selectedPanel">null</field>
<property name="selectedIndex">
<getter>
<![CDATA[
var indexStr = this.getAttribute("selectedIndex");
return indexStr ? parseInt(indexStr) : -1;
]]>
</getter>
<setter>
<![CDATA[
var panel = this._selectedPanel;
this._selectedPanel = this.childNodes[val];
this.setAttribute("selectedIndex", val);
if (this._selectedPanel != panel) {
var event = document.createEvent("Events");
event.initEvent("select", false, true);
this.dispatchEvent(event);
}
return val;
]]>
</setter>
</property>
<property name="selectedPanel">
<getter>
<![CDATA[
return this._selectedPanel;
]]>
</getter>
<setter>
<![CDATA[
var selectedIndex = -1;
for (var panel = val; panel != null; panel = panel.previousSibling)
++selectedIndex;
this.selectedIndex = selectedIndex;
return val;
]]>
</setter>
</property>
</implementation>
</binding>
<binding id="tab" display="xul:button"
extends="chrome://global/content/bindings/tabbox.xml#tab-base">
<content chromedir="&locale.dir;">
<xul:hbox class="tab-middle box-inherit" xbl:inherits="align,dir,pack,orient,selected" flex="1">
<xul:image class="tab-icon" xbl:inherits="validate,src=image"/>
<xul:label class="tab-text" xbl:inherits="value=label,accesskey,crop,disabled" flex="1"/>
</xul:hbox>
</content>
<implementation implements="nsIDOMXULSelectControlItemElement, nsIAccessibleProvider">
<property name="accessible">
<getter>
<![CDATA[
var accService = Components.classes["@mozilla.org/accessibilityService;1"].getService(Components.interfaces.nsIAccessibilityService);
return accService.createXULTabAccessible(this);
]]>
</getter>
</property>
<property name="label">
<getter>
return this.getAttribute("label");
</getter>
<setter>
this.setAttribute("label", val);
return val;
</setter>
</property>
<property name="tabs"
onget="return this.getAttribute('tabs');"
onset="this.setAttribute('tabs', val); return val;"/>
<!-- XXX -->
<property name="selected">
<getter>
return this.getAttribute("selected") == "true" ? true : false;
</getter>
<setter>
this.setAttribute("selected", val);
if (this.previousSibling) {
if (val)
this.previousSibling.setAttribute("beforeselected", val);
else
this.previousSibling.removeAttribute("beforeselected");
}
if (this.nextSibling) {
if (val)
this.nextSibling.setAttribute("afterselected", val);
else
this.nextSibling.removeAttribute("afterselected");
}
return val;
</setter>
</property>
<property name="linkedPanel" onget="return this.getAttribute('linkedpanel')"
onset="this.setAttribute('linkedpanel', val); return val;"/>
<field name="arrowKeysShouldWrap" readonly="true">
#ifdef XP_MACOSX
true
#else
false
#endif
</field>
</implementation>
<handlers>
<handler event="mousedown" button="0">
<![CDATA[
if (this != this.parentNode.selectedItem) { // Not selected yet
// Select new tab after short delay so that PostHandleEvent() doesn't see
// the tab as selected yet, otherwise it will focus the tab for us --
// the CSS for tab has -moz-user-focus: normal only for selected="true".
function setTab(tab) {
tab.parentNode.selectNewTab(tab);
}
setTimeout(setTab, 0, this);
}
// Otherwise this tab is already selected and we will fall
// through to mousedown behavior which sets focus on the current tab,
// Only a click on an already selected tab should focus the tab itself.
]]>
</handler>
<handler event="keypress" keycode="VK_LEFT">
<![CDATA[
var direction = window.getComputedStyle(this.parentNode, null).direction;
this.parentNode.advanceSelectedTab(direction == 'ltr' ? -1 : 1, this.arrowKeysShouldWrap);
]]>
</handler>
<handler event="keypress" keycode="VK_RIGHT">
<![CDATA[
var direction = window.getComputedStyle(this.parentNode, null).direction;
this.parentNode.advanceSelectedTab(direction == 'ltr' ? 1 : -1, this.arrowKeysShouldWrap);
]]>
</handler>
<handler event="keypress" keycode="VK_UP">
<![CDATA[
this.parentNode.advanceSelectedTab(-1, this.arrowKeysShouldWrap);
]]>
</handler>
<handler event="keypress" keycode="VK_DOWN">
<![CDATA[
this.parentNode.advanceSelectedTab(1, this.arrowKeysShouldWrap);
]]>
</handler>
<handler event="keypress" keycode="VK_HOME">
<![CDATA[
this.parentNode.selectNewTab(this.parentNode.childNodes[0]);
]]>
</handler>
<handler event="keypress" keycode="VK_END">
<![CDATA[
this.parentNode.selectNewTab(this.parentNode.childNodes[this.parentNode.childNodes.length - 1], -1);
]]>
</handler>
</handlers>
</binding>
</bindings>