toolkit/content/widgets/listbox.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.

     1 <?xml version="1.0"?>
     3 <!-- This Source Code Form is subject to the terms of the Mozilla Public
     4    - License, v. 2.0. If a copy of the MPL was not distributed with this
     5    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
     7 <bindings id="listboxBindings"
     8           xmlns="http://www.mozilla.org/xbl"
     9           xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    10           xmlns:xbl="http://www.mozilla.org/xbl">
    12   <!--
    13     Interface binding that is base for bindings of xul:listbox and
    14     xul:richlistbox elements. This binding assumes that successors bindings
    15     will implement the following properties and methods:
    17     /** Return the number of items */
    18     readonly itemCount
    20     /** Return index of given item
    21     * @param aItem - given item element */
    22     getIndexOfItem(aItem)
    24     /** Return item at given index
    25     * @param aIndex - index of item element */
    26     getItemAtIndex(aIndex)
    28     /** Return count of item elements */
    29     getRowCount()
    31     /** Return count of visible item elements */
    32     getNumberOfVisibleRows()
    34     /** Return index of first visible item element */
    35     getIndexOfFirstVisibleRow()
    37     /** Return true if item of given index is visible
    38      * @param aIndex - index of item element
    39      *
    40      * @note XXX: this method should be removed after bug 364612 is fixed
    41      */
    42     ensureIndexIsVisible(aIndex)
    44     /** Return true if item element is visible
    45      * @param aElement - given item element */
    46     ensureElementIsVisible(aElement)
    48     /** Scroll list control to make visible item of given index
    49      * @param aIndex - index of item element
    50      *
    51      * @note XXX: this method should be removed after bug 364612 is fixed
    52      */
    53     scrollToIndex(aIndex)
    55     /** Create item element and append it to the end of listbox
    56      * @param aLabel - label of new item element
    57      * @param aValue - value of new item element */
    58     appendItem(aLabel, aValue)
    60     /** Create item element and insert it to given position
    61      * @param aIndex - insertion position
    62      * @param aLabel - label of new item element
    63      * @param aValue - value of new item element */
    64     insertItemAt(aIndex, aLabel, aValue)
    66     /** Scroll up/down one page
    67      * @param aDirection - specifies scrolling direction, should be either -1 or 1
    68      * @return the number of elements the selection scrolled
    69      */
    70     scrollOnePage(aDirection)
    72     /** Fire "select" event */
    73     _fireOnSelect()
    74    -->
    75    <binding id="listbox-base" role="xul:listbox"
    76             extends="chrome://global/content/bindings/general.xml#basecontrol">
    78     <implementation implements="nsIDOMXULMultiSelectControlElement">
    79       <field name="_lastKeyTime">0</field>
    80       <field name="_incrementalString">""</field>
    82     <!-- nsIDOMXULSelectControlElement -->
    83       <property name="selectedItem"
    84                 onset="this.selectItem(val);">
    85         <getter>
    86         <![CDATA[
    87           return this.selectedItems.length > 0 ? this.selectedItems[0] : null;
    88         ]]>
    89         </getter>
    90       </property>
    92       <property name="selectedIndex">
    93         <getter>
    94         <![CDATA[
    95           if (this.selectedItems.length > 0)
    96             return this.getIndexOfItem(this.selectedItems[0]);
    97           return -1;
    98         ]]>
    99         </getter>
   100         <setter>
   101         <![CDATA[
   102           if (val >= 0) {
   103             this.selectItem(this.getItemAtIndex(val));
   104           } else {
   105             this.clearSelection();
   106             this.currentItem = null;
   107           }
   108         ]]>
   109         </setter>
   110       </property>
   112       <property name="value">
   113         <getter>
   114         <![CDATA[
   115           if (this.selectedItems.length > 0)
   116             return this.selectedItem.value;
   117           return null;
   118         ]]>
   119         </getter>
   120         <setter>
   121         <![CDATA[
   122           var kids = this.getElementsByAttribute("value", val);
   123           if (kids && kids.item(0))
   124             this.selectItem(kids[0]);
   125           return val;
   126         ]]>
   127         </setter>
   128       </property>
   130       <method name="removeItemAt">
   131         <parameter name="index"/>
   132         <body>
   133         <![CDATA[
   134           var remove = this.getItemAtIndex(index);
   135           if (remove)
   136             this.removeChild(remove);
   137           return remove;
   138         ]]>
   139         </body>
   140       </method>
   142     <!-- nsIDOMXULMultiSelectControlElement -->
   143       <property name="selType"
   144                 onget="return this.getAttribute('seltype');"
   145                 onset="this.setAttribute('seltype', val); return val;"/>
   147       <property name="currentItem" onget="return this._currentItem;">
   148         <setter>
   149           if (this._currentItem == val)
   150             return val;
   152           if (this._currentItem)
   153             this._currentItem.current = false;
   154           this._currentItem = val;
   156           if (val)
   157             val.current = true;
   159           return val;
   160         </setter>
   161       </property>
   163       <property name="currentIndex">
   164         <getter>
   165           return this.currentItem ? this.getIndexOfItem(this.currentItem) : -1;
   166         </getter>
   167         <setter>
   168         <![CDATA[
   169           if (val >= 0)
   170             this.currentItem = this.getItemAtIndex(val);
   171           else
   172             this.currentItem = null;
   173         ]]>
   174         </setter>
   175       </property>
   177       <field name="selectedItems">[]</field>
   179       <method name="addItemToSelection">
   180         <parameter name="aItem"/>
   181         <body>
   182         <![CDATA[
   183           if (this.selType != "multiple" && this.selectedCount)
   184             return;
   186           if (aItem.selected)
   187             return;
   189           this.selectedItems.push(aItem);
   190           aItem.selected = true;
   192           this._fireOnSelect();
   193         ]]>
   194         </body>
   195       </method>
   197       <method name="removeItemFromSelection">
   198         <parameter name="aItem"/>
   199         <body>
   200         <![CDATA[
   201           if (!aItem.selected)
   202             return;
   204           for (var i = 0; i < this.selectedItems.length; ++i) {
   205             if (this.selectedItems[i] == aItem) {
   206               this.selectedItems.splice(i, 1);
   207               aItem.selected = false;
   208               break;
   209             }
   210           }
   212           this._fireOnSelect();
   213         ]]>
   214         </body>
   215       </method>
   217       <method name="toggleItemSelection">
   218         <parameter name="aItem"/>
   219         <body>
   220         <![CDATA[
   221           if (aItem.selected)
   222             this.removeItemFromSelection(aItem);
   223           else
   224             this.addItemToSelection(aItem);
   225         ]]>
   226         </body>
   227       </method>
   229       <method name="selectItem">
   230         <parameter name="aItem"/>
   231         <body>
   232         <![CDATA[
   233           if (!aItem)
   234             return;
   236           if (this.selectedItems.length == 1 && this.selectedItems[0] == aItem)
   237             return;
   239           this._selectionStart = null;
   241           var suppress = this._suppressOnSelect;
   242           this._suppressOnSelect = true;
   244           this.clearSelection();
   245           this.addItemToSelection(aItem);
   246           this.currentItem = aItem;
   248           this._suppressOnSelect = suppress;
   249           this._fireOnSelect();
   250         ]]>
   251         </body>
   252       </method>
   254       <method name="selectItemRange">
   255         <parameter name="aStartItem"/>
   256         <parameter name="aEndItem"/>
   257         <body>
   258         <![CDATA[
   259           if (this.selType != "multiple")
   260             return;
   262           if (!aStartItem)
   263             aStartItem = this._selectionStart ?
   264               this._selectionStart : this.currentItem;
   266           if (!aStartItem)
   267             aStartItem = aEndItem;
   269           var suppressSelect = this._suppressOnSelect;
   270           this._suppressOnSelect = true;
   272           this._selectionStart = aStartItem;
   274           var currentItem;
   275           var startIndex = this.getIndexOfItem(aStartItem);
   276           var endIndex = this.getIndexOfItem(aEndItem);
   277           if (endIndex < startIndex) {
   278             currentItem = aEndItem;
   279             aEndItem = aStartItem;
   280             aStartItem = currentItem;
   281           } else {
   282             currentItem = aStartItem;
   283           }
   285           while (currentItem) {
   286             this.addItemToSelection(currentItem);
   287             if (currentItem == aEndItem) {
   288               currentItem = this.getNextItem(currentItem, 1);
   289               break;
   290             }
   291             currentItem = this.getNextItem(currentItem, 1);
   292           }
   294           // Clear around new selection
   295           // Don't use clearSelection() because it causes a lot of noise
   296           // with respect to selection removed notifications used by the
   297           // accessibility API support.
   298           var userSelecting = this._userSelecting;
   299           this._userSelecting = false; // that's US automatically unselecting
   300           for (; currentItem; currentItem = this.getNextItem(currentItem, 1))
   301             this.removeItemFromSelection(currentItem);
   303           for (currentItem = this.getItemAtIndex(0); currentItem != aStartItem;
   304                currentItem = this.getNextItem(currentItem, 1))
   305             this.removeItemFromSelection(currentItem);
   306           this._userSelecting = userSelecting;
   308           this._suppressOnSelect = suppressSelect;
   310           this._fireOnSelect();
   311         ]]>
   312         </body>
   313       </method>
   315       <method name="selectAll">
   316         <body>
   317           this._selectionStart = null;
   319           var suppress = this._suppressOnSelect;
   320           this._suppressOnSelect = true;
   322           var item = this.getItemAtIndex(0);
   323           while (item) {
   324             this.addItemToSelection(item);
   325             item = this.getNextItem(item, 1);
   326           }
   328           this._suppressOnSelect = suppress;
   329           this._fireOnSelect();
   330         </body>
   331       </method>
   333       <method name="invertSelection">
   334         <body>
   335           this._selectionStart = null;
   337           var suppress = this._suppressOnSelect;
   338           this._suppressOnSelect = true;
   340           var item = this.getItemAtIndex(0);
   341           while (item) {
   342             if (item.selected)
   343               this.removeItemFromSelection(item);
   344             else
   345               this.addItemToSelection(item);
   346             item = this.getNextItem(item, 1);
   347           }
   349           this._suppressOnSelect = suppress;
   350           this._fireOnSelect();
   351         </body>
   352       </method>
   354       <method name="clearSelection">
   355         <body>
   356         <![CDATA[
   357           if (this.selectedItems) {
   358             for (var i = this.selectedItems.length - 1; i >= 0; --i)
   359               this.selectedItems[i].selected = false;
   361             this.selectedItems.length = 0;
   362           }
   364           this._selectionStart = null;
   365           this._fireOnSelect();
   366         ]]>
   367         </body>
   368       </method>
   370       <property name="selectedCount" readonly="true"
   371                 onget="return this.selectedItems.length;"/>
   373       <method name="getSelectedItem">
   374         <parameter name="aIndex"/>
   375         <body>
   376         <![CDATA[
   377           return aIndex < this.selectedItems.length ?
   378             this.selectedItems[aIndex] : null;
   379         ]]>
   380         </body>
   381       </method>
   383     <!-- Other public members -->
   384       <property name="disableKeyNavigation"
   385                 onget="return this.hasAttribute('disableKeyNavigation');">
   386         <setter>
   387           if (val)
   388             this.setAttribute("disableKeyNavigation", "true");
   389           else
   390             this.removeAttribute("disableKeyNavigation");
   391           return val;
   392         </setter>
   393       </property>
   395       <property name="suppressOnSelect"
   396                 onget="return this.getAttribute('suppressonselect') == 'true';"
   397                 onset="this.setAttribute('suppressonselect', val);"/>
   399       <property name="_selectDelay"
   400                 onset="this.setAttribute('_selectDelay', val);"
   401                 onget="return this.getAttribute('_selectDelay') || 50;"/>
   403       <method name="timedSelect">
   404         <parameter name="aItem"/>
   405         <parameter name="aTimeout"/>
   406         <body>
   407         <![CDATA[
   408           var suppress = this._suppressOnSelect;
   409           if (aTimeout != -1)
   410             this._suppressOnSelect = true;
   412           this.selectItem(aItem);
   414           this._suppressOnSelect = suppress;
   416           if (aTimeout != -1) {
   417             if (this._selectTimeout)
   418               window.clearTimeout(this._selectTimeout);
   419             this._selectTimeout =
   420               window.setTimeout(this._selectTimeoutHandler, aTimeout, this);
   421           }
   422         ]]>
   423         </body>
   424       </method>
   426       <method name="moveByOffset">
   427         <parameter name="aOffset"/>
   428         <parameter name="aIsSelecting"/>
   429         <parameter name="aIsSelectingRange"/>
   430         <body>
   431         <![CDATA[
   432           if ((aIsSelectingRange || !aIsSelecting) &&
   433               this.selType != "multiple")
   434             return;
   436           var newIndex = this.currentIndex + aOffset;
   437           if (newIndex < 0)
   438             newIndex = 0;
   440           var numItems = this.getRowCount();
   441           if (newIndex > numItems - 1)
   442             newIndex = numItems - 1;
   444           var newItem = this.getItemAtIndex(newIndex);
   445           // make sure that the item is actually visible/selectable
   446           if (this._userSelecting && newItem && !this._canUserSelect(newItem))
   447             newItem =
   448               aOffset > 0 ? this.getNextItem(newItem, 1) || this.getPreviousItem(newItem, 1) :
   449                             this.getPreviousItem(newItem, 1) || this.getNextItem(newItem, 1);
   450           if (newItem) {
   451             this.ensureIndexIsVisible(this.getIndexOfItem(newItem));
   452             if (aIsSelectingRange)
   453               this.selectItemRange(null, newItem);
   454             else if (aIsSelecting)
   455               this.selectItem(newItem);
   457             this.currentItem = newItem;
   458           }
   459         ]]>
   460         </body>
   461       </method>
   463     <!-- Private -->
   464       <method name="getNextItem">
   465         <parameter name="aStartItem"/>
   466         <parameter name="aDelta"/>
   467         <body>
   468         <![CDATA[
   469           while (aStartItem) {
   470             aStartItem = aStartItem.nextSibling;
   471             if (aStartItem && aStartItem instanceof
   472                 Components.interfaces.nsIDOMXULSelectControlItemElement &&
   473                 (!this._userSelecting || this._canUserSelect(aStartItem))) {
   474               --aDelta;
   475               if (aDelta == 0)
   476                 return aStartItem;
   477             }
   478           }
   479           return null;
   480         ]]></body>
   481       </method>
   483       <method name="getPreviousItem">
   484         <parameter name="aStartItem"/>
   485         <parameter name="aDelta"/>
   486         <body>
   487         <![CDATA[
   488           while (aStartItem) {
   489             aStartItem = aStartItem.previousSibling;
   490             if (aStartItem && aStartItem instanceof
   491                 Components.interfaces.nsIDOMXULSelectControlItemElement &&
   492                 (!this._userSelecting || this._canUserSelect(aStartItem))) {
   493               --aDelta;
   494               if (aDelta == 0)
   495                 return aStartItem;
   496             }
   497           }
   498           return null;
   499         ]]>
   500         </body>
   501       </method>
   503       <method name="_moveByOffsetFromUserEvent">
   504         <parameter name="aOffset"/>
   505         <parameter name="aEvent"/>
   506         <body>
   507         <![CDATA[
   508           if (!aEvent.defaultPrevented) {
   509             this._userSelecting = true;
   510             this._mayReverse = true;
   511             this.moveByOffset(aOffset, !aEvent.ctrlKey, aEvent.shiftKey);
   512             this._userSelecting = false;
   513             this._mayReverse = false;
   514             aEvent.preventDefault();
   515           }
   516         ]]>
   517         </body>
   518       </method>
   520       <method name="_canUserSelect">
   521         <parameter name="aItem"/>
   522         <body>
   523         <![CDATA[
   524           var style = document.defaultView.getComputedStyle(aItem, "");
   525           return style.display != "none" && style.visibility == "visible";
   526         ]]>
   527         </body>
   528       </method>
   530       <method name="_selectTimeoutHandler">
   531         <parameter name="aMe"/>
   532         <body>
   533           aMe._fireOnSelect();
   534           aMe._selectTimeout = null;
   535         </body>
   536       </method>
   538       <field name="_suppressOnSelect">false</field>
   539       <field name="_userSelecting">false</field>
   540       <field name="_mayReverse">false</field>
   541       <field name="_selectTimeout">null</field>
   542       <field name="_currentItem">null</field>
   543       <field name="_selectionStart">null</field>
   544     </implementation>
   546     <handlers>
   547       <handler event="keypress" keycode="VK_UP" modifiers="control shift any"
   548                action="this._moveByOffsetFromUserEvent(-1, event);"
   549                group="system"/>
   550       <handler event="keypress" keycode="VK_DOWN" modifiers="control shift any"
   551                action="this._moveByOffsetFromUserEvent(1, event);"
   552                group="system"/>
   553       <handler event="keypress" keycode="VK_HOME" modifiers="control shift any"
   554                group="system">
   555         <![CDATA[
   556           this._mayReverse = true;
   557           this._moveByOffsetFromUserEvent(-this.currentIndex, event);
   558           this._mayReverse = false;
   559         ]]>
   560       </handler>
   561       <handler event="keypress" keycode="VK_END" modifiers="control shift any"
   562                group="system">
   563         <![CDATA[
   564           this._mayReverse = true;
   565           this._moveByOffsetFromUserEvent(this.getRowCount() - this.currentIndex - 1, event);
   566           this._mayReverse = false;
   567         ]]>
   568       </handler>
   569       <handler event="keypress" keycode="VK_PAGE_UP" modifiers="control shift any"
   570                group="system">
   571         <![CDATA[
   572           this._mayReverse = true;
   573           this._moveByOffsetFromUserEvent(this.scrollOnePage(-1), event);
   574           this._mayReverse = false;
   575         ]]>
   576       </handler>
   577       <handler event="keypress" keycode="VK_PAGE_DOWN" modifiers="control shift any"
   578                group="system">
   579         <![CDATA[
   580           this._mayReverse = true;
   581           this._moveByOffsetFromUserEvent(this.scrollOnePage(1), event);
   582           this._mayReverse = false;
   583         ]]>
   584       </handler>
   585       <handler event="keypress" key=" " modifiers="control" phase="target">
   586       <![CDATA[
   587         if (this.currentItem && this.selType == "multiple")
   588           this.toggleItemSelection(this.currentItem);
   589       ]]>
   590       </handler>
   591       <handler event="focus">
   592       <![CDATA[
   593         if (this.getRowCount() > 0) {
   594           if (this.currentIndex == -1) {
   595             this.currentIndex = this.getIndexOfFirstVisibleRow();
   596           }
   597           else {
   598             this.currentItem._fireEvent("DOMMenuItemActive");
   599           }
   600         }
   601         this._lastKeyTime = 0;
   602       ]]>
   603       </handler>
   604       <handler event="keypress" phase="target">
   605       <![CDATA[
   606         if (this.disableKeyNavigation || !event.charCode ||
   607             event.altKey || event.ctrlKey || event.metaKey)
   608           return;
   610         if (event.timeStamp - this._lastKeyTime > 1000)
   611           this._incrementalString = "";
   613         var key = String.fromCharCode(event.charCode).toLowerCase();
   614         this._incrementalString += key;
   615         this._lastKeyTime = event.timeStamp;
   617         // If all letters in the incremental string are the same, just
   618         // try to match the first one
   619         var incrementalString = /^(.)\1+$/.test(this._incrementalString) ?
   620                                 RegExp.$1 : this._incrementalString;
   621         var length = incrementalString.length;
   623         var rowCount = this.getRowCount();
   624         var l = this.selectedItems.length;
   625         var start = l > 0 ? this.getIndexOfItem(this.selectedItems[l - 1]) : -1;
   626         // start from the first element if none was selected or from the one
   627         // following the selected one if it's a new or a repeated-letter search
   628         if (start == -1 || length == 1)
   629           start++;
   631         for (var i = 0; i < rowCount; i++) {
   632           var k = (start + i) % rowCount;
   633           var listitem = this.getItemAtIndex(k);
   634           if (!this._canUserSelect(listitem))
   635             continue;
   636           // allow richlistitems to specify the string being searched for
   637           var searchText = "searchLabel" in listitem ? listitem.searchLabel :
   638                            listitem.getAttribute("label"); // (see also bug 250123)
   639           searchText = searchText.substring(0, length).toLowerCase();
   640           if (searchText == incrementalString) {
   641             this.ensureIndexIsVisible(k);
   642             this.timedSelect(listitem, this._selectDelay);
   643             break;
   644           }
   645         }
   646       ]]>
   647       </handler>
   648     </handlers>
   649   </binding>
   652   <!-- Binding for xul:listbox element.
   653   -->
   654   <binding id="listbox"
   655            extends="#listbox-base">
   657     <resources>
   658       <stylesheet src="chrome://global/skin/listbox.css"/>
   659     </resources>
   661     <content>
   662       <children includes="listcols">
   663         <xul:listcols>
   664           <xul:listcol flex="1"/>
   665         </xul:listcols>
   666       </children>
   667       <xul:listrows>
   668         <children includes="listhead"/>
   669         <xul:listboxbody xbl:inherits="rows,size,minheight">
   670           <children includes="listitem"/>
   671         </xul:listboxbody> 
   672       </xul:listrows>
   673     </content>
   675     <implementation>
   677       <!-- ///////////////// public listbox members ///////////////// -->
   679       <property name="listBoxObject"
   680                 onget="return this.boxObject.QueryInterface(Components.interfaces.nsIListBoxObject);"
   681                 readonly="true"/>
   683       <!-- ///////////////// private listbox members ///////////////// -->
   685       <method name="_fireOnSelect">
   686         <body>
   687         <![CDATA[
   688           if (!this._suppressOnSelect && !this.suppressOnSelect) {
   689             var event = document.createEvent("Events");
   690             event.initEvent("select", true, true);
   691             this.dispatchEvent(event);
   692           }
   693         ]]>
   694         </body>
   695       </method>
   697       <constructor>
   698       <![CDATA[
   699         var count = this.itemCount;
   700         for (var index = 0; index < count; index++) {
   701           var item = this.getItemAtIndex(index);
   702           if (item.getAttribute("selected") == "true")
   703             this.selectedItems.push(item);
   704         }
   705       ]]>
   706       </constructor>
   708       <!-- ///////////////// nsIDOMXULSelectControlElement ///////////////// -->
   710       <method name="appendItem">
   711         <parameter name="aLabel"/>
   712         <parameter name="aValue"/>
   713         <body>
   714           const XULNS =
   715             "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
   717           var item = this.ownerDocument.createElementNS(XULNS, "listitem");
   718           item.setAttribute("label", aLabel);
   719           item.setAttribute("value", aValue);
   720           this.appendChild(item);
   721           return item;
   722         </body>
   723       </method>
   725       <method name="insertItemAt">
   726         <parameter name="aIndex"/>
   727         <parameter name="aLabel"/>
   728         <parameter name="aValue"/>
   729         <body>
   730           const XULNS =
   731             "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
   733           var item = this.ownerDocument.createElementNS(XULNS, "listitem");
   734           item.setAttribute("label", aLabel);
   735           item.setAttribute("value", aValue);
   736           var before = this.getItemAtIndex(aIndex);
   737           if (before)
   738             this.insertBefore(item, before);
   739           else
   740             this.appendChild(item);
   741           return item;
   742         </body>
   743       </method>
   745       <property name="itemCount" readonly="true"
   746                 onget="return this.listBoxObject.getRowCount()"/>
   748       <!-- ///////////////// nsIListBoxObject ///////////////// -->
   749       <method name="getIndexOfItem">
   750         <parameter name="item"/>
   751         <body>
   752           return this.listBoxObject.getIndexOfItem(item);
   753         </body>
   754       </method>
   755       <method name="getItemAtIndex">
   756         <parameter name="index"/>
   757         <body>
   758           return this.listBoxObject.getItemAtIndex(index);
   759         </body>
   760       </method>
   761       <method name="ensureIndexIsVisible">
   762         <parameter name="index"/>
   763         <body>
   764           return this.listBoxObject.ensureIndexIsVisible(index);
   765         </body>
   766       </method>
   767       <method name="ensureElementIsVisible">
   768         <parameter name="element"/>
   769         <body>
   770           return this.ensureIndexIsVisible(this.listBoxObject.getIndexOfItem(element));
   771         </body>
   772       </method>
   773       <method name="scrollToIndex">
   774         <parameter name="index"/>
   775         <body>
   776           return this.listBoxObject.scrollToIndex(index);
   777         </body>
   778       </method>
   779       <method name="getNumberOfVisibleRows">
   780         <body>
   781           return this.listBoxObject.getNumberOfVisibleRows();
   782         </body>
   783       </method>
   784       <method name="getIndexOfFirstVisibleRow">
   785         <body>
   786           return this.listBoxObject.getIndexOfFirstVisibleRow();
   787         </body>
   788       </method>
   789       <method name="getRowCount">
   790         <body>
   791           return this.listBoxObject.getRowCount();
   792         </body>
   793       </method>
   795       <method name="scrollOnePage">
   796         <parameter name="direction"/>  <!-- Must be -1 or 1 -->
   797         <body>      
   798           <![CDATA[
   799             var pageOffset = this.getNumberOfVisibleRows() * direction;
   800             // skip over invisible elements - the user won't care about them
   801             for (var i = 0; i != pageOffset; i += direction) {
   802               var item = this.getItemAtIndex(this.currentIndex + i);
   803               if (item && !this._canUserSelect(item))
   804                 pageOffset += direction;
   805             }
   806             var newTop = this.getIndexOfFirstVisibleRow() + pageOffset;
   807             if (direction == 1) {
   808               var maxTop = this.getRowCount() - this.getNumberOfVisibleRows();
   809               for (i = this.getRowCount(); i >= 0 && i > maxTop; i--) {
   810                 item = this.getItemAtIndex(i);
   811                 if (item && !this._canUserSelect(item))
   812                   maxTop--;
   813               }
   814               if (newTop >= maxTop)
   815                 newTop = maxTop;
   816             }
   817             if (newTop < 0)
   818               newTop = 0;
   819             this.scrollToIndex(newTop);
   820             return pageOffset;          
   821           ]]>
   822         </body>
   823       </method>
   824     </implementation>
   826     <handlers>
   827       <handler event="keypress" key=" " phase="target">
   828         <![CDATA[
   829           if (this.currentItem) {
   830             if (this.currentItem.getAttribute("type") != "checkbox")
   831               this.addItemToSelection(this.currentItem);
   832             else if (!this.currentItem.disabled) {
   833               this.currentItem.checked = !this.currentItem.checked;
   834               this.currentItem.doCommand();
   835             }
   836           }
   837         ]]>
   838       </handler>
   840       <handler event="MozSwipeGesture">
   841         <![CDATA[
   842           // Figure out which index to show
   843           let targetIndex = 0;
   845           // Only handle swipe gestures up and down
   846           switch (event.direction) {
   847             case event.DIRECTION_DOWN:
   848               targetIndex = this.itemCount - 1;
   849               // Fall through for actual action
   850             case event.DIRECTION_UP:
   851               this.ensureIndexIsVisible(targetIndex);
   852               break;
   853           }
   854         ]]>
   855       </handler>
   856     </handlers>    
   857   </binding>
   859   <binding id="listrows">
   861     <resources>
   862       <stylesheet src="chrome://global/skin/listbox.css"/>
   863     </resources>
   865     <handlers>
   866       <handler event="DOMMouseScroll" phase="capturing">
   867       <![CDATA[
   868         if (event.axis == event.HORIZONTAL_AXIS)
   869           return;
   871         var listBox = this.parentNode.listBoxObject;
   872         var rows = event.detail;
   873         if (rows == UIEvent.SCROLL_PAGE_UP)
   874           rows = -listBox.getNumberOfVisibleRows();
   875         else if (rows == UIEvent.SCROLL_PAGE_DOWN)
   876           rows = listBox.getNumberOfVisibleRows();
   878         listBox.scrollByLines(rows);
   879         event.preventDefault();
   880       ]]>
   881       </handler>
   883       <handler event="MozMousePixelScroll" phase="capturing">
   884       <![CDATA[
   885         if (event.axis == event.HORIZONTAL_AXIS)
   886           return;
   888         // shouldn't be scrolled by pixel scrolling events before a line/page
   889         // scrolling event.
   890         event.preventDefault();
   891       ]]>
   892       </handler>
   893     </handlers>
   894   </binding>
   896   <binding id="listitem" role="xul:listitem"
   897            extends="chrome://global/content/bindings/general.xml#basetext">
   898     <resources>
   899       <stylesheet src="chrome://global/skin/listbox.css"/>
   900     </resources>
   902     <content>
   903       <children>
   904         <xul:listcell xbl:inherits="label,crop,disabled,flexlabel"/>
   905       </children>
   906     </content>
   908     <implementation implements="nsIDOMXULSelectControlItemElement">
   909       <property name="current" onget="return this.getAttribute('current') == 'true';">
   910         <setter><![CDATA[
   911           if (val)
   912             this.setAttribute("current", "true");
   913           else
   914             this.removeAttribute("current");
   916           this._fireEvent(val ? "DOMMenuItemActive" : "DOMMenuItemInactive");
   918           return val;
   919         ]]></setter>
   920       </property>
   922       <!-- ///////////////// nsIDOMXULSelectControlItemElement ///////////////// -->
   924       <property name="value" onget="return this.getAttribute('value');"
   925                              onset="this.setAttribute('value', val); return val;"/>
   926       <property name="label" onget="return this.getAttribute('label');"
   927                              onset="this.setAttribute('label', val); return val;"/>
   929       <property name="selected" onget="return this.getAttribute('selected') == 'true';">
   930         <setter><![CDATA[
   931           if (val)
   932             this.setAttribute("selected", "true");
   933           else
   934             this.removeAttribute("selected");
   936           return val;
   937         ]]></setter>
   938       </property>
   940       <property name="control">
   941         <getter><![CDATA[
   942           var parent = this.parentNode;
   943           while (parent) {
   944             if (parent instanceof Components.interfaces.nsIDOMXULSelectControlElement)
   945               return parent;
   946             parent = parent.parentNode;
   947           }
   948           return null;
   949         ]]></getter>
   950       </property>
   952       <method name="_fireEvent">
   953         <parameter name="name"/>
   954         <body>
   955         <![CDATA[
   956           var event = document.createEvent("Events");
   957           event.initEvent(name, true, true);
   958           this.dispatchEvent(event);
   959         ]]>
   960         </body>
   961       </method>
   962     </implementation>
   963     <handlers>
   964       <!-- If there is no modifier key, we select on mousedown, not
   965            click, so that drags work correctly. -->
   966       <handler event="mousedown">
   967       <![CDATA[
   968         var control = this.control;
   969         if (!control || control.disabled)
   970           return;
   971         if ((!event.ctrlKey
   972 #ifdef XP_MACOSX
   973              || event.button == 2
   974 #endif
   975             ) && !event.shiftKey && !event.metaKey) {
   976           if (!this.selected) {
   977             control.selectItem(this);
   978           }
   979           control.currentItem = this;
   980         }
   981       ]]>
   982       </handler>
   984       <!-- On a click (up+down on the same item), deselect everything
   985            except this item. -->
   986       <handler event="click" button="0">
   987       <![CDATA[
   988         var control = this.control;
   989         if (!control || control.disabled)
   990           return;
   991         control._userSelecting = true;
   992         if (control.selType != "multiple") {
   993           control.selectItem(this);
   994         }
   995         else if (event.ctrlKey || event.metaKey) {
   996           control.toggleItemSelection(this);
   997           control.currentItem = this;
   998         }
   999         else if (event.shiftKey) {
  1000           control.selectItemRange(null, this);
  1001           control.currentItem = this;
  1003         else {
  1004           /* We want to deselect all the selected items except what was
  1005             clicked, UNLESS it was a right-click.  We have to do this
  1006             in click rather than mousedown so that you can drag a
  1007             selected group of items */
  1009           // use selectItemRange instead of selectItem, because this
  1010           // doesn't de- and reselect this item if it is selected
  1011           control.selectItemRange(this, this);
  1013         control._userSelecting = false;
  1014       ]]>
  1015       </handler>
  1016     </handlers>
  1017   </binding>
  1019   <binding id="listitem-iconic"
  1020            extends="chrome://global/content/bindings/listbox.xml#listitem">
  1021     <content>
  1022       <children>
  1023         <xul:listcell class="listcell-iconic" xbl:inherits="label,image,crop,disabled,flexlabel"/>
  1024       </children>
  1025     </content>
  1026   </binding>
  1028   <binding id="listitem-checkbox"
  1029            extends="chrome://global/content/bindings/listbox.xml#listitem">
  1030     <content>
  1031       <children>
  1032         <xul:listcell type="checkbox" xbl:inherits="label,crop,checked,disabled,flexlabel"/>
  1033       </children>
  1034     </content>
  1036     <implementation>
  1037       <property name="checked"
  1038                 onget="return this.getAttribute('checked') == 'true';">
  1039         <setter><![CDATA[
  1040           if (val)
  1041             this.setAttribute('checked', 'true');
  1042           else
  1043             this.removeAttribute('checked');
  1044           var event = document.createEvent('Events');
  1045           event.initEvent('CheckboxStateChange', true, true);
  1046           this.dispatchEvent(event);
  1047           return val;
  1048         ]]></setter>
  1049       </property>
  1050     </implementation>
  1052     <handlers> 
  1053       <handler event="mousedown" button="0">
  1054       <![CDATA[
  1055         if (!this.disabled && !this.control.disabled) {
  1056           this.checked = !this.checked;
  1057           this.doCommand();
  1059       ]]>
  1060       </handler>
  1061     </handlers>
  1062   </binding>
  1064   <binding id="listitem-checkbox-iconic"
  1065            extends="chrome://global/content/bindings/listbox.xml#listitem-checkbox">
  1066     <content>
  1067       <children>
  1068         <xul:listcell type="checkbox" class="listcell-iconic" xbl:inherits="label,image,crop,checked,disabled,flexlabel"/>
  1069       </children>
  1070     </content>
  1071   </binding>
  1073   <binding id="listcell" role="xul:listcell"
  1074            extends="chrome://global/content/bindings/general.xml#basecontrol">
  1076     <resources>
  1077       <stylesheet src="chrome://global/skin/listbox.css"/>
  1078     </resources>
  1080     <content>
  1081       <children>
  1082         <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>
  1083       </children>
  1084     </content>
  1085   </binding>
  1087   <binding id="listcell-iconic"
  1088            extends="chrome://global/content/bindings/listbox.xml#listcell">
  1089     <content>
  1090       <children>
  1091         <xul:image class="listcell-icon" xbl:inherits="src=image"/>
  1092         <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>
  1093       </children>
  1094     </content>
  1095   </binding>
  1097   <binding id="listcell-checkbox"
  1098            extends="chrome://global/content/bindings/listbox.xml#listcell">
  1099     <content>
  1100       <children>
  1101         <xul:image class="listcell-check" xbl:inherits="checked,disabled"/>
  1102         <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>
  1103       </children>
  1104     </content>
  1105   </binding>
  1107   <binding id="listcell-checkbox-iconic"
  1108            extends="chrome://global/content/bindings/listbox.xml#listcell-checkbox">
  1109     <content>
  1110       <children>
  1111         <xul:image class="listcell-check" xbl:inherits="checked,disabled"/>
  1112         <xul:image class="listcell-icon" xbl:inherits="src=image"/>
  1113         <xul:label class="listcell-label" xbl:inherits="value=label,flex=flexlabel,crop,disabled" flex="1" crop="right"/>
  1114       </children>
  1115     </content>
  1116   </binding>
  1118   <binding id="listhead" role="xul:listhead">
  1120     <resources>
  1121       <stylesheet src="chrome://global/skin/listbox.css"/>
  1122     </resources>
  1124     <content>
  1125       <xul:listheaditem>
  1126         <children includes="listheader"/>
  1127       </xul:listheaditem>
  1128     </content>
  1129   </binding>
  1131   <binding id="listheader" display="xul:button" role="xul:listheader">
  1133     <resources>
  1134       <stylesheet src="chrome://global/skin/listbox.css"/>
  1135     </resources>
  1137     <content>
  1138       <xul:image class="listheader-icon"/>
  1139       <xul:label class="listheader-label" xbl:inherits="value=label,crop" flex="1" crop="right"/>
  1140       <xul:image class="listheader-sortdirection" xbl:inherits="sortDirection"/>
  1141     </content>
  1142   </binding>
  1144 </bindings>

mercurial