1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/content/widgets/tabbox.xml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,851 @@ 1.4 +<?xml version="1.0"?> 1.5 +<!-- This Source Code Form is subject to the terms of the Mozilla Public 1.6 + - License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> 1.8 + 1.9 + 1.10 +<bindings id="tabBindings" 1.11 + xmlns="http://www.mozilla.org/xbl" 1.12 + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 1.13 + xmlns:xbl="http://www.mozilla.org/xbl"> 1.14 + 1.15 + <binding id="tab-base"> 1.16 + <resources> 1.17 + <stylesheet src="chrome://global/skin/tabbox.css"/> 1.18 + </resources> 1.19 + </binding> 1.20 + 1.21 + <binding id="tabbox" 1.22 + extends="chrome://global/content/bindings/tabbox.xml#tab-base"> 1.23 + <implementation implements="nsIDOMEventListener"> 1.24 + <property name="handleCtrlTab"> 1.25 + <setter> 1.26 + <![CDATA[ 1.27 + this.setAttribute("handleCtrlTab", val); 1.28 + return val; 1.29 + ]]> 1.30 + </setter> 1.31 + <getter> 1.32 + <![CDATA[ 1.33 + return (this.getAttribute("handleCtrlTab") != "false"); 1.34 + ]]> 1.35 + </getter> 1.36 + </property> 1.37 + 1.38 + <property name="handleCtrlPageUpDown"> 1.39 + <setter> 1.40 + <![CDATA[ 1.41 + this.setAttribute("handleCtrlPageUpDown", val); 1.42 + return val; 1.43 + ]]> 1.44 + </setter> 1.45 + <getter> 1.46 + <![CDATA[ 1.47 + return (this.getAttribute("handleCtrlPageUpDown") != "false"); 1.48 + ]]> 1.49 + </getter> 1.50 + </property> 1.51 + 1.52 + <field name="_handleMetaAltArrows" readonly="true"> 1.53 +#ifdef XP_MACOSX 1.54 + true 1.55 +#else 1.56 + false 1.57 +#endif 1.58 + </field> 1.59 + 1.60 + <!-- _tabs and _tabpanels are deprecated, they exist only for 1.61 + backwards compatibility. --> 1.62 + <property name="_tabs" readonly="true" onget="return this.tabs;"/> 1.63 + <property name="_tabpanels" readonly="true" onget="return this.tabpanels;"/> 1.64 + 1.65 + <property name="tabs" readonly="true"> 1.66 + <getter> 1.67 + <![CDATA[ 1.68 + return this.getElementsByTagNameNS( 1.69 + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", 1.70 + "tabs").item(0); 1.71 + ]]> 1.72 + </getter> 1.73 + </property> 1.74 + 1.75 + <property name="tabpanels" readonly="true"> 1.76 + <getter> 1.77 + <![CDATA[ 1.78 + return this.getElementsByTagNameNS( 1.79 + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", 1.80 + "tabpanels").item(0); 1.81 + ]]> 1.82 + </getter> 1.83 + </property> 1.84 + 1.85 + <property name="selectedIndex"> 1.86 + <getter> 1.87 + <![CDATA[ 1.88 + var tabs = this.tabs; 1.89 + return tabs ? tabs.selectedIndex : -1; 1.90 + ]]> 1.91 + </getter> 1.92 + 1.93 + <setter> 1.94 + <![CDATA[ 1.95 + var tabs = this.tabs; 1.96 + if (tabs) 1.97 + tabs.selectedIndex = val; 1.98 + this.setAttribute("selectedIndex", val); 1.99 + return val; 1.100 + ]]> 1.101 + </setter> 1.102 + </property> 1.103 + 1.104 + <property name="selectedTab"> 1.105 + <getter> 1.106 + <![CDATA[ 1.107 + var tabs = this.tabs; 1.108 + return tabs && tabs.selectedItem; 1.109 + ]]> 1.110 + </getter> 1.111 + 1.112 + <setter> 1.113 + <![CDATA[ 1.114 + if (val) { 1.115 + var tabs = this.tabs; 1.116 + if (tabs) 1.117 + tabs.selectedItem = val; 1.118 + } 1.119 + return val; 1.120 + ]]> 1.121 + </setter> 1.122 + </property> 1.123 + 1.124 + <property name="selectedPanel"> 1.125 + <getter> 1.126 + <![CDATA[ 1.127 + var tabpanels = this.tabpanels; 1.128 + return tabpanels && tabpanels.selectedPanel; 1.129 + ]]> 1.130 + </getter> 1.131 + 1.132 + <setter> 1.133 + <![CDATA[ 1.134 + if (val) { 1.135 + var tabpanels = this.tabpanels; 1.136 + if (tabpanels) 1.137 + tabpanels.selectedPanel = val; 1.138 + } 1.139 + return val; 1.140 + ]]> 1.141 + </setter> 1.142 + </property> 1.143 + 1.144 + <method name="handleEvent"> 1.145 + <parameter name="event"/> 1.146 + <body> 1.147 + <![CDATA[ 1.148 + if (!event.isTrusted) { 1.149 + // Don't let untrusted events mess with tabs. 1.150 + return; 1.151 + } 1.152 + 1.153 + switch (event.keyCode) { 1.154 + case event.DOM_VK_TAB: 1.155 + if (event.ctrlKey && !event.altKey && !event.metaKey) 1.156 + if (this.tabs && this.handleCtrlTab) { 1.157 + this.tabs.advanceSelectedTab(event.shiftKey ? -1 : 1, true); 1.158 + event.stopPropagation(); 1.159 + event.preventDefault(); 1.160 + } 1.161 + break; 1.162 + case event.DOM_VK_PAGE_UP: 1.163 + if (event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) 1.164 + if (this.tabs && this.handleCtrlPageUpDown) { 1.165 + this.tabs.advanceSelectedTab(-1, true); 1.166 + event.stopPropagation(); 1.167 + event.preventDefault(); 1.168 + } 1.169 + break; 1.170 + case event.DOM_VK_PAGE_DOWN: 1.171 + if (event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey) 1.172 + if (this.tabs && this.handleCtrlPageUpDown) { 1.173 + this.tabs.advanceSelectedTab(1, true); 1.174 + event.stopPropagation(); 1.175 + event.preventDefault(); 1.176 + } 1.177 + break; 1.178 + case event.DOM_VK_LEFT: 1.179 + if (event.metaKey && event.altKey && !event.shiftKey && !event.ctrlKey) 1.180 + if (this.tabs && this._handleMetaAltArrows) { 1.181 + var offset = window.getComputedStyle(this, "") 1.182 + .direction == "ltr" ? -1 : 1; 1.183 + this.tabs.advanceSelectedTab(offset, true); 1.184 + event.stopPropagation(); 1.185 + event.preventDefault(); 1.186 + } 1.187 + break; 1.188 + case event.DOM_VK_RIGHT: 1.189 + if (event.metaKey && event.altKey && !event.shiftKey && !event.ctrlKey) 1.190 + if (this.tabs && this._handleMetaAltArrows) { 1.191 + var offset = window.getComputedStyle(this, "") 1.192 + .direction == "ltr" ? 1 : -1; 1.193 + this.tabs.advanceSelectedTab(offset, true); 1.194 + event.stopPropagation(); 1.195 + event.preventDefault(); 1.196 + } 1.197 + break; 1.198 + } 1.199 + ]]> 1.200 + </body> 1.201 + </method> 1.202 + 1.203 + <field name="_eventNode">this</field> 1.204 + 1.205 + <property name="eventNode" onget="return this._eventNode;"> 1.206 + <setter> 1.207 + <![CDATA[ 1.208 + if (val != this._eventNode) { 1.209 + val.addEventListener("keypress", this, false); 1.210 + this._eventNode.removeEventListener("keypress", this, false); 1.211 + this._eventNode = val; 1.212 + } 1.213 + return val; 1.214 + ]]> 1.215 + </setter> 1.216 + </property> 1.217 + 1.218 + <constructor> 1.219 + switch (this.getAttribute("eventnode")) { 1.220 + case "parent": this._eventNode = this.parentNode; break; 1.221 + case "window": this._eventNode = window; break; 1.222 + case "document": this._eventNode = document; break; 1.223 + } 1.224 + this._eventNode.addEventListener("keypress", this, false); 1.225 + </constructor> 1.226 + 1.227 + <destructor> 1.228 + this._eventNode.removeEventListener("keypress", this, false); 1.229 + </destructor> 1.230 + </implementation> 1.231 + </binding> 1.232 + 1.233 + <binding id="tabs" role="xul:tabs" 1.234 + extends="chrome://global/content/bindings/general.xml#basecontrol"> 1.235 + <resources> 1.236 + <stylesheet src="chrome://global/skin/tabbox.css"/> 1.237 + </resources> 1.238 + 1.239 + <content> 1.240 + <xul:spacer class="tabs-left"/> 1.241 + <children/> 1.242 + <xul:spacer class="tabs-right" flex="1"/> 1.243 + </content> 1.244 + 1.245 + <implementation implements="nsIDOMXULSelectControlElement, nsIDOMXULRelatedElement"> 1.246 + <constructor> 1.247 + <![CDATA[ 1.248 + // first and last tabs need to be able to have unique styles 1.249 + // and also need to select first tab on startup. 1.250 + if (this.firstChild) 1.251 + this.firstChild.setAttribute("first-tab", "true"); 1.252 + if (this.lastChild) 1.253 + this.lastChild.setAttribute("last-tab", "true"); 1.254 + 1.255 + if (!this.hasAttribute("orient")) 1.256 + this.setAttribute("orient", "horizontal"); 1.257 + 1.258 + if (this.tabbox && this.tabbox.hasAttribute("selectedIndex")) { 1.259 + let selectedIndex = parseInt(this.tabbox.getAttribute("selectedIndex")); 1.260 + this.selectedIndex = selectedIndex > 0 ? selectedIndex : 0; 1.261 + return; 1.262 + } 1.263 + 1.264 + var children = this.childNodes; 1.265 + var length = children.length; 1.266 + for (var i = 0; i < length; i++) { 1.267 + if (children[i].getAttribute("selected") == "true") { 1.268 + this.selectedIndex = i; 1.269 + return; 1.270 + } 1.271 + } 1.272 + 1.273 + var value = this.value; 1.274 + if (value) 1.275 + this.value = value; 1.276 + else 1.277 + this.selectedIndex = 0; 1.278 + ]]> 1.279 + </constructor> 1.280 + 1.281 + <!-- nsIDOMXULRelatedElement --> 1.282 + <method name="getRelatedElement"> 1.283 + <parameter name="aTabElm"/> 1.284 + <body> 1.285 + <![CDATA[ 1.286 + if (!aTabElm) 1.287 + return null; 1.288 + 1.289 + let tabboxElm = this.tabbox; 1.290 + if (!tabboxElm) 1.291 + return null; 1.292 + 1.293 + let tabpanelsElm = tabboxElm.tabpanels; 1.294 + if (!tabpanelsElm) 1.295 + return null; 1.296 + 1.297 + // Get linked tab panel by 'linkedpanel' attribute on the given tab 1.298 + // element. 1.299 + let linkedPanelElm = null; 1.300 + 1.301 + let linkedPanelId = aTabElm.linkedPanel; 1.302 + if (linkedPanelId) { 1.303 + let ownerDoc = this.ownerDocument; 1.304 + 1.305 + // XXX bug 565858: if XUL tab element is anonymous element then 1.306 + // suppose linked tab panel is hosted within the same XBL binding 1.307 + // and search it by ID attribute inside an anonymous content of 1.308 + // the binding. This is not robust assumption since tab elements may 1.309 + // live outside a tabbox element so that for example tab elements 1.310 + // can be explicit content but tab panels can be anonymous. 1.311 + 1.312 + let bindingParent = ownerDoc.getBindingParent(aTabElm); 1.313 + if (bindingParent) 1.314 + return ownerDoc.getAnonymousElementByAttribute(bindingParent, 1.315 + "id", 1.316 + linkedPanelId); 1.317 + 1.318 + return ownerDoc.getElementById(linkedPanelId); 1.319 + } 1.320 + 1.321 + // otherwise linked tabpanel element has the same index as the given 1.322 + // tab element. 1.323 + let tabElmIdx = this.getIndexOfItem(aTabElm); 1.324 + return tabpanelsElm.childNodes[tabElmIdx]; 1.325 + ]]> 1.326 + </body> 1.327 + </method> 1.328 + 1.329 + <!-- nsIDOMXULSelectControlElement --> 1.330 + <property name="itemCount" readonly="true" 1.331 + onget="return this.childNodes.length"/> 1.332 + 1.333 + <property name="value" onget="return this.getAttribute('value');"> 1.334 + <setter> 1.335 + <![CDATA[ 1.336 + this.setAttribute("value", val); 1.337 + var children = this.childNodes; 1.338 + for (var c = children.length - 1; c >= 0; c--) { 1.339 + if (children[c].value == val) { 1.340 + this.selectedIndex = c; 1.341 + break; 1.342 + } 1.343 + } 1.344 + return val; 1.345 + ]]> 1.346 + </setter> 1.347 + </property> 1.348 + 1.349 + <field name="tabbox" readonly="true"><![CDATA[ 1.350 + var parent = this.parentNode; 1.351 + while (parent) { 1.352 + if (parent.localName == "tabbox") 1.353 + break; 1.354 + parent = parent.parentNode; 1.355 + } 1.356 + parent; 1.357 + ]]></field> 1.358 + 1.359 + <!-- _tabbox is deprecated, it exists only for backwards compatibility. --> 1.360 + <field name="_tabbox" readonly="true"><![CDATA[ 1.361 + this.tabbox; 1.362 + ]]></field> 1.363 + 1.364 + <property name="selectedIndex"> 1.365 + <getter> 1.366 + <![CDATA[ 1.367 + const tabs = this.childNodes; 1.368 + for (var i = 0; i < tabs.length; i++) { 1.369 + if (tabs[i].selected) 1.370 + return i; 1.371 + } 1.372 + return -1; 1.373 + ]]> 1.374 + </getter> 1.375 + 1.376 + <setter> 1.377 + <![CDATA[ 1.378 + var tab = this.getItemAtIndex(val); 1.379 + if (tab) { 1.380 + var alreadySelected = tab.selected; 1.381 + 1.382 + Array.forEach(this.childNodes, function (aTab) { 1.383 + if (aTab.selected && aTab != tab) 1.384 + aTab._selected = false; 1.385 + }); 1.386 + tab._selected = true; 1.387 + 1.388 + this.setAttribute("value", tab.value); 1.389 + 1.390 + let linkedPanel = this.getRelatedElement(tab); 1.391 + if (linkedPanel) { 1.392 + this.tabbox.setAttribute("selectedIndex", val); 1.393 + 1.394 + // This will cause an onselect event to fire for the tabpanel 1.395 + // element. 1.396 + this.tabbox.tabpanels.selectedPanel = linkedPanel; 1.397 + } 1.398 + 1.399 + if (!alreadySelected) { 1.400 + // Fire an onselect event for the tabs element. 1.401 + var event = document.createEvent('Events'); 1.402 + event.initEvent('select', true, true); 1.403 + this.dispatchEvent(event); 1.404 + } 1.405 + } 1.406 + return val; 1.407 + ]]> 1.408 + </setter> 1.409 + </property> 1.410 + 1.411 + <property name="selectedItem"> 1.412 + <getter> 1.413 + <![CDATA[ 1.414 + const tabs = this.childNodes; 1.415 + for (var i = 0; i < tabs.length; i++) { 1.416 + if (tabs[i].selected) 1.417 + return tabs[i]; 1.418 + } 1.419 + return null; 1.420 + ]]> 1.421 + </getter> 1.422 + 1.423 + <setter> 1.424 + <![CDATA[ 1.425 + if (val && !val.selected) 1.426 + // The selectedIndex setter ignores invalid values 1.427 + // such as -1 if |val| isn't one of our child nodes. 1.428 + this.selectedIndex = this.getIndexOfItem(val); 1.429 + return val; 1.430 + ]]> 1.431 + </setter> 1.432 + </property> 1.433 + 1.434 + <method name="getIndexOfItem"> 1.435 + <parameter name="item"/> 1.436 + <body> 1.437 + <![CDATA[ 1.438 + return Array.indexOf(this.childNodes, item); 1.439 + ]]> 1.440 + </body> 1.441 + </method> 1.442 + 1.443 + <method name="getItemAtIndex"> 1.444 + <parameter name="index"/> 1.445 + <body> 1.446 + <![CDATA[ 1.447 + return this.childNodes.item(index); 1.448 + ]]> 1.449 + </body> 1.450 + </method> 1.451 + 1.452 + <method name="_selectNewTab"> 1.453 + <parameter name="aNewTab"/> 1.454 + <parameter name="aFallbackDir"/> 1.455 + <parameter name="aWrap"/> 1.456 + <body> 1.457 + <![CDATA[ 1.458 + var requestedTab = aNewTab; 1.459 + while (aNewTab.hidden || aNewTab.disabled || !this._canAdvanceToTab(aNewTab)) { 1.460 + aNewTab = aFallbackDir == -1 ? aNewTab.previousSibling : aNewTab.nextSibling; 1.461 + if (!aNewTab && aWrap) 1.462 + aNewTab = aFallbackDir == -1 ? this.childNodes[this.childNodes.length - 1] : 1.463 + this.childNodes[0]; 1.464 + if (!aNewTab || aNewTab == requestedTab) 1.465 + return; 1.466 + } 1.467 + 1.468 + var isTabFocused = false; 1.469 + try { 1.470 + isTabFocused = 1.471 + (document.commandDispatcher.focusedElement == this.selectedItem); 1.472 + } catch (e) {} 1.473 + this.selectedItem = aNewTab; 1.474 + if (isTabFocused) { 1.475 + aNewTab.focus(); 1.476 + } 1.477 + else if (this.getAttribute("setfocus") != "false") { 1.478 + let selectedPanel = this.tabbox.selectedPanel; 1.479 + document.commandDispatcher.advanceFocusIntoSubtree(selectedPanel); 1.480 + 1.481 + // Make sure that the focus doesn't move outside the tabbox 1.482 + if (this.tabbox) { 1.483 + try { 1.484 + let el = document.commandDispatcher.focusedElement; 1.485 + while (el && el != this.tabbox.tabpanels) { 1.486 + if (el == this.tabbox || el == selectedPanel) 1.487 + return; 1.488 + el = el.parentNode; 1.489 + } 1.490 + aNewTab.focus(); 1.491 + } catch(e) { 1.492 + } 1.493 + } 1.494 + } 1.495 + ]]> 1.496 + </body> 1.497 + </method> 1.498 + 1.499 + <method name="_canAdvanceToTab"> 1.500 + <parameter name="aTab"/> 1.501 + <body> 1.502 + <![CDATA[ 1.503 + return true; 1.504 + ]]> 1.505 + </body> 1.506 + </method> 1.507 + 1.508 + <method name="advanceSelectedTab"> 1.509 + <parameter name="aDir"/> 1.510 + <parameter name="aWrap"/> 1.511 + <body> 1.512 + <![CDATA[ 1.513 + var startTab = this.selectedItem; 1.514 + var next = startTab[aDir == -1 ? "previousSibling" : "nextSibling"]; 1.515 + if (!next && aWrap) { 1.516 + next = aDir == -1 ? this.childNodes[this.childNodes.length - 1] : 1.517 + this.childNodes[0]; 1.518 + } 1.519 + if (next && next != startTab) { 1.520 + this._selectNewTab(next, aDir, aWrap); 1.521 + } 1.522 + ]]> 1.523 + </body> 1.524 + </method> 1.525 + 1.526 + <method name="appendItem"> 1.527 + <parameter name="label"/> 1.528 + <parameter name="value"/> 1.529 + <body> 1.530 + <![CDATA[ 1.531 + var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.532 + var tab = document.createElementNS(XULNS, "tab"); 1.533 + tab.setAttribute("label", label); 1.534 + tab.setAttribute("value", value); 1.535 + this.appendChild(tab); 1.536 + return tab; 1.537 + ]]> 1.538 + </body> 1.539 + </method> 1.540 + 1.541 + <method name="insertItemAt"> 1.542 + <parameter name="index"/> 1.543 + <parameter name="label"/> 1.544 + <parameter name="value"/> 1.545 + <body> 1.546 + <![CDATA[ 1.547 + var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.548 + var tab = document.createElementNS(XULNS, "tab"); 1.549 + tab.setAttribute("label", label); 1.550 + tab.setAttribute("value", value); 1.551 + var before = this.getItemAtIndex(index); 1.552 + if (before) 1.553 + this.insertBefore(tab, before); 1.554 + else 1.555 + this.appendChild(tab); 1.556 + return tab; 1.557 + ]]> 1.558 + </body> 1.559 + </method> 1.560 + 1.561 + <method name="removeItemAt"> 1.562 + <parameter name="index"/> 1.563 + <body> 1.564 + <![CDATA[ 1.565 + var remove = this.getItemAtIndex(index); 1.566 + if (remove) 1.567 + this.removeChild(remove); 1.568 + return remove; 1.569 + ]]> 1.570 + </body> 1.571 + </method> 1.572 + </implementation> 1.573 + 1.574 +#ifdef MOZ_WIDGET_GTK 1.575 + <handlers> 1.576 + <handler event="DOMMouseScroll"> 1.577 + <![CDATA[ 1.578 + if (event.detail > 0) 1.579 + this.advanceSelectedTab(1, false); 1.580 + else 1.581 + this.advanceSelectedTab(-1, false); 1.582 + 1.583 + event.stopPropagation(); 1.584 + ]]> 1.585 + </handler> 1.586 + </handlers> 1.587 +#endif 1.588 + </binding> 1.589 + 1.590 + <binding id="tabpanels" role="xul:tabpanels" 1.591 + extends="chrome://global/content/bindings/tabbox.xml#tab-base"> 1.592 + <implementation implements="nsIDOMXULRelatedElement"> 1.593 + <!-- nsIDOMXULRelatedElement --> 1.594 + <method name="getRelatedElement"> 1.595 + <parameter name="aTabPanelElm"/> 1.596 + <body> 1.597 + <![CDATA[ 1.598 + if (!aTabPanelElm) 1.599 + return null; 1.600 + 1.601 + let tabboxElm = this.tabbox; 1.602 + if (!tabboxElm) 1.603 + return null; 1.604 + 1.605 + let tabsElm = tabboxElm.tabs; 1.606 + if (!tabsElm) 1.607 + return null; 1.608 + 1.609 + // Return tab element having 'linkedpanel' attribute equal to the id 1.610 + // of the tab panel or the same index as the tab panel element. 1.611 + let tabpanelIdx = Array.indexOf(this.childNodes, aTabPanelElm); 1.612 + if (tabpanelIdx == -1) 1.613 + return null; 1.614 + 1.615 + let tabElms = tabsElm.childNodes; 1.616 + let tabElmFromIndex = tabElms[tabpanelIdx]; 1.617 + 1.618 + let tabpanelId = aTabPanelElm.id; 1.619 + if (tabpanelId) { 1.620 + for (let idx = 0; idx < tabElms.length; idx++) { 1.621 + var tabElm = tabElms[idx]; 1.622 + if (tabElm.linkedPanel == tabpanelId) 1.623 + return tabElm; 1.624 + } 1.625 + } 1.626 + 1.627 + return tabElmFromIndex; 1.628 + ]]> 1.629 + </body> 1.630 + </method> 1.631 + 1.632 + <!-- public --> 1.633 + <field name="tabbox" readonly="true"><![CDATA[ 1.634 + var parent = this.parentNode; 1.635 + while (parent) { 1.636 + if (parent.localName == "tabbox") 1.637 + break; 1.638 + parent = parent.parentNode; 1.639 + } 1.640 + parent; 1.641 + ]]></field> 1.642 + 1.643 + <field name="_selectedPanel">this.childNodes.item(this.selectedIndex)</field> 1.644 + 1.645 + <property name="selectedIndex"> 1.646 + <getter> 1.647 + <![CDATA[ 1.648 + var indexStr = this.getAttribute("selectedIndex"); 1.649 + return indexStr ? parseInt(indexStr) : -1; 1.650 + ]]> 1.651 + </getter> 1.652 + 1.653 + <setter> 1.654 + <![CDATA[ 1.655 + if (val < 0 || val >= this.childNodes.length) 1.656 + return val; 1.657 + var panel = this._selectedPanel; 1.658 + this._selectedPanel = this.childNodes[val]; 1.659 + this.setAttribute("selectedIndex", val); 1.660 + if (this._selectedPanel != panel) { 1.661 + var event = document.createEvent("Events"); 1.662 + event.initEvent("select", true, true); 1.663 + this.dispatchEvent(event); 1.664 + } 1.665 + return val; 1.666 + ]]> 1.667 + </setter> 1.668 + </property> 1.669 + 1.670 + <property name="selectedPanel"> 1.671 + <getter> 1.672 + <![CDATA[ 1.673 + return this._selectedPanel; 1.674 + ]]> 1.675 + </getter> 1.676 + 1.677 + <setter> 1.678 + <![CDATA[ 1.679 + var selectedIndex = -1; 1.680 + for (var panel = val; panel != null; panel = panel.previousSibling) 1.681 + ++selectedIndex; 1.682 + this.selectedIndex = selectedIndex; 1.683 + return val; 1.684 + ]]> 1.685 + </setter> 1.686 + </property> 1.687 + </implementation> 1.688 + </binding> 1.689 + 1.690 + <binding id="tab" display="xul:button" role="xul:tab" 1.691 + extends="chrome://global/content/bindings/general.xml#control-item"> 1.692 + <resources> 1.693 + <stylesheet src="chrome://global/skin/tabbox.css"/> 1.694 + </resources> 1.695 + 1.696 + <content> 1.697 + <xul:hbox class="tab-middle box-inherit" xbl:inherits="align,dir,pack,orient,selected" flex="1"> 1.698 + <xul:image class="tab-icon" 1.699 + xbl:inherits="validate,src=image" 1.700 + role="presentation"/> 1.701 + <xul:label class="tab-text" 1.702 + xbl:inherits="value=label,accesskey,crop,disabled" 1.703 + flex="1" 1.704 + role="presentation"/> 1.705 + </xul:hbox> 1.706 + </content> 1.707 + 1.708 + <implementation implements="nsIDOMXULSelectControlItemElement"> 1.709 + <property name="control" readonly="true"> 1.710 + <getter> 1.711 + <![CDATA[ 1.712 + var parent = this.parentNode; 1.713 + if (parent instanceof Components.interfaces.nsIDOMXULSelectControlElement) 1.714 + return parent; 1.715 + return null; 1.716 + ]]> 1.717 + </getter> 1.718 + </property> 1.719 + 1.720 + <property name="selected" readonly="true" 1.721 + onget="return this.getAttribute('selected') == 'true';"/> 1.722 + 1.723 + <property name="_selected"> 1.724 + <setter> 1.725 + <![CDATA[ 1.726 + if (val) 1.727 + this.setAttribute("selected", "true"); 1.728 + else 1.729 + this.removeAttribute("selected"); 1.730 + 1.731 + if (this.previousSibling && this.previousSibling.localName == "tab") { 1.732 + if (val) 1.733 + this.previousSibling.setAttribute("beforeselected", "true"); 1.734 + else 1.735 + this.previousSibling.removeAttribute("beforeselected"); 1.736 + this.removeAttribute("first-tab"); 1.737 + } 1.738 + else 1.739 + this.setAttribute("first-tab", "true"); 1.740 + 1.741 + if (this.nextSibling && this.nextSibling.localName == "tab") { 1.742 + if (val) 1.743 + this.nextSibling.setAttribute("afterselected", "true"); 1.744 + else 1.745 + this.nextSibling.removeAttribute("afterselected"); 1.746 + this.removeAttribute("last-tab"); 1.747 + } 1.748 + else 1.749 + this.setAttribute("last-tab", "true"); 1.750 + return val; 1.751 + ]]> 1.752 + </setter> 1.753 + </property> 1.754 + 1.755 + <property name="linkedPanel" onget="return this.getAttribute('linkedpanel')" 1.756 + onset="this.setAttribute('linkedpanel', val); return val;"/> 1.757 + 1.758 + <field name="arrowKeysShouldWrap" readonly="true"> 1.759 +#ifdef XP_MACOSX 1.760 + true 1.761 +#else 1.762 + false 1.763 +#endif 1.764 + </field> 1.765 + <field name="TelemetryStopwatch" readonly="true"> 1.766 + let tmp = {}; 1.767 + Cu.import("resource://gre/modules/TelemetryStopwatch.jsm", tmp); 1.768 + tmp.TelemetryStopwatch; 1.769 + </field> 1.770 + </implementation> 1.771 + 1.772 + <handlers> 1.773 + <handler event="mousedown" button="0"> 1.774 + <![CDATA[ 1.775 + if (this.disabled) 1.776 + return; 1.777 + 1.778 + if (this != this.parentNode.selectedItem) { // Not selected yet 1.779 + let stopwatchid = this.parentNode.getAttribute("stopwatchid"); 1.780 + if (stopwatchid) { 1.781 + this.TelemetryStopwatch.start(stopwatchid); 1.782 + } 1.783 + 1.784 + // Call this before setting the 'ignorefocus' attribute because this 1.785 + // will pass on focus if the formerly selected tab was focused as well. 1.786 + this.parentNode._selectNewTab(this); 1.787 + 1.788 + var isTabFocused = false; 1.789 + try { 1.790 + isTabFocused = (document.commandDispatcher.focusedElement == this); 1.791 + } catch (e) {} 1.792 + 1.793 + // Set '-moz-user-focus' to 'ignore' so that PostHandleEvent() can't 1.794 + // focus the tab; we only want tabs to be focusable by the mouse if 1.795 + // they are already focused. After a short timeout we'll reset 1.796 + // '-moz-user-focus' so that tabs can be focused by keyboard again. 1.797 + if (!isTabFocused) { 1.798 + this.setAttribute("ignorefocus", "true"); 1.799 + setTimeout(function (tab) tab.removeAttribute("ignorefocus"), 0, this); 1.800 + } 1.801 + 1.802 + if (stopwatchid) { 1.803 + this.TelemetryStopwatch.finish(stopwatchid); 1.804 + } 1.805 + } 1.806 + // Otherwise this tab is already selected and we will fall 1.807 + // through to mousedown behavior which sets focus on the current tab, 1.808 + // Only a click on an already selected tab should focus the tab itself. 1.809 + ]]> 1.810 + </handler> 1.811 + 1.812 + <handler event="keypress" keycode="VK_LEFT"> 1.813 + <![CDATA[ 1.814 + var direction = window.getComputedStyle(this.parentNode, null).direction; 1.815 + this.parentNode.advanceSelectedTab(direction == 'ltr' ? -1 : 1, this.arrowKeysShouldWrap); 1.816 + ]]> 1.817 + </handler> 1.818 + 1.819 + <handler event="keypress" keycode="VK_RIGHT"> 1.820 + <![CDATA[ 1.821 + var direction = window.getComputedStyle(this.parentNode, null).direction; 1.822 + this.parentNode.advanceSelectedTab(direction == 'ltr' ? 1 : -1, this.arrowKeysShouldWrap); 1.823 + ]]> 1.824 + </handler> 1.825 + 1.826 + <handler event="keypress" keycode="VK_UP"> 1.827 + <![CDATA[ 1.828 + this.parentNode.advanceSelectedTab(-1, this.arrowKeysShouldWrap); 1.829 + ]]> 1.830 + </handler> 1.831 + 1.832 + <handler event="keypress" keycode="VK_DOWN"> 1.833 + <![CDATA[ 1.834 + this.parentNode.advanceSelectedTab(1, this.arrowKeysShouldWrap); 1.835 + ]]> 1.836 + </handler> 1.837 + 1.838 + <handler event="keypress" keycode="VK_HOME"> 1.839 + <![CDATA[ 1.840 + this.parentNode._selectNewTab(this.parentNode.childNodes[0]); 1.841 + ]]> 1.842 + </handler> 1.843 + 1.844 + <handler event="keypress" keycode="VK_END"> 1.845 + <![CDATA[ 1.846 + var tabs = this.parentNode.childNodes; 1.847 + this.parentNode._selectNewTab(tabs[tabs.length - 1], -1); 1.848 + ]]> 1.849 + </handler> 1.850 + </handlers> 1.851 + </binding> 1.852 + 1.853 +</bindings> 1.854 +