toolkit/content/widgets/tabbox.xml

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 <?xml version="1.0"?>
michael@0 2 <!-- This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 - License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
michael@0 5
michael@0 6
michael@0 7 <bindings id="tabBindings"
michael@0 8 xmlns="http://www.mozilla.org/xbl"
michael@0 9 xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
michael@0 10 xmlns:xbl="http://www.mozilla.org/xbl">
michael@0 11
michael@0 12 <binding id="tab-base">
michael@0 13 <resources>
michael@0 14 <stylesheet src="chrome://global/skin/tabbox.css"/>
michael@0 15 </resources>
michael@0 16 </binding>
michael@0 17
michael@0 18 <binding id="tabbox"
michael@0 19 extends="chrome://global/content/bindings/tabbox.xml#tab-base">
michael@0 20 <implementation implements="nsIDOMEventListener">
michael@0 21 <property name="handleCtrlTab">
michael@0 22 <setter>
michael@0 23 <![CDATA[
michael@0 24 this.setAttribute("handleCtrlTab", val);
michael@0 25 return val;
michael@0 26 ]]>
michael@0 27 </setter>
michael@0 28 <getter>
michael@0 29 <![CDATA[
michael@0 30 return (this.getAttribute("handleCtrlTab") != "false");
michael@0 31 ]]>
michael@0 32 </getter>
michael@0 33 </property>
michael@0 34
michael@0 35 <property name="handleCtrlPageUpDown">
michael@0 36 <setter>
michael@0 37 <![CDATA[
michael@0 38 this.setAttribute("handleCtrlPageUpDown", val);
michael@0 39 return val;
michael@0 40 ]]>
michael@0 41 </setter>
michael@0 42 <getter>
michael@0 43 <![CDATA[
michael@0 44 return (this.getAttribute("handleCtrlPageUpDown") != "false");
michael@0 45 ]]>
michael@0 46 </getter>
michael@0 47 </property>
michael@0 48
michael@0 49 <field name="_handleMetaAltArrows" readonly="true">
michael@0 50 #ifdef XP_MACOSX
michael@0 51 true
michael@0 52 #else
michael@0 53 false
michael@0 54 #endif
michael@0 55 </field>
michael@0 56
michael@0 57 <!-- _tabs and _tabpanels are deprecated, they exist only for
michael@0 58 backwards compatibility. -->
michael@0 59 <property name="_tabs" readonly="true" onget="return this.tabs;"/>
michael@0 60 <property name="_tabpanels" readonly="true" onget="return this.tabpanels;"/>
michael@0 61
michael@0 62 <property name="tabs" readonly="true">
michael@0 63 <getter>
michael@0 64 <![CDATA[
michael@0 65 return this.getElementsByTagNameNS(
michael@0 66 "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
michael@0 67 "tabs").item(0);
michael@0 68 ]]>
michael@0 69 </getter>
michael@0 70 </property>
michael@0 71
michael@0 72 <property name="tabpanels" readonly="true">
michael@0 73 <getter>
michael@0 74 <![CDATA[
michael@0 75 return this.getElementsByTagNameNS(
michael@0 76 "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul",
michael@0 77 "tabpanels").item(0);
michael@0 78 ]]>
michael@0 79 </getter>
michael@0 80 </property>
michael@0 81
michael@0 82 <property name="selectedIndex">
michael@0 83 <getter>
michael@0 84 <![CDATA[
michael@0 85 var tabs = this.tabs;
michael@0 86 return tabs ? tabs.selectedIndex : -1;
michael@0 87 ]]>
michael@0 88 </getter>
michael@0 89
michael@0 90 <setter>
michael@0 91 <![CDATA[
michael@0 92 var tabs = this.tabs;
michael@0 93 if (tabs)
michael@0 94 tabs.selectedIndex = val;
michael@0 95 this.setAttribute("selectedIndex", val);
michael@0 96 return val;
michael@0 97 ]]>
michael@0 98 </setter>
michael@0 99 </property>
michael@0 100
michael@0 101 <property name="selectedTab">
michael@0 102 <getter>
michael@0 103 <![CDATA[
michael@0 104 var tabs = this.tabs;
michael@0 105 return tabs && tabs.selectedItem;
michael@0 106 ]]>
michael@0 107 </getter>
michael@0 108
michael@0 109 <setter>
michael@0 110 <![CDATA[
michael@0 111 if (val) {
michael@0 112 var tabs = this.tabs;
michael@0 113 if (tabs)
michael@0 114 tabs.selectedItem = val;
michael@0 115 }
michael@0 116 return val;
michael@0 117 ]]>
michael@0 118 </setter>
michael@0 119 </property>
michael@0 120
michael@0 121 <property name="selectedPanel">
michael@0 122 <getter>
michael@0 123 <![CDATA[
michael@0 124 var tabpanels = this.tabpanels;
michael@0 125 return tabpanels && tabpanels.selectedPanel;
michael@0 126 ]]>
michael@0 127 </getter>
michael@0 128
michael@0 129 <setter>
michael@0 130 <![CDATA[
michael@0 131 if (val) {
michael@0 132 var tabpanels = this.tabpanels;
michael@0 133 if (tabpanels)
michael@0 134 tabpanels.selectedPanel = val;
michael@0 135 }
michael@0 136 return val;
michael@0 137 ]]>
michael@0 138 </setter>
michael@0 139 </property>
michael@0 140
michael@0 141 <method name="handleEvent">
michael@0 142 <parameter name="event"/>
michael@0 143 <body>
michael@0 144 <![CDATA[
michael@0 145 if (!event.isTrusted) {
michael@0 146 // Don't let untrusted events mess with tabs.
michael@0 147 return;
michael@0 148 }
michael@0 149
michael@0 150 switch (event.keyCode) {
michael@0 151 case event.DOM_VK_TAB:
michael@0 152 if (event.ctrlKey && !event.altKey && !event.metaKey)
michael@0 153 if (this.tabs && this.handleCtrlTab) {
michael@0 154 this.tabs.advanceSelectedTab(event.shiftKey ? -1 : 1, true);
michael@0 155 event.stopPropagation();
michael@0 156 event.preventDefault();
michael@0 157 }
michael@0 158 break;
michael@0 159 case event.DOM_VK_PAGE_UP:
michael@0 160 if (event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey)
michael@0 161 if (this.tabs && this.handleCtrlPageUpDown) {
michael@0 162 this.tabs.advanceSelectedTab(-1, true);
michael@0 163 event.stopPropagation();
michael@0 164 event.preventDefault();
michael@0 165 }
michael@0 166 break;
michael@0 167 case event.DOM_VK_PAGE_DOWN:
michael@0 168 if (event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey)
michael@0 169 if (this.tabs && this.handleCtrlPageUpDown) {
michael@0 170 this.tabs.advanceSelectedTab(1, true);
michael@0 171 event.stopPropagation();
michael@0 172 event.preventDefault();
michael@0 173 }
michael@0 174 break;
michael@0 175 case event.DOM_VK_LEFT:
michael@0 176 if (event.metaKey && event.altKey && !event.shiftKey && !event.ctrlKey)
michael@0 177 if (this.tabs && this._handleMetaAltArrows) {
michael@0 178 var offset = window.getComputedStyle(this, "")
michael@0 179 .direction == "ltr" ? -1 : 1;
michael@0 180 this.tabs.advanceSelectedTab(offset, true);
michael@0 181 event.stopPropagation();
michael@0 182 event.preventDefault();
michael@0 183 }
michael@0 184 break;
michael@0 185 case event.DOM_VK_RIGHT:
michael@0 186 if (event.metaKey && event.altKey && !event.shiftKey && !event.ctrlKey)
michael@0 187 if (this.tabs && this._handleMetaAltArrows) {
michael@0 188 var offset = window.getComputedStyle(this, "")
michael@0 189 .direction == "ltr" ? 1 : -1;
michael@0 190 this.tabs.advanceSelectedTab(offset, true);
michael@0 191 event.stopPropagation();
michael@0 192 event.preventDefault();
michael@0 193 }
michael@0 194 break;
michael@0 195 }
michael@0 196 ]]>
michael@0 197 </body>
michael@0 198 </method>
michael@0 199
michael@0 200 <field name="_eventNode">this</field>
michael@0 201
michael@0 202 <property name="eventNode" onget="return this._eventNode;">
michael@0 203 <setter>
michael@0 204 <![CDATA[
michael@0 205 if (val != this._eventNode) {
michael@0 206 val.addEventListener("keypress", this, false);
michael@0 207 this._eventNode.removeEventListener("keypress", this, false);
michael@0 208 this._eventNode = val;
michael@0 209 }
michael@0 210 return val;
michael@0 211 ]]>
michael@0 212 </setter>
michael@0 213 </property>
michael@0 214
michael@0 215 <constructor>
michael@0 216 switch (this.getAttribute("eventnode")) {
michael@0 217 case "parent": this._eventNode = this.parentNode; break;
michael@0 218 case "window": this._eventNode = window; break;
michael@0 219 case "document": this._eventNode = document; break;
michael@0 220 }
michael@0 221 this._eventNode.addEventListener("keypress", this, false);
michael@0 222 </constructor>
michael@0 223
michael@0 224 <destructor>
michael@0 225 this._eventNode.removeEventListener("keypress", this, false);
michael@0 226 </destructor>
michael@0 227 </implementation>
michael@0 228 </binding>
michael@0 229
michael@0 230 <binding id="tabs" role="xul:tabs"
michael@0 231 extends="chrome://global/content/bindings/general.xml#basecontrol">
michael@0 232 <resources>
michael@0 233 <stylesheet src="chrome://global/skin/tabbox.css"/>
michael@0 234 </resources>
michael@0 235
michael@0 236 <content>
michael@0 237 <xul:spacer class="tabs-left"/>
michael@0 238 <children/>
michael@0 239 <xul:spacer class="tabs-right" flex="1"/>
michael@0 240 </content>
michael@0 241
michael@0 242 <implementation implements="nsIDOMXULSelectControlElement, nsIDOMXULRelatedElement">
michael@0 243 <constructor>
michael@0 244 <![CDATA[
michael@0 245 // first and last tabs need to be able to have unique styles
michael@0 246 // and also need to select first tab on startup.
michael@0 247 if (this.firstChild)
michael@0 248 this.firstChild.setAttribute("first-tab", "true");
michael@0 249 if (this.lastChild)
michael@0 250 this.lastChild.setAttribute("last-tab", "true");
michael@0 251
michael@0 252 if (!this.hasAttribute("orient"))
michael@0 253 this.setAttribute("orient", "horizontal");
michael@0 254
michael@0 255 if (this.tabbox && this.tabbox.hasAttribute("selectedIndex")) {
michael@0 256 let selectedIndex = parseInt(this.tabbox.getAttribute("selectedIndex"));
michael@0 257 this.selectedIndex = selectedIndex > 0 ? selectedIndex : 0;
michael@0 258 return;
michael@0 259 }
michael@0 260
michael@0 261 var children = this.childNodes;
michael@0 262 var length = children.length;
michael@0 263 for (var i = 0; i < length; i++) {
michael@0 264 if (children[i].getAttribute("selected") == "true") {
michael@0 265 this.selectedIndex = i;
michael@0 266 return;
michael@0 267 }
michael@0 268 }
michael@0 269
michael@0 270 var value = this.value;
michael@0 271 if (value)
michael@0 272 this.value = value;
michael@0 273 else
michael@0 274 this.selectedIndex = 0;
michael@0 275 ]]>
michael@0 276 </constructor>
michael@0 277
michael@0 278 <!-- nsIDOMXULRelatedElement -->
michael@0 279 <method name="getRelatedElement">
michael@0 280 <parameter name="aTabElm"/>
michael@0 281 <body>
michael@0 282 <![CDATA[
michael@0 283 if (!aTabElm)
michael@0 284 return null;
michael@0 285
michael@0 286 let tabboxElm = this.tabbox;
michael@0 287 if (!tabboxElm)
michael@0 288 return null;
michael@0 289
michael@0 290 let tabpanelsElm = tabboxElm.tabpanels;
michael@0 291 if (!tabpanelsElm)
michael@0 292 return null;
michael@0 293
michael@0 294 // Get linked tab panel by 'linkedpanel' attribute on the given tab
michael@0 295 // element.
michael@0 296 let linkedPanelElm = null;
michael@0 297
michael@0 298 let linkedPanelId = aTabElm.linkedPanel;
michael@0 299 if (linkedPanelId) {
michael@0 300 let ownerDoc = this.ownerDocument;
michael@0 301
michael@0 302 // XXX bug 565858: if XUL tab element is anonymous element then
michael@0 303 // suppose linked tab panel is hosted within the same XBL binding
michael@0 304 // and search it by ID attribute inside an anonymous content of
michael@0 305 // the binding. This is not robust assumption since tab elements may
michael@0 306 // live outside a tabbox element so that for example tab elements
michael@0 307 // can be explicit content but tab panels can be anonymous.
michael@0 308
michael@0 309 let bindingParent = ownerDoc.getBindingParent(aTabElm);
michael@0 310 if (bindingParent)
michael@0 311 return ownerDoc.getAnonymousElementByAttribute(bindingParent,
michael@0 312 "id",
michael@0 313 linkedPanelId);
michael@0 314
michael@0 315 return ownerDoc.getElementById(linkedPanelId);
michael@0 316 }
michael@0 317
michael@0 318 // otherwise linked tabpanel element has the same index as the given
michael@0 319 // tab element.
michael@0 320 let tabElmIdx = this.getIndexOfItem(aTabElm);
michael@0 321 return tabpanelsElm.childNodes[tabElmIdx];
michael@0 322 ]]>
michael@0 323 </body>
michael@0 324 </method>
michael@0 325
michael@0 326 <!-- nsIDOMXULSelectControlElement -->
michael@0 327 <property name="itemCount" readonly="true"
michael@0 328 onget="return this.childNodes.length"/>
michael@0 329
michael@0 330 <property name="value" onget="return this.getAttribute('value');">
michael@0 331 <setter>
michael@0 332 <![CDATA[
michael@0 333 this.setAttribute("value", val);
michael@0 334 var children = this.childNodes;
michael@0 335 for (var c = children.length - 1; c >= 0; c--) {
michael@0 336 if (children[c].value == val) {
michael@0 337 this.selectedIndex = c;
michael@0 338 break;
michael@0 339 }
michael@0 340 }
michael@0 341 return val;
michael@0 342 ]]>
michael@0 343 </setter>
michael@0 344 </property>
michael@0 345
michael@0 346 <field name="tabbox" readonly="true"><![CDATA[
michael@0 347 var parent = this.parentNode;
michael@0 348 while (parent) {
michael@0 349 if (parent.localName == "tabbox")
michael@0 350 break;
michael@0 351 parent = parent.parentNode;
michael@0 352 }
michael@0 353 parent;
michael@0 354 ]]></field>
michael@0 355
michael@0 356 <!-- _tabbox is deprecated, it exists only for backwards compatibility. -->
michael@0 357 <field name="_tabbox" readonly="true"><![CDATA[
michael@0 358 this.tabbox;
michael@0 359 ]]></field>
michael@0 360
michael@0 361 <property name="selectedIndex">
michael@0 362 <getter>
michael@0 363 <![CDATA[
michael@0 364 const tabs = this.childNodes;
michael@0 365 for (var i = 0; i < tabs.length; i++) {
michael@0 366 if (tabs[i].selected)
michael@0 367 return i;
michael@0 368 }
michael@0 369 return -1;
michael@0 370 ]]>
michael@0 371 </getter>
michael@0 372
michael@0 373 <setter>
michael@0 374 <![CDATA[
michael@0 375 var tab = this.getItemAtIndex(val);
michael@0 376 if (tab) {
michael@0 377 var alreadySelected = tab.selected;
michael@0 378
michael@0 379 Array.forEach(this.childNodes, function (aTab) {
michael@0 380 if (aTab.selected && aTab != tab)
michael@0 381 aTab._selected = false;
michael@0 382 });
michael@0 383 tab._selected = true;
michael@0 384
michael@0 385 this.setAttribute("value", tab.value);
michael@0 386
michael@0 387 let linkedPanel = this.getRelatedElement(tab);
michael@0 388 if (linkedPanel) {
michael@0 389 this.tabbox.setAttribute("selectedIndex", val);
michael@0 390
michael@0 391 // This will cause an onselect event to fire for the tabpanel
michael@0 392 // element.
michael@0 393 this.tabbox.tabpanels.selectedPanel = linkedPanel;
michael@0 394 }
michael@0 395
michael@0 396 if (!alreadySelected) {
michael@0 397 // Fire an onselect event for the tabs element.
michael@0 398 var event = document.createEvent('Events');
michael@0 399 event.initEvent('select', true, true);
michael@0 400 this.dispatchEvent(event);
michael@0 401 }
michael@0 402 }
michael@0 403 return val;
michael@0 404 ]]>
michael@0 405 </setter>
michael@0 406 </property>
michael@0 407
michael@0 408 <property name="selectedItem">
michael@0 409 <getter>
michael@0 410 <![CDATA[
michael@0 411 const tabs = this.childNodes;
michael@0 412 for (var i = 0; i < tabs.length; i++) {
michael@0 413 if (tabs[i].selected)
michael@0 414 return tabs[i];
michael@0 415 }
michael@0 416 return null;
michael@0 417 ]]>
michael@0 418 </getter>
michael@0 419
michael@0 420 <setter>
michael@0 421 <![CDATA[
michael@0 422 if (val && !val.selected)
michael@0 423 // The selectedIndex setter ignores invalid values
michael@0 424 // such as -1 if |val| isn't one of our child nodes.
michael@0 425 this.selectedIndex = this.getIndexOfItem(val);
michael@0 426 return val;
michael@0 427 ]]>
michael@0 428 </setter>
michael@0 429 </property>
michael@0 430
michael@0 431 <method name="getIndexOfItem">
michael@0 432 <parameter name="item"/>
michael@0 433 <body>
michael@0 434 <![CDATA[
michael@0 435 return Array.indexOf(this.childNodes, item);
michael@0 436 ]]>
michael@0 437 </body>
michael@0 438 </method>
michael@0 439
michael@0 440 <method name="getItemAtIndex">
michael@0 441 <parameter name="index"/>
michael@0 442 <body>
michael@0 443 <![CDATA[
michael@0 444 return this.childNodes.item(index);
michael@0 445 ]]>
michael@0 446 </body>
michael@0 447 </method>
michael@0 448
michael@0 449 <method name="_selectNewTab">
michael@0 450 <parameter name="aNewTab"/>
michael@0 451 <parameter name="aFallbackDir"/>
michael@0 452 <parameter name="aWrap"/>
michael@0 453 <body>
michael@0 454 <![CDATA[
michael@0 455 var requestedTab = aNewTab;
michael@0 456 while (aNewTab.hidden || aNewTab.disabled || !this._canAdvanceToTab(aNewTab)) {
michael@0 457 aNewTab = aFallbackDir == -1 ? aNewTab.previousSibling : aNewTab.nextSibling;
michael@0 458 if (!aNewTab && aWrap)
michael@0 459 aNewTab = aFallbackDir == -1 ? this.childNodes[this.childNodes.length - 1] :
michael@0 460 this.childNodes[0];
michael@0 461 if (!aNewTab || aNewTab == requestedTab)
michael@0 462 return;
michael@0 463 }
michael@0 464
michael@0 465 var isTabFocused = false;
michael@0 466 try {
michael@0 467 isTabFocused =
michael@0 468 (document.commandDispatcher.focusedElement == this.selectedItem);
michael@0 469 } catch (e) {}
michael@0 470 this.selectedItem = aNewTab;
michael@0 471 if (isTabFocused) {
michael@0 472 aNewTab.focus();
michael@0 473 }
michael@0 474 else if (this.getAttribute("setfocus") != "false") {
michael@0 475 let selectedPanel = this.tabbox.selectedPanel;
michael@0 476 document.commandDispatcher.advanceFocusIntoSubtree(selectedPanel);
michael@0 477
michael@0 478 // Make sure that the focus doesn't move outside the tabbox
michael@0 479 if (this.tabbox) {
michael@0 480 try {
michael@0 481 let el = document.commandDispatcher.focusedElement;
michael@0 482 while (el && el != this.tabbox.tabpanels) {
michael@0 483 if (el == this.tabbox || el == selectedPanel)
michael@0 484 return;
michael@0 485 el = el.parentNode;
michael@0 486 }
michael@0 487 aNewTab.focus();
michael@0 488 } catch(e) {
michael@0 489 }
michael@0 490 }
michael@0 491 }
michael@0 492 ]]>
michael@0 493 </body>
michael@0 494 </method>
michael@0 495
michael@0 496 <method name="_canAdvanceToTab">
michael@0 497 <parameter name="aTab"/>
michael@0 498 <body>
michael@0 499 <![CDATA[
michael@0 500 return true;
michael@0 501 ]]>
michael@0 502 </body>
michael@0 503 </method>
michael@0 504
michael@0 505 <method name="advanceSelectedTab">
michael@0 506 <parameter name="aDir"/>
michael@0 507 <parameter name="aWrap"/>
michael@0 508 <body>
michael@0 509 <![CDATA[
michael@0 510 var startTab = this.selectedItem;
michael@0 511 var next = startTab[aDir == -1 ? "previousSibling" : "nextSibling"];
michael@0 512 if (!next && aWrap) {
michael@0 513 next = aDir == -1 ? this.childNodes[this.childNodes.length - 1] :
michael@0 514 this.childNodes[0];
michael@0 515 }
michael@0 516 if (next && next != startTab) {
michael@0 517 this._selectNewTab(next, aDir, aWrap);
michael@0 518 }
michael@0 519 ]]>
michael@0 520 </body>
michael@0 521 </method>
michael@0 522
michael@0 523 <method name="appendItem">
michael@0 524 <parameter name="label"/>
michael@0 525 <parameter name="value"/>
michael@0 526 <body>
michael@0 527 <![CDATA[
michael@0 528 var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
michael@0 529 var tab = document.createElementNS(XULNS, "tab");
michael@0 530 tab.setAttribute("label", label);
michael@0 531 tab.setAttribute("value", value);
michael@0 532 this.appendChild(tab);
michael@0 533 return tab;
michael@0 534 ]]>
michael@0 535 </body>
michael@0 536 </method>
michael@0 537
michael@0 538 <method name="insertItemAt">
michael@0 539 <parameter name="index"/>
michael@0 540 <parameter name="label"/>
michael@0 541 <parameter name="value"/>
michael@0 542 <body>
michael@0 543 <![CDATA[
michael@0 544 var XULNS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
michael@0 545 var tab = document.createElementNS(XULNS, "tab");
michael@0 546 tab.setAttribute("label", label);
michael@0 547 tab.setAttribute("value", value);
michael@0 548 var before = this.getItemAtIndex(index);
michael@0 549 if (before)
michael@0 550 this.insertBefore(tab, before);
michael@0 551 else
michael@0 552 this.appendChild(tab);
michael@0 553 return tab;
michael@0 554 ]]>
michael@0 555 </body>
michael@0 556 </method>
michael@0 557
michael@0 558 <method name="removeItemAt">
michael@0 559 <parameter name="index"/>
michael@0 560 <body>
michael@0 561 <![CDATA[
michael@0 562 var remove = this.getItemAtIndex(index);
michael@0 563 if (remove)
michael@0 564 this.removeChild(remove);
michael@0 565 return remove;
michael@0 566 ]]>
michael@0 567 </body>
michael@0 568 </method>
michael@0 569 </implementation>
michael@0 570
michael@0 571 #ifdef MOZ_WIDGET_GTK
michael@0 572 <handlers>
michael@0 573 <handler event="DOMMouseScroll">
michael@0 574 <![CDATA[
michael@0 575 if (event.detail > 0)
michael@0 576 this.advanceSelectedTab(1, false);
michael@0 577 else
michael@0 578 this.advanceSelectedTab(-1, false);
michael@0 579
michael@0 580 event.stopPropagation();
michael@0 581 ]]>
michael@0 582 </handler>
michael@0 583 </handlers>
michael@0 584 #endif
michael@0 585 </binding>
michael@0 586
michael@0 587 <binding id="tabpanels" role="xul:tabpanels"
michael@0 588 extends="chrome://global/content/bindings/tabbox.xml#tab-base">
michael@0 589 <implementation implements="nsIDOMXULRelatedElement">
michael@0 590 <!-- nsIDOMXULRelatedElement -->
michael@0 591 <method name="getRelatedElement">
michael@0 592 <parameter name="aTabPanelElm"/>
michael@0 593 <body>
michael@0 594 <![CDATA[
michael@0 595 if (!aTabPanelElm)
michael@0 596 return null;
michael@0 597
michael@0 598 let tabboxElm = this.tabbox;
michael@0 599 if (!tabboxElm)
michael@0 600 return null;
michael@0 601
michael@0 602 let tabsElm = tabboxElm.tabs;
michael@0 603 if (!tabsElm)
michael@0 604 return null;
michael@0 605
michael@0 606 // Return tab element having 'linkedpanel' attribute equal to the id
michael@0 607 // of the tab panel or the same index as the tab panel element.
michael@0 608 let tabpanelIdx = Array.indexOf(this.childNodes, aTabPanelElm);
michael@0 609 if (tabpanelIdx == -1)
michael@0 610 return null;
michael@0 611
michael@0 612 let tabElms = tabsElm.childNodes;
michael@0 613 let tabElmFromIndex = tabElms[tabpanelIdx];
michael@0 614
michael@0 615 let tabpanelId = aTabPanelElm.id;
michael@0 616 if (tabpanelId) {
michael@0 617 for (let idx = 0; idx < tabElms.length; idx++) {
michael@0 618 var tabElm = tabElms[idx];
michael@0 619 if (tabElm.linkedPanel == tabpanelId)
michael@0 620 return tabElm;
michael@0 621 }
michael@0 622 }
michael@0 623
michael@0 624 return tabElmFromIndex;
michael@0 625 ]]>
michael@0 626 </body>
michael@0 627 </method>
michael@0 628
michael@0 629 <!-- public -->
michael@0 630 <field name="tabbox" readonly="true"><![CDATA[
michael@0 631 var parent = this.parentNode;
michael@0 632 while (parent) {
michael@0 633 if (parent.localName == "tabbox")
michael@0 634 break;
michael@0 635 parent = parent.parentNode;
michael@0 636 }
michael@0 637 parent;
michael@0 638 ]]></field>
michael@0 639
michael@0 640 <field name="_selectedPanel">this.childNodes.item(this.selectedIndex)</field>
michael@0 641
michael@0 642 <property name="selectedIndex">
michael@0 643 <getter>
michael@0 644 <![CDATA[
michael@0 645 var indexStr = this.getAttribute("selectedIndex");
michael@0 646 return indexStr ? parseInt(indexStr) : -1;
michael@0 647 ]]>
michael@0 648 </getter>
michael@0 649
michael@0 650 <setter>
michael@0 651 <![CDATA[
michael@0 652 if (val < 0 || val >= this.childNodes.length)
michael@0 653 return val;
michael@0 654 var panel = this._selectedPanel;
michael@0 655 this._selectedPanel = this.childNodes[val];
michael@0 656 this.setAttribute("selectedIndex", val);
michael@0 657 if (this._selectedPanel != panel) {
michael@0 658 var event = document.createEvent("Events");
michael@0 659 event.initEvent("select", true, true);
michael@0 660 this.dispatchEvent(event);
michael@0 661 }
michael@0 662 return val;
michael@0 663 ]]>
michael@0 664 </setter>
michael@0 665 </property>
michael@0 666
michael@0 667 <property name="selectedPanel">
michael@0 668 <getter>
michael@0 669 <![CDATA[
michael@0 670 return this._selectedPanel;
michael@0 671 ]]>
michael@0 672 </getter>
michael@0 673
michael@0 674 <setter>
michael@0 675 <![CDATA[
michael@0 676 var selectedIndex = -1;
michael@0 677 for (var panel = val; panel != null; panel = panel.previousSibling)
michael@0 678 ++selectedIndex;
michael@0 679 this.selectedIndex = selectedIndex;
michael@0 680 return val;
michael@0 681 ]]>
michael@0 682 </setter>
michael@0 683 </property>
michael@0 684 </implementation>
michael@0 685 </binding>
michael@0 686
michael@0 687 <binding id="tab" display="xul:button" role="xul:tab"
michael@0 688 extends="chrome://global/content/bindings/general.xml#control-item">
michael@0 689 <resources>
michael@0 690 <stylesheet src="chrome://global/skin/tabbox.css"/>
michael@0 691 </resources>
michael@0 692
michael@0 693 <content>
michael@0 694 <xul:hbox class="tab-middle box-inherit" xbl:inherits="align,dir,pack,orient,selected" flex="1">
michael@0 695 <xul:image class="tab-icon"
michael@0 696 xbl:inherits="validate,src=image"
michael@0 697 role="presentation"/>
michael@0 698 <xul:label class="tab-text"
michael@0 699 xbl:inherits="value=label,accesskey,crop,disabled"
michael@0 700 flex="1"
michael@0 701 role="presentation"/>
michael@0 702 </xul:hbox>
michael@0 703 </content>
michael@0 704
michael@0 705 <implementation implements="nsIDOMXULSelectControlItemElement">
michael@0 706 <property name="control" readonly="true">
michael@0 707 <getter>
michael@0 708 <![CDATA[
michael@0 709 var parent = this.parentNode;
michael@0 710 if (parent instanceof Components.interfaces.nsIDOMXULSelectControlElement)
michael@0 711 return parent;
michael@0 712 return null;
michael@0 713 ]]>
michael@0 714 </getter>
michael@0 715 </property>
michael@0 716
michael@0 717 <property name="selected" readonly="true"
michael@0 718 onget="return this.getAttribute('selected') == 'true';"/>
michael@0 719
michael@0 720 <property name="_selected">
michael@0 721 <setter>
michael@0 722 <![CDATA[
michael@0 723 if (val)
michael@0 724 this.setAttribute("selected", "true");
michael@0 725 else
michael@0 726 this.removeAttribute("selected");
michael@0 727
michael@0 728 if (this.previousSibling && this.previousSibling.localName == "tab") {
michael@0 729 if (val)
michael@0 730 this.previousSibling.setAttribute("beforeselected", "true");
michael@0 731 else
michael@0 732 this.previousSibling.removeAttribute("beforeselected");
michael@0 733 this.removeAttribute("first-tab");
michael@0 734 }
michael@0 735 else
michael@0 736 this.setAttribute("first-tab", "true");
michael@0 737
michael@0 738 if (this.nextSibling && this.nextSibling.localName == "tab") {
michael@0 739 if (val)
michael@0 740 this.nextSibling.setAttribute("afterselected", "true");
michael@0 741 else
michael@0 742 this.nextSibling.removeAttribute("afterselected");
michael@0 743 this.removeAttribute("last-tab");
michael@0 744 }
michael@0 745 else
michael@0 746 this.setAttribute("last-tab", "true");
michael@0 747 return val;
michael@0 748 ]]>
michael@0 749 </setter>
michael@0 750 </property>
michael@0 751
michael@0 752 <property name="linkedPanel" onget="return this.getAttribute('linkedpanel')"
michael@0 753 onset="this.setAttribute('linkedpanel', val); return val;"/>
michael@0 754
michael@0 755 <field name="arrowKeysShouldWrap" readonly="true">
michael@0 756 #ifdef XP_MACOSX
michael@0 757 true
michael@0 758 #else
michael@0 759 false
michael@0 760 #endif
michael@0 761 </field>
michael@0 762 <field name="TelemetryStopwatch" readonly="true">
michael@0 763 let tmp = {};
michael@0 764 Cu.import("resource://gre/modules/TelemetryStopwatch.jsm", tmp);
michael@0 765 tmp.TelemetryStopwatch;
michael@0 766 </field>
michael@0 767 </implementation>
michael@0 768
michael@0 769 <handlers>
michael@0 770 <handler event="mousedown" button="0">
michael@0 771 <![CDATA[
michael@0 772 if (this.disabled)
michael@0 773 return;
michael@0 774
michael@0 775 if (this != this.parentNode.selectedItem) { // Not selected yet
michael@0 776 let stopwatchid = this.parentNode.getAttribute("stopwatchid");
michael@0 777 if (stopwatchid) {
michael@0 778 this.TelemetryStopwatch.start(stopwatchid);
michael@0 779 }
michael@0 780
michael@0 781 // Call this before setting the 'ignorefocus' attribute because this
michael@0 782 // will pass on focus if the formerly selected tab was focused as well.
michael@0 783 this.parentNode._selectNewTab(this);
michael@0 784
michael@0 785 var isTabFocused = false;
michael@0 786 try {
michael@0 787 isTabFocused = (document.commandDispatcher.focusedElement == this);
michael@0 788 } catch (e) {}
michael@0 789
michael@0 790 // Set '-moz-user-focus' to 'ignore' so that PostHandleEvent() can't
michael@0 791 // focus the tab; we only want tabs to be focusable by the mouse if
michael@0 792 // they are already focused. After a short timeout we'll reset
michael@0 793 // '-moz-user-focus' so that tabs can be focused by keyboard again.
michael@0 794 if (!isTabFocused) {
michael@0 795 this.setAttribute("ignorefocus", "true");
michael@0 796 setTimeout(function (tab) tab.removeAttribute("ignorefocus"), 0, this);
michael@0 797 }
michael@0 798
michael@0 799 if (stopwatchid) {
michael@0 800 this.TelemetryStopwatch.finish(stopwatchid);
michael@0 801 }
michael@0 802 }
michael@0 803 // Otherwise this tab is already selected and we will fall
michael@0 804 // through to mousedown behavior which sets focus on the current tab,
michael@0 805 // Only a click on an already selected tab should focus the tab itself.
michael@0 806 ]]>
michael@0 807 </handler>
michael@0 808
michael@0 809 <handler event="keypress" keycode="VK_LEFT">
michael@0 810 <![CDATA[
michael@0 811 var direction = window.getComputedStyle(this.parentNode, null).direction;
michael@0 812 this.parentNode.advanceSelectedTab(direction == 'ltr' ? -1 : 1, this.arrowKeysShouldWrap);
michael@0 813 ]]>
michael@0 814 </handler>
michael@0 815
michael@0 816 <handler event="keypress" keycode="VK_RIGHT">
michael@0 817 <![CDATA[
michael@0 818 var direction = window.getComputedStyle(this.parentNode, null).direction;
michael@0 819 this.parentNode.advanceSelectedTab(direction == 'ltr' ? 1 : -1, this.arrowKeysShouldWrap);
michael@0 820 ]]>
michael@0 821 </handler>
michael@0 822
michael@0 823 <handler event="keypress" keycode="VK_UP">
michael@0 824 <![CDATA[
michael@0 825 this.parentNode.advanceSelectedTab(-1, this.arrowKeysShouldWrap);
michael@0 826 ]]>
michael@0 827 </handler>
michael@0 828
michael@0 829 <handler event="keypress" keycode="VK_DOWN">
michael@0 830 <![CDATA[
michael@0 831 this.parentNode.advanceSelectedTab(1, this.arrowKeysShouldWrap);
michael@0 832 ]]>
michael@0 833 </handler>
michael@0 834
michael@0 835 <handler event="keypress" keycode="VK_HOME">
michael@0 836 <![CDATA[
michael@0 837 this.parentNode._selectNewTab(this.parentNode.childNodes[0]);
michael@0 838 ]]>
michael@0 839 </handler>
michael@0 840
michael@0 841 <handler event="keypress" keycode="VK_END">
michael@0 842 <![CDATA[
michael@0 843 var tabs = this.parentNode.childNodes;
michael@0 844 this.parentNode._selectNewTab(tabs[tabs.length - 1], -1);
michael@0 845 ]]>
michael@0 846 </handler>
michael@0 847 </handlers>
michael@0 848 </binding>
michael@0 849
michael@0 850 </bindings>
michael@0 851

mercurial