1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/content/widgets/listbox.xml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1145 @@ 1.4 +<?xml version="1.0"?> 1.5 + 1.6 +<!-- This Source Code Form is subject to the terms of the Mozilla Public 1.7 + - License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> 1.9 + 1.10 +<bindings id="listboxBindings" 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 + <!-- 1.16 + Interface binding that is base for bindings of xul:listbox and 1.17 + xul:richlistbox elements. This binding assumes that successors bindings 1.18 + will implement the following properties and methods: 1.19 + 1.20 + /** Return the number of items */ 1.21 + readonly itemCount 1.22 + 1.23 + /** Return index of given item 1.24 + * @param aItem - given item element */ 1.25 + getIndexOfItem(aItem) 1.26 + 1.27 + /** Return item at given index 1.28 + * @param aIndex - index of item element */ 1.29 + getItemAtIndex(aIndex) 1.30 + 1.31 + /** Return count of item elements */ 1.32 + getRowCount() 1.33 + 1.34 + /** Return count of visible item elements */ 1.35 + getNumberOfVisibleRows() 1.36 + 1.37 + /** Return index of first visible item element */ 1.38 + getIndexOfFirstVisibleRow() 1.39 + 1.40 + /** Return true if item of given index is visible 1.41 + * @param aIndex - index of item element 1.42 + * 1.43 + * @note XXX: this method should be removed after bug 364612 is fixed 1.44 + */ 1.45 + ensureIndexIsVisible(aIndex) 1.46 + 1.47 + /** Return true if item element is visible 1.48 + * @param aElement - given item element */ 1.49 + ensureElementIsVisible(aElement) 1.50 + 1.51 + /** Scroll list control to make visible item of given index 1.52 + * @param aIndex - index of item element 1.53 + * 1.54 + * @note XXX: this method should be removed after bug 364612 is fixed 1.55 + */ 1.56 + scrollToIndex(aIndex) 1.57 + 1.58 + /** Create item element and append it to the end of listbox 1.59 + * @param aLabel - label of new item element 1.60 + * @param aValue - value of new item element */ 1.61 + appendItem(aLabel, aValue) 1.62 + 1.63 + /** Create item element and insert it to given position 1.64 + * @param aIndex - insertion position 1.65 + * @param aLabel - label of new item element 1.66 + * @param aValue - value of new item element */ 1.67 + insertItemAt(aIndex, aLabel, aValue) 1.68 + 1.69 + /** Scroll up/down one page 1.70 + * @param aDirection - specifies scrolling direction, should be either -1 or 1 1.71 + * @return the number of elements the selection scrolled 1.72 + */ 1.73 + scrollOnePage(aDirection) 1.74 + 1.75 + /** Fire "select" event */ 1.76 + _fireOnSelect() 1.77 + --> 1.78 + <binding id="listbox-base" role="xul:listbox" 1.79 + extends="chrome://global/content/bindings/general.xml#basecontrol"> 1.80 + 1.81 + <implementation implements="nsIDOMXULMultiSelectControlElement"> 1.82 + <field name="_lastKeyTime">0</field> 1.83 + <field name="_incrementalString">""</field> 1.84 + 1.85 + <!-- nsIDOMXULSelectControlElement --> 1.86 + <property name="selectedItem" 1.87 + onset="this.selectItem(val);"> 1.88 + <getter> 1.89 + <![CDATA[ 1.90 + return this.selectedItems.length > 0 ? this.selectedItems[0] : null; 1.91 + ]]> 1.92 + </getter> 1.93 + </property> 1.94 + 1.95 + <property name="selectedIndex"> 1.96 + <getter> 1.97 + <![CDATA[ 1.98 + if (this.selectedItems.length > 0) 1.99 + return this.getIndexOfItem(this.selectedItems[0]); 1.100 + return -1; 1.101 + ]]> 1.102 + </getter> 1.103 + <setter> 1.104 + <![CDATA[ 1.105 + if (val >= 0) { 1.106 + this.selectItem(this.getItemAtIndex(val)); 1.107 + } else { 1.108 + this.clearSelection(); 1.109 + this.currentItem = null; 1.110 + } 1.111 + ]]> 1.112 + </setter> 1.113 + </property> 1.114 + 1.115 + <property name="value"> 1.116 + <getter> 1.117 + <![CDATA[ 1.118 + if (this.selectedItems.length > 0) 1.119 + return this.selectedItem.value; 1.120 + return null; 1.121 + ]]> 1.122 + </getter> 1.123 + <setter> 1.124 + <![CDATA[ 1.125 + var kids = this.getElementsByAttribute("value", val); 1.126 + if (kids && kids.item(0)) 1.127 + this.selectItem(kids[0]); 1.128 + return val; 1.129 + ]]> 1.130 + </setter> 1.131 + </property> 1.132 + 1.133 + <method name="removeItemAt"> 1.134 + <parameter name="index"/> 1.135 + <body> 1.136 + <![CDATA[ 1.137 + var remove = this.getItemAtIndex(index); 1.138 + if (remove) 1.139 + this.removeChild(remove); 1.140 + return remove; 1.141 + ]]> 1.142 + </body> 1.143 + </method> 1.144 + 1.145 + <!-- nsIDOMXULMultiSelectControlElement --> 1.146 + <property name="selType" 1.147 + onget="return this.getAttribute('seltype');" 1.148 + onset="this.setAttribute('seltype', val); return val;"/> 1.149 + 1.150 + <property name="currentItem" onget="return this._currentItem;"> 1.151 + <setter> 1.152 + if (this._currentItem == val) 1.153 + return val; 1.154 + 1.155 + if (this._currentItem) 1.156 + this._currentItem.current = false; 1.157 + this._currentItem = val; 1.158 + 1.159 + if (val) 1.160 + val.current = true; 1.161 + 1.162 + return val; 1.163 + </setter> 1.164 + </property> 1.165 + 1.166 + <property name="currentIndex"> 1.167 + <getter> 1.168 + return this.currentItem ? this.getIndexOfItem(this.currentItem) : -1; 1.169 + </getter> 1.170 + <setter> 1.171 + <![CDATA[ 1.172 + if (val >= 0) 1.173 + this.currentItem = this.getItemAtIndex(val); 1.174 + else 1.175 + this.currentItem = null; 1.176 + ]]> 1.177 + </setter> 1.178 + </property> 1.179 + 1.180 + <field name="selectedItems">[]</field> 1.181 + 1.182 + <method name="addItemToSelection"> 1.183 + <parameter name="aItem"/> 1.184 + <body> 1.185 + <![CDATA[ 1.186 + if (this.selType != "multiple" && this.selectedCount) 1.187 + return; 1.188 + 1.189 + if (aItem.selected) 1.190 + return; 1.191 + 1.192 + this.selectedItems.push(aItem); 1.193 + aItem.selected = true; 1.194 + 1.195 + this._fireOnSelect(); 1.196 + ]]> 1.197 + </body> 1.198 + </method> 1.199 + 1.200 + <method name="removeItemFromSelection"> 1.201 + <parameter name="aItem"/> 1.202 + <body> 1.203 + <![CDATA[ 1.204 + if (!aItem.selected) 1.205 + return; 1.206 + 1.207 + for (var i = 0; i < this.selectedItems.length; ++i) { 1.208 + if (this.selectedItems[i] == aItem) { 1.209 + this.selectedItems.splice(i, 1); 1.210 + aItem.selected = false; 1.211 + break; 1.212 + } 1.213 + } 1.214 + 1.215 + this._fireOnSelect(); 1.216 + ]]> 1.217 + </body> 1.218 + </method> 1.219 + 1.220 + <method name="toggleItemSelection"> 1.221 + <parameter name="aItem"/> 1.222 + <body> 1.223 + <![CDATA[ 1.224 + if (aItem.selected) 1.225 + this.removeItemFromSelection(aItem); 1.226 + else 1.227 + this.addItemToSelection(aItem); 1.228 + ]]> 1.229 + </body> 1.230 + </method> 1.231 + 1.232 + <method name="selectItem"> 1.233 + <parameter name="aItem"/> 1.234 + <body> 1.235 + <![CDATA[ 1.236 + if (!aItem) 1.237 + return; 1.238 + 1.239 + if (this.selectedItems.length == 1 && this.selectedItems[0] == aItem) 1.240 + return; 1.241 + 1.242 + this._selectionStart = null; 1.243 + 1.244 + var suppress = this._suppressOnSelect; 1.245 + this._suppressOnSelect = true; 1.246 + 1.247 + this.clearSelection(); 1.248 + this.addItemToSelection(aItem); 1.249 + this.currentItem = aItem; 1.250 + 1.251 + this._suppressOnSelect = suppress; 1.252 + this._fireOnSelect(); 1.253 + ]]> 1.254 + </body> 1.255 + </method> 1.256 + 1.257 + <method name="selectItemRange"> 1.258 + <parameter name="aStartItem"/> 1.259 + <parameter name="aEndItem"/> 1.260 + <body> 1.261 + <![CDATA[ 1.262 + if (this.selType != "multiple") 1.263 + return; 1.264 + 1.265 + if (!aStartItem) 1.266 + aStartItem = this._selectionStart ? 1.267 + this._selectionStart : this.currentItem; 1.268 + 1.269 + if (!aStartItem) 1.270 + aStartItem = aEndItem; 1.271 + 1.272 + var suppressSelect = this._suppressOnSelect; 1.273 + this._suppressOnSelect = true; 1.274 + 1.275 + this._selectionStart = aStartItem; 1.276 + 1.277 + var currentItem; 1.278 + var startIndex = this.getIndexOfItem(aStartItem); 1.279 + var endIndex = this.getIndexOfItem(aEndItem); 1.280 + if (endIndex < startIndex) { 1.281 + currentItem = aEndItem; 1.282 + aEndItem = aStartItem; 1.283 + aStartItem = currentItem; 1.284 + } else { 1.285 + currentItem = aStartItem; 1.286 + } 1.287 + 1.288 + while (currentItem) { 1.289 + this.addItemToSelection(currentItem); 1.290 + if (currentItem == aEndItem) { 1.291 + currentItem = this.getNextItem(currentItem, 1); 1.292 + break; 1.293 + } 1.294 + currentItem = this.getNextItem(currentItem, 1); 1.295 + } 1.296 + 1.297 + // Clear around new selection 1.298 + // Don't use clearSelection() because it causes a lot of noise 1.299 + // with respect to selection removed notifications used by the 1.300 + // accessibility API support. 1.301 + var userSelecting = this._userSelecting; 1.302 + this._userSelecting = false; // that's US automatically unselecting 1.303 + for (; currentItem; currentItem = this.getNextItem(currentItem, 1)) 1.304 + this.removeItemFromSelection(currentItem); 1.305 + 1.306 + for (currentItem = this.getItemAtIndex(0); currentItem != aStartItem; 1.307 + currentItem = this.getNextItem(currentItem, 1)) 1.308 + this.removeItemFromSelection(currentItem); 1.309 + this._userSelecting = userSelecting; 1.310 + 1.311 + this._suppressOnSelect = suppressSelect; 1.312 + 1.313 + this._fireOnSelect(); 1.314 + ]]> 1.315 + </body> 1.316 + </method> 1.317 + 1.318 + <method name="selectAll"> 1.319 + <body> 1.320 + this._selectionStart = null; 1.321 + 1.322 + var suppress = this._suppressOnSelect; 1.323 + this._suppressOnSelect = true; 1.324 + 1.325 + var item = this.getItemAtIndex(0); 1.326 + while (item) { 1.327 + this.addItemToSelection(item); 1.328 + item = this.getNextItem(item, 1); 1.329 + } 1.330 + 1.331 + this._suppressOnSelect = suppress; 1.332 + this._fireOnSelect(); 1.333 + </body> 1.334 + </method> 1.335 + 1.336 + <method name="invertSelection"> 1.337 + <body> 1.338 + this._selectionStart = null; 1.339 + 1.340 + var suppress = this._suppressOnSelect; 1.341 + this._suppressOnSelect = true; 1.342 + 1.343 + var item = this.getItemAtIndex(0); 1.344 + while (item) { 1.345 + if (item.selected) 1.346 + this.removeItemFromSelection(item); 1.347 + else 1.348 + this.addItemToSelection(item); 1.349 + item = this.getNextItem(item, 1); 1.350 + } 1.351 + 1.352 + this._suppressOnSelect = suppress; 1.353 + this._fireOnSelect(); 1.354 + </body> 1.355 + </method> 1.356 + 1.357 + <method name="clearSelection"> 1.358 + <body> 1.359 + <![CDATA[ 1.360 + if (this.selectedItems) { 1.361 + for (var i = this.selectedItems.length - 1; i >= 0; --i) 1.362 + this.selectedItems[i].selected = false; 1.363 + 1.364 + this.selectedItems.length = 0; 1.365 + } 1.366 + 1.367 + this._selectionStart = null; 1.368 + this._fireOnSelect(); 1.369 + ]]> 1.370 + </body> 1.371 + </method> 1.372 + 1.373 + <property name="selectedCount" readonly="true" 1.374 + onget="return this.selectedItems.length;"/> 1.375 + 1.376 + <method name="getSelectedItem"> 1.377 + <parameter name="aIndex"/> 1.378 + <body> 1.379 + <![CDATA[ 1.380 + return aIndex < this.selectedItems.length ? 1.381 + this.selectedItems[aIndex] : null; 1.382 + ]]> 1.383 + </body> 1.384 + </method> 1.385 + 1.386 + <!-- Other public members --> 1.387 + <property name="disableKeyNavigation" 1.388 + onget="return this.hasAttribute('disableKeyNavigation');"> 1.389 + <setter> 1.390 + if (val) 1.391 + this.setAttribute("disableKeyNavigation", "true"); 1.392 + else 1.393 + this.removeAttribute("disableKeyNavigation"); 1.394 + return val; 1.395 + </setter> 1.396 + </property> 1.397 + 1.398 + <property name="suppressOnSelect" 1.399 + onget="return this.getAttribute('suppressonselect') == 'true';" 1.400 + onset="this.setAttribute('suppressonselect', val);"/> 1.401 + 1.402 + <property name="_selectDelay" 1.403 + onset="this.setAttribute('_selectDelay', val);" 1.404 + onget="return this.getAttribute('_selectDelay') || 50;"/> 1.405 + 1.406 + <method name="timedSelect"> 1.407 + <parameter name="aItem"/> 1.408 + <parameter name="aTimeout"/> 1.409 + <body> 1.410 + <![CDATA[ 1.411 + var suppress = this._suppressOnSelect; 1.412 + if (aTimeout != -1) 1.413 + this._suppressOnSelect = true; 1.414 + 1.415 + this.selectItem(aItem); 1.416 + 1.417 + this._suppressOnSelect = suppress; 1.418 + 1.419 + if (aTimeout != -1) { 1.420 + if (this._selectTimeout) 1.421 + window.clearTimeout(this._selectTimeout); 1.422 + this._selectTimeout = 1.423 + window.setTimeout(this._selectTimeoutHandler, aTimeout, this); 1.424 + } 1.425 + ]]> 1.426 + </body> 1.427 + </method> 1.428 + 1.429 + <method name="moveByOffset"> 1.430 + <parameter name="aOffset"/> 1.431 + <parameter name="aIsSelecting"/> 1.432 + <parameter name="aIsSelectingRange"/> 1.433 + <body> 1.434 + <![CDATA[ 1.435 + if ((aIsSelectingRange || !aIsSelecting) && 1.436 + this.selType != "multiple") 1.437 + return; 1.438 + 1.439 + var newIndex = this.currentIndex + aOffset; 1.440 + if (newIndex < 0) 1.441 + newIndex = 0; 1.442 + 1.443 + var numItems = this.getRowCount(); 1.444 + if (newIndex > numItems - 1) 1.445 + newIndex = numItems - 1; 1.446 + 1.447 + var newItem = this.getItemAtIndex(newIndex); 1.448 + // make sure that the item is actually visible/selectable 1.449 + if (this._userSelecting && newItem && !this._canUserSelect(newItem)) 1.450 + newItem = 1.451 + aOffset > 0 ? this.getNextItem(newItem, 1) || this.getPreviousItem(newItem, 1) : 1.452 + this.getPreviousItem(newItem, 1) || this.getNextItem(newItem, 1); 1.453 + if (newItem) { 1.454 + this.ensureIndexIsVisible(this.getIndexOfItem(newItem)); 1.455 + if (aIsSelectingRange) 1.456 + this.selectItemRange(null, newItem); 1.457 + else if (aIsSelecting) 1.458 + this.selectItem(newItem); 1.459 + 1.460 + this.currentItem = newItem; 1.461 + } 1.462 + ]]> 1.463 + </body> 1.464 + </method> 1.465 + 1.466 + <!-- Private --> 1.467 + <method name="getNextItem"> 1.468 + <parameter name="aStartItem"/> 1.469 + <parameter name="aDelta"/> 1.470 + <body> 1.471 + <![CDATA[ 1.472 + while (aStartItem) { 1.473 + aStartItem = aStartItem.nextSibling; 1.474 + if (aStartItem && aStartItem instanceof 1.475 + Components.interfaces.nsIDOMXULSelectControlItemElement && 1.476 + (!this._userSelecting || this._canUserSelect(aStartItem))) { 1.477 + --aDelta; 1.478 + if (aDelta == 0) 1.479 + return aStartItem; 1.480 + } 1.481 + } 1.482 + return null; 1.483 + ]]></body> 1.484 + </method> 1.485 + 1.486 + <method name="getPreviousItem"> 1.487 + <parameter name="aStartItem"/> 1.488 + <parameter name="aDelta"/> 1.489 + <body> 1.490 + <![CDATA[ 1.491 + while (aStartItem) { 1.492 + aStartItem = aStartItem.previousSibling; 1.493 + if (aStartItem && aStartItem instanceof 1.494 + Components.interfaces.nsIDOMXULSelectControlItemElement && 1.495 + (!this._userSelecting || this._canUserSelect(aStartItem))) { 1.496 + --aDelta; 1.497 + if (aDelta == 0) 1.498 + return aStartItem; 1.499 + } 1.500 + } 1.501 + return null; 1.502 + ]]> 1.503 + </body> 1.504 + </method> 1.505 + 1.506 + <method name="_moveByOffsetFromUserEvent"> 1.507 + <parameter name="aOffset"/> 1.508 + <parameter name="aEvent"/> 1.509 + <body> 1.510 + <![CDATA[ 1.511 + if (!aEvent.defaultPrevented) { 1.512 + this._userSelecting = true; 1.513 + this._mayReverse = true; 1.514 + this.moveByOffset(aOffset, !aEvent.ctrlKey, aEvent.shiftKey); 1.515 + this._userSelecting = false; 1.516 + this._mayReverse = false; 1.517 + aEvent.preventDefault(); 1.518 + } 1.519 + ]]> 1.520 + </body> 1.521 + </method> 1.522 + 1.523 + <method name="_canUserSelect"> 1.524 + <parameter name="aItem"/> 1.525 + <body> 1.526 + <![CDATA[ 1.527 + var style = document.defaultView.getComputedStyle(aItem, ""); 1.528 + return style.display != "none" && style.visibility == "visible"; 1.529 + ]]> 1.530 + </body> 1.531 + </method> 1.532 + 1.533 + <method name="_selectTimeoutHandler"> 1.534 + <parameter name="aMe"/> 1.535 + <body> 1.536 + aMe._fireOnSelect(); 1.537 + aMe._selectTimeout = null; 1.538 + </body> 1.539 + </method> 1.540 + 1.541 + <field name="_suppressOnSelect">false</field> 1.542 + <field name="_userSelecting">false</field> 1.543 + <field name="_mayReverse">false</field> 1.544 + <field name="_selectTimeout">null</field> 1.545 + <field name="_currentItem">null</field> 1.546 + <field name="_selectionStart">null</field> 1.547 + </implementation> 1.548 + 1.549 + <handlers> 1.550 + <handler event="keypress" keycode="VK_UP" modifiers="control shift any" 1.551 + action="this._moveByOffsetFromUserEvent(-1, event);" 1.552 + group="system"/> 1.553 + <handler event="keypress" keycode="VK_DOWN" modifiers="control shift any" 1.554 + action="this._moveByOffsetFromUserEvent(1, event);" 1.555 + group="system"/> 1.556 + <handler event="keypress" keycode="VK_HOME" modifiers="control shift any" 1.557 + group="system"> 1.558 + <![CDATA[ 1.559 + this._mayReverse = true; 1.560 + this._moveByOffsetFromUserEvent(-this.currentIndex, event); 1.561 + this._mayReverse = false; 1.562 + ]]> 1.563 + </handler> 1.564 + <handler event="keypress" keycode="VK_END" modifiers="control shift any" 1.565 + group="system"> 1.566 + <![CDATA[ 1.567 + this._mayReverse = true; 1.568 + this._moveByOffsetFromUserEvent(this.getRowCount() - this.currentIndex - 1, event); 1.569 + this._mayReverse = false; 1.570 + ]]> 1.571 + </handler> 1.572 + <handler event="keypress" keycode="VK_PAGE_UP" modifiers="control shift any" 1.573 + group="system"> 1.574 + <![CDATA[ 1.575 + this._mayReverse = true; 1.576 + this._moveByOffsetFromUserEvent(this.scrollOnePage(-1), event); 1.577 + this._mayReverse = false; 1.578 + ]]> 1.579 + </handler> 1.580 + <handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="control shift any" 1.581 + group="system"> 1.582 + <![CDATA[ 1.583 + this._mayReverse = true; 1.584 + this._moveByOffsetFromUserEvent(this.scrollOnePage(1), event); 1.585 + this._mayReverse = false; 1.586 + ]]> 1.587 + </handler> 1.588 + <handler event="keypress" key=" " modifiers="control" phase="target"> 1.589 + <![CDATA[ 1.590 + if (this.currentItem && this.selType == "multiple") 1.591 + this.toggleItemSelection(this.currentItem); 1.592 + ]]> 1.593 + </handler> 1.594 + <handler event="focus"> 1.595 + <![CDATA[ 1.596 + if (this.getRowCount() > 0) { 1.597 + if (this.currentIndex == -1) { 1.598 + this.currentIndex = this.getIndexOfFirstVisibleRow(); 1.599 + } 1.600 + else { 1.601 + this.currentItem._fireEvent("DOMMenuItemActive"); 1.602 + } 1.603 + } 1.604 + this._lastKeyTime = 0; 1.605 + ]]> 1.606 + </handler> 1.607 + <handler event="keypress" phase="target"> 1.608 + <![CDATA[ 1.609 + if (this.disableKeyNavigation || !event.charCode || 1.610 + event.altKey || event.ctrlKey || event.metaKey) 1.611 + return; 1.612 + 1.613 + if (event.timeStamp - this._lastKeyTime > 1000) 1.614 + this._incrementalString = ""; 1.615 + 1.616 + var key = String.fromCharCode(event.charCode).toLowerCase(); 1.617 + this._incrementalString += key; 1.618 + this._lastKeyTime = event.timeStamp; 1.619 + 1.620 + // If all letters in the incremental string are the same, just 1.621 + // try to match the first one 1.622 + var incrementalString = /^(.)\1+$/.test(this._incrementalString) ? 1.623 + RegExp.$1 : this._incrementalString; 1.624 + var length = incrementalString.length; 1.625 + 1.626 + var rowCount = this.getRowCount(); 1.627 + var l = this.selectedItems.length; 1.628 + var start = l > 0 ? this.getIndexOfItem(this.selectedItems[l - 1]) : -1; 1.629 + // start from the first element if none was selected or from the one 1.630 + // following the selected one if it's a new or a repeated-letter search 1.631 + if (start == -1 || length == 1) 1.632 + start++; 1.633 + 1.634 + for (var i = 0; i < rowCount; i++) { 1.635 + var k = (start + i) % rowCount; 1.636 + var listitem = this.getItemAtIndex(k); 1.637 + if (!this._canUserSelect(listitem)) 1.638 + continue; 1.639 + // allow richlistitems to specify the string being searched for 1.640 + var searchText = "searchLabel" in listitem ? listitem.searchLabel : 1.641 + listitem.getAttribute("label"); // (see also bug 250123) 1.642 + searchText = searchText.substring(0, length).toLowerCase(); 1.643 + if (searchText == incrementalString) { 1.644 + this.ensureIndexIsVisible(k); 1.645 + this.timedSelect(listitem, this._selectDelay); 1.646 + break; 1.647 + } 1.648 + } 1.649 + ]]> 1.650 + </handler> 1.651 + </handlers> 1.652 + </binding> 1.653 + 1.654 + 1.655 + <!-- Binding for xul:listbox element. 1.656 + --> 1.657 + <binding id="listbox" 1.658 + extends="#listbox-base"> 1.659 + 1.660 + <resources> 1.661 + <stylesheet src="chrome://global/skin/listbox.css"/> 1.662 + </resources> 1.663 + 1.664 + <content> 1.665 + <children includes="listcols"> 1.666 + <xul:listcols> 1.667 + <xul:listcol flex="1"/> 1.668 + </xul:listcols> 1.669 + </children> 1.670 + <xul:listrows> 1.671 + <children includes="listhead"/> 1.672 + <xul:listboxbody xbl:inherits="rows,size,minheight"> 1.673 + <children includes="listitem"/> 1.674 + </xul:listboxbody> 1.675 + </xul:listrows> 1.676 + </content> 1.677 + 1.678 + <implementation> 1.679 + 1.680 + <!-- ///////////////// public listbox members ///////////////// --> 1.681 + 1.682 + <property name="listBoxObject" 1.683 + onget="return this.boxObject.QueryInterface(Components.interfaces.nsIListBoxObject);" 1.684 + readonly="true"/> 1.685 + 1.686 + <!-- ///////////////// private listbox members ///////////////// --> 1.687 + 1.688 + <method name="_fireOnSelect"> 1.689 + <body> 1.690 + <![CDATA[ 1.691 + if (!this._suppressOnSelect && !this.suppressOnSelect) { 1.692 + var event = document.createEvent("Events"); 1.693 + event.initEvent("select", true, true); 1.694 + this.dispatchEvent(event); 1.695 + } 1.696 + ]]> 1.697 + </body> 1.698 + </method> 1.699 + 1.700 + <constructor> 1.701 + <![CDATA[ 1.702 + var count = this.itemCount; 1.703 + for (var index = 0; index < count; index++) { 1.704 + var item = this.getItemAtIndex(index); 1.705 + if (item.getAttribute("selected") == "true") 1.706 + this.selectedItems.push(item); 1.707 + } 1.708 + ]]> 1.709 + </constructor> 1.710 + 1.711 + <!-- ///////////////// nsIDOMXULSelectControlElement ///////////////// --> 1.712 + 1.713 + <method name="appendItem"> 1.714 + <parameter name="aLabel"/> 1.715 + <parameter name="aValue"/> 1.716 + <body> 1.717 + const XULNS = 1.718 + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.719 + 1.720 + var item = this.ownerDocument.createElementNS(XULNS, "listitem"); 1.721 + item.setAttribute("label", aLabel); 1.722 + item.setAttribute("value", aValue); 1.723 + this.appendChild(item); 1.724 + return item; 1.725 + </body> 1.726 + </method> 1.727 + 1.728 + <method name="insertItemAt"> 1.729 + <parameter name="aIndex"/> 1.730 + <parameter name="aLabel"/> 1.731 + <parameter name="aValue"/> 1.732 + <body> 1.733 + const XULNS = 1.734 + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.735 + 1.736 + var item = this.ownerDocument.createElementNS(XULNS, "listitem"); 1.737 + item.setAttribute("label", aLabel); 1.738 + item.setAttribute("value", aValue); 1.739 + var before = this.getItemAtIndex(aIndex); 1.740 + if (before) 1.741 + this.insertBefore(item, before); 1.742 + else 1.743 + this.appendChild(item); 1.744 + return item; 1.745 + </body> 1.746 + </method> 1.747 + 1.748 + <property name="itemCount" readonly="true" 1.749 + onget="return this.listBoxObject.getRowCount()"/> 1.750 + 1.751 + <!-- ///////////////// nsIListBoxObject ///////////////// --> 1.752 + <method name="getIndexOfItem"> 1.753 + <parameter name="item"/> 1.754 + <body> 1.755 + return this.listBoxObject.getIndexOfItem(item); 1.756 + </body> 1.757 + </method> 1.758 + <method name="getItemAtIndex"> 1.759 + <parameter name="index"/> 1.760 + <body> 1.761 + return this.listBoxObject.getItemAtIndex(index); 1.762 + </body> 1.763 + </method> 1.764 + <method name="ensureIndexIsVisible"> 1.765 + <parameter name="index"/> 1.766 + <body> 1.767 + return this.listBoxObject.ensureIndexIsVisible(index); 1.768 + </body> 1.769 + </method> 1.770 + <method name="ensureElementIsVisible"> 1.771 + <parameter name="element"/> 1.772 + <body> 1.773 + return this.ensureIndexIsVisible(this.listBoxObject.getIndexOfItem(element)); 1.774 + </body> 1.775 + </method> 1.776 + <method name="scrollToIndex"> 1.777 + <parameter name="index"/> 1.778 + <body> 1.779 + return this.listBoxObject.scrollToIndex(index); 1.780 + </body> 1.781 + </method> 1.782 + <method name="getNumberOfVisibleRows"> 1.783 + <body> 1.784 + return this.listBoxObject.getNumberOfVisibleRows(); 1.785 + </body> 1.786 + </method> 1.787 + <method name="getIndexOfFirstVisibleRow"> 1.788 + <body> 1.789 + return this.listBoxObject.getIndexOfFirstVisibleRow(); 1.790 + </body> 1.791 + </method> 1.792 + <method name="getRowCount"> 1.793 + <body> 1.794 + return this.listBoxObject.getRowCount(); 1.795 + </body> 1.796 + </method> 1.797 + 1.798 + <method name="scrollOnePage"> 1.799 + <parameter name="direction"/> <!-- Must be -1 or 1 --> 1.800 + <body> 1.801 + <![CDATA[ 1.802 + var pageOffset = this.getNumberOfVisibleRows() * direction; 1.803 + // skip over invisible elements - the user won't care about them 1.804 + for (var i = 0; i != pageOffset; i += direction) { 1.805 + var item = this.getItemAtIndex(this.currentIndex + i); 1.806 + if (item && !this._canUserSelect(item)) 1.807 + pageOffset += direction; 1.808 + } 1.809 + var newTop = this.getIndexOfFirstVisibleRow() + pageOffset; 1.810 + if (direction == 1) { 1.811 + var maxTop = this.getRowCount() - this.getNumberOfVisibleRows(); 1.812 + for (i = this.getRowCount(); i >= 0 && i > maxTop; i--) { 1.813 + item = this.getItemAtIndex(i); 1.814 + if (item && !this._canUserSelect(item)) 1.815 + maxTop--; 1.816 + } 1.817 + if (newTop >= maxTop) 1.818 + newTop = maxTop; 1.819 + } 1.820 + if (newTop < 0) 1.821 + newTop = 0; 1.822 + this.scrollToIndex(newTop); 1.823 + return pageOffset; 1.824 + ]]> 1.825 + </body> 1.826 + </method> 1.827 + </implementation> 1.828 + 1.829 + <handlers> 1.830 + <handler event="keypress" key=" " phase="target"> 1.831 + <![CDATA[ 1.832 + if (this.currentItem) { 1.833 + if (this.currentItem.getAttribute("type") != "checkbox") 1.834 + this.addItemToSelection(this.currentItem); 1.835 + else if (!this.currentItem.disabled) { 1.836 + this.currentItem.checked = !this.currentItem.checked; 1.837 + this.currentItem.doCommand(); 1.838 + } 1.839 + } 1.840 + ]]> 1.841 + </handler> 1.842 + 1.843 + <handler event="MozSwipeGesture"> 1.844 + <![CDATA[ 1.845 + // Figure out which index to show 1.846 + let targetIndex = 0; 1.847 + 1.848 + // Only handle swipe gestures up and down 1.849 + switch (event.direction) { 1.850 + case event.DIRECTION_DOWN: 1.851 + targetIndex = this.itemCount - 1; 1.852 + // Fall through for actual action 1.853 + case event.DIRECTION_UP: 1.854 + this.ensureIndexIsVisible(targetIndex); 1.855 + break; 1.856 + } 1.857 + ]]> 1.858 + </handler> 1.859 + </handlers> 1.860 + </binding> 1.861 + 1.862 + <binding id="listrows"> 1.863 + 1.864 + <resources> 1.865 + <stylesheet src="chrome://global/skin/listbox.css"/> 1.866 + </resources> 1.867 + 1.868 + <handlers> 1.869 + <handler event="DOMMouseScroll" phase="capturing"> 1.870 + <![CDATA[ 1.871 + if (event.axis == event.HORIZONTAL_AXIS) 1.872 + return; 1.873 + 1.874 + var listBox = this.parentNode.listBoxObject; 1.875 + var rows = event.detail; 1.876 + if (rows == UIEvent.SCROLL_PAGE_UP) 1.877 + rows = -listBox.getNumberOfVisibleRows(); 1.878 + else if (rows == UIEvent.SCROLL_PAGE_DOWN) 1.879 + rows = listBox.getNumberOfVisibleRows(); 1.880 + 1.881 + listBox.scrollByLines(rows); 1.882 + event.preventDefault(); 1.883 + ]]> 1.884 + </handler> 1.885 + 1.886 + <handler event="MozMousePixelScroll" phase="capturing"> 1.887 + <![CDATA[ 1.888 + if (event.axis == event.HORIZONTAL_AXIS) 1.889 + return; 1.890 + 1.891 + // shouldn't be scrolled by pixel scrolling events before a line/page 1.892 + // scrolling event. 1.893 + event.preventDefault(); 1.894 + ]]> 1.895 + </handler> 1.896 + </handlers> 1.897 + </binding> 1.898 + 1.899 + <binding id="listitem" role="xul:listitem" 1.900 + extends="chrome://global/content/bindings/general.xml#basetext"> 1.901 + <resources> 1.902 + <stylesheet src="chrome://global/skin/listbox.css"/> 1.903 + </resources> 1.904 + 1.905 + <content> 1.906 + <children> 1.907 + <xul:listcell xbl:inherits="label,crop,disabled,flexlabel"/> 1.908 + </children> 1.909 + </content> 1.910 + 1.911 + <implementation implements="nsIDOMXULSelectControlItemElement"> 1.912 + <property name="current" onget="return this.getAttribute('current') == 'true';"> 1.913 + <setter><![CDATA[ 1.914 + if (val) 1.915 + this.setAttribute("current", "true"); 1.916 + else 1.917 + this.removeAttribute("current"); 1.918 + 1.919 + this._fireEvent(val ? "DOMMenuItemActive" : "DOMMenuItemInactive"); 1.920 + 1.921 + return val; 1.922 + ]]></setter> 1.923 + </property> 1.924 + 1.925 + <!-- ///////////////// nsIDOMXULSelectControlItemElement ///////////////// --> 1.926 + 1.927 + <property name="value" onget="return this.getAttribute('value');" 1.928 + onset="this.setAttribute('value', val); return val;"/> 1.929 + <property name="label" onget="return this.getAttribute('label');" 1.930 + onset="this.setAttribute('label', val); return val;"/> 1.931 + 1.932 + <property name="selected" onget="return this.getAttribute('selected') == 'true';"> 1.933 + <setter><![CDATA[ 1.934 + if (val) 1.935 + this.setAttribute("selected", "true"); 1.936 + else 1.937 + this.removeAttribute("selected"); 1.938 + 1.939 + return val; 1.940 + ]]></setter> 1.941 + </property> 1.942 + 1.943 + <property name="control"> 1.944 + <getter><![CDATA[ 1.945 + var parent = this.parentNode; 1.946 + while (parent) { 1.947 + if (parent instanceof Components.interfaces.nsIDOMXULSelectControlElement) 1.948 + return parent; 1.949 + parent = parent.parentNode; 1.950 + } 1.951 + return null; 1.952 + ]]></getter> 1.953 + </property> 1.954 + 1.955 + <method name="_fireEvent"> 1.956 + <parameter name="name"/> 1.957 + <body> 1.958 + <![CDATA[ 1.959 + var event = document.createEvent("Events"); 1.960 + event.initEvent(name, true, true); 1.961 + this.dispatchEvent(event); 1.962 + ]]> 1.963 + </body> 1.964 + </method> 1.965 + </implementation> 1.966 + <handlers> 1.967 + <!-- If there is no modifier key, we select on mousedown, not 1.968 + click, so that drags work correctly. --> 1.969 + <handler event="mousedown"> 1.970 + <![CDATA[ 1.971 + var control = this.control; 1.972 + if (!control || control.disabled) 1.973 + return; 1.974 + if ((!event.ctrlKey 1.975 +#ifdef XP_MACOSX 1.976 + || event.button == 2 1.977 +#endif 1.978 + ) && !event.shiftKey && !event.metaKey) { 1.979 + if (!this.selected) { 1.980 + control.selectItem(this); 1.981 + } 1.982 + control.currentItem = this; 1.983 + } 1.984 + ]]> 1.985 + </handler> 1.986 + 1.987 + <!-- On a click (up+down on the same item), deselect everything 1.988 + except this item. --> 1.989 + <handler event="click" button="0"> 1.990 + <![CDATA[ 1.991 + var control = this.control; 1.992 + if (!control || control.disabled) 1.993 + return; 1.994 + control._userSelecting = true; 1.995 + if (control.selType != "multiple") { 1.996 + control.selectItem(this); 1.997 + } 1.998 + else if (event.ctrlKey || event.metaKey) { 1.999 + control.toggleItemSelection(this); 1.1000 + control.currentItem = this; 1.1001 + } 1.1002 + else if (event.shiftKey) { 1.1003 + control.selectItemRange(null, this); 1.1004 + control.currentItem = this; 1.1005 + } 1.1006 + else { 1.1007 + /* We want to deselect all the selected items except what was 1.1008 + clicked, UNLESS it was a right-click. We have to do this 1.1009 + in click rather than mousedown so that you can drag a 1.1010 + selected group of items */ 1.1011 + 1.1012 + // use selectItemRange instead of selectItem, because this 1.1013 + // doesn't de- and reselect this item if it is selected 1.1014 + control.selectItemRange(this, this); 1.1015 + } 1.1016 + control._userSelecting = false; 1.1017 + ]]> 1.1018 + </handler> 1.1019 + </handlers> 1.1020 + </binding> 1.1021 + 1.1022 + <binding id="listitem-iconic" 1.1023 + extends="chrome://global/content/bindings/listbox.xml#listitem"> 1.1024 + <content> 1.1025 + <children> 1.1026 + <xul:listcell class="listcell-iconic" xbl:inherits="label,image,crop,disabled,flexlabel"/> 1.1027 + </children> 1.1028 + </content> 1.1029 + </binding> 1.1030 + 1.1031 + <binding id="listitem-checkbox" 1.1032 + extends="chrome://global/content/bindings/listbox.xml#listitem"> 1.1033 + <content> 1.1034 + <children> 1.1035 + <xul:listcell type="checkbox" xbl:inherits="label,crop,checked,disabled,flexlabel"/> 1.1036 + </children> 1.1037 + </content> 1.1038 + 1.1039 + <implementation> 1.1040 + <property name="checked" 1.1041 + onget="return this.getAttribute('checked') == 'true';"> 1.1042 + <setter><![CDATA[ 1.1043 + if (val) 1.1044 + this.setAttribute('checked', 'true'); 1.1045 + else 1.1046 + this.removeAttribute('checked'); 1.1047 + var event = document.createEvent('Events'); 1.1048 + event.initEvent('CheckboxStateChange', true, true); 1.1049 + this.dispatchEvent(event); 1.1050 + return val; 1.1051 + ]]></setter> 1.1052 + </property> 1.1053 + </implementation> 1.1054 + 1.1055 + <handlers> 1.1056 + <handler event="mousedown" button="0"> 1.1057 + <![CDATA[ 1.1058 + if (!this.disabled && !this.control.disabled) { 1.1059 + this.checked = !this.checked; 1.1060 + this.doCommand(); 1.1061 + } 1.1062 + ]]> 1.1063 + </handler> 1.1064 + </handlers> 1.1065 + </binding> 1.1066 + 1.1067 + <binding id="listitem-checkbox-iconic" 1.1068 + extends="chrome://global/content/bindings/listbox.xml#listitem-checkbox"> 1.1069 + <content> 1.1070 + <children> 1.1071 + <xul:listcell type="checkbox" class="listcell-iconic" xbl:inherits="label,image,crop,checked,disabled,flexlabel"/> 1.1072 + </children> 1.1073 + </content> 1.1074 + </binding> 1.1075 + 1.1076 + <binding id="listcell" role="xul:listcell" 1.1077 + extends="chrome://global/content/bindings/general.xml#basecontrol"> 1.1078 + 1.1079 + <resources> 1.1080 + <stylesheet src="chrome://global/skin/listbox.css"/> 1.1081 + </resources> 1.1082 + 1.1083 + <content> 1.1084 + <children> 1.1085 + <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/> 1.1086 + </children> 1.1087 + </content> 1.1088 + </binding> 1.1089 + 1.1090 + <binding id="listcell-iconic" 1.1091 + extends="chrome://global/content/bindings/listbox.xml#listcell"> 1.1092 + <content> 1.1093 + <children> 1.1094 + <xul:image class="listcell-icon" xbl:inherits="src=image"/> 1.1095 + <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/> 1.1096 + </children> 1.1097 + </content> 1.1098 + </binding> 1.1099 + 1.1100 + <binding id="listcell-checkbox" 1.1101 + extends="chrome://global/content/bindings/listbox.xml#listcell"> 1.1102 + <content> 1.1103 + <children> 1.1104 + <xul:image class="listcell-check" xbl:inherits="checked,disabled"/> 1.1105 + <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/> 1.1106 + </children> 1.1107 + </content> 1.1108 + </binding> 1.1109 + 1.1110 + <binding id="listcell-checkbox-iconic" 1.1111 + extends="chrome://global/content/bindings/listbox.xml#listcell-checkbox"> 1.1112 + <content> 1.1113 + <children> 1.1114 + <xul:image class="listcell-check" xbl:inherits="checked,disabled"/> 1.1115 + <xul:image class="listcell-icon" xbl:inherits="src=image"/> 1.1116 + <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/> 1.1117 + </children> 1.1118 + </content> 1.1119 + </binding> 1.1120 + 1.1121 + <binding id="listhead" role="xul:listhead"> 1.1122 + 1.1123 + <resources> 1.1124 + <stylesheet src="chrome://global/skin/listbox.css"/> 1.1125 + </resources> 1.1126 + 1.1127 + <content> 1.1128 + <xul:listheaditem> 1.1129 + <children includes="listheader"/> 1.1130 + </xul:listheaditem> 1.1131 + </content> 1.1132 + </binding> 1.1133 + 1.1134 + <binding id="listheader" display="xul:button" role="xul:listheader"> 1.1135 + 1.1136 + <resources> 1.1137 + <stylesheet src="chrome://global/skin/listbox.css"/> 1.1138 + </resources> 1.1139 + 1.1140 + <content> 1.1141 + <xul:image class="listheader-icon"/> 1.1142 + <xul:label class="listheader-label" xbl:inherits="value=label,crop" flex="1" crop="right"/> 1.1143 + <xul:image class="listheader-sortdirection" xbl:inherits="sortDirection"/> 1.1144 + </content> 1.1145 + </binding> 1.1146 + 1.1147 +</bindings> 1.1148 +