toolkit/content/widgets/tree.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"?>
     2 <!-- This Source Code Form is subject to the terms of the Mozilla Public
     3    - License, v. 2.0. If a copy of the MPL was not distributed with this
     4    - file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
     7 <!DOCTYPE bindings [
     8 <!ENTITY % treeDTD SYSTEM "chrome://global/locale/tree.dtd">
     9 %treeDTD;
    10 ]>
    12 <bindings id="treeBindings"
    13    xmlns="http://www.mozilla.org/xbl"
    14    xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    15    xmlns:xbl="http://www.mozilla.org/xbl">
    17   <binding id="tree-base" extends="chrome://global/content/bindings/general.xml#basecontrol">
    18     <resources>
    19       <stylesheet src="chrome://global/skin/tree.css"/>
    20     </resources>
    21     <implementation>
    22       <method name="_isAccelPressed">
    23         <parameter name="aEvent"/>
    24         <body><![CDATA[
    25 # Workaround until bug 302174 is fixed
    26 #ifdef XP_MACOSX
    27           return aEvent.metaKey;
    28 #else
    29           return aEvent.ctrlKey;
    30 #endif
    31         ]]></body>
    32       </method>
    33     </implementation>
    34   </binding>
    36   <binding id="tree" extends="chrome://global/content/bindings/tree.xml#tree-base" role="xul:tree">
    37     <content hidevscroll="true" hidehscroll="true" clickthrough="never">
    38       <children includes="treecols"/>
    39       <xul:stack class="tree-stack" flex="1">
    40         <xul:treerows class="tree-rows" flex="1" xbl:inherits="hidevscroll">
    41           <children/>
    42         </xul:treerows>
    43         <xul:textbox anonid="input" class="tree-input" left="0" top="0" hidden="true"/>
    44       </xul:stack>
    45       <xul:hbox xbl:inherits="collapsed=hidehscroll">
    46         <xul:scrollbar orient="horizontal" flex="1" increment="16" style="position:relative; z-index:2147483647;"/>
    47         <xul:scrollcorner xbl:inherits="collapsed=hidevscroll"/>
    48       </xul:hbox>
    49     </content>
    51     <implementation implements="nsIDOMXULTreeElement, nsIDOMXULMultiSelectControlElement">
    53       <!-- ///////////////// nsIDOMXULTreeElement ///////////////// -->
    55       <property name="columns"
    56                 onget="return this.treeBoxObject.columns;"/>
    58       <property name="view"
    59                 onget="return this.treeBoxObject.view;"
    60                 onset="return this.treeBoxObject.view = val;"/>
    62       <property name="body"
    63                 onget="return this.treeBoxObject.treeBody;"/>
    65       <property name="editable"
    66                 onget="return this.getAttribute('editable') == 'true';"
    67                 onset="if (val) this.setAttribute('editable', 'true');
    68                        else this.removeAttribute('editable'); return val;"/>
    70       <!-- ///////////////// nsIDOMXULSelectControlElement ///////////////// -->
    72       <!-- ///////////////// nsIDOMXULMultiSelectControlElement ///////////////// -->
    74       <property name="selType"
    75                 onget="return this.getAttribute('seltype')"
    76                 onset="this.setAttribute('seltype', val); return val;"/>
    78       <property name="currentIndex"
    79                 onget="return this.view ? this.view.selection.currentIndex: - 1;"
    80                 onset="if (this.view) return this.view.selection.currentIndex = val; return val;"/>
    82       <property name="treeBoxObject"
    83                 onget="return this.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);"
    84                 readonly="true"/>
    85 # contentView is obsolete (see bug 202391)
    86       <property name="contentView"
    87                 onget="return this.view; /*.QueryInterface(Components.interfaces.nsITreeContentView)*/"
    88                 readonly="true"/>
    89 # builderView is obsolete (see bug 202393)
    90       <property name="builderView"
    91                 onget="return this.view; /*.QueryInterface(Components.interfaces.nsIXULTreeBuilder)*/"
    92                 readonly="true"/>
    93       <field name="pageUpOrDownMovesSelection">
    94 #ifdef XP_MACOSX
    95         false
    96 #else
    97         true
    98 #endif
    99       </field>
   100       <property name="keepCurrentInView"
   101                 onget="return (this.getAttribute('keepcurrentinview') == 'true');"
   102                 onset="if (val) this.setAttribute('keepcurrentinview', 'true');
   103                        else this.removeAttribute('keepcurrentinview'); return val;"/>
   105       <property name="enableColumnDrag"
   106                 onget="return this.hasAttribute('enableColumnDrag');"
   107                 onset="if (val) this.setAttribute('enableColumnDrag', 'true');
   108                        else this.removeAttribute('enableColumnDrag'); return val;"/>
   110       <field name="_inputField">null</field>
   112       <property name="inputField" readonly="true">
   113         <getter><![CDATA[
   114           if (!this._inputField)
   115             this._inputField = document.getAnonymousElementByAttribute(this, "anonid", "input");
   116           return this._inputField;
   117         ]]></getter>
   118       </property>
   120       <property name="disableKeyNavigation"
   121                 onget="return this.hasAttribute('disableKeyNavigation');"
   122                 onset="if (val) this.setAttribute('disableKeyNavigation', 'true');
   123                        else this.removeAttribute('disableKeyNavigation'); return val;"/>
   125       <field name="_editingRow">-1</field>
   126       <field name="_editingColumn">null</field>
   128       <property name="editingRow" readonly="true"
   129                 onget="return this._editingRow;"/>
   130       <property name="editingColumn" readonly="true"
   131                 onget="return this._editingColumn;"/>
   133       <property name="_selectDelay" 
   134                 onset="this.setAttribute('_selectDelay', val);"
   135                 onget="return this.getAttribute('_selectDelay') || 50;"/>
   136       <field name="_columnsDirty">true</field>
   137       <field name="_lastKeyTime">0</field>
   138       <field name="_incrementalString">""</field>
   140       <method name="_ensureColumnOrder">
   141         <body><![CDATA[
   142           if (!this._columnsDirty)
   143             return;
   145           if (this.columns) {
   146             // update the ordinal position of each column to assure that it is
   147             // an odd number and 2 positions above its next sibling
   148             var cols = [];
   149             var i;
   150             for (var col = this.columns.getFirstColumn(); col; col = col.getNext())
   151               cols.push(col.element);
   152             for (i = 0; i < cols.length; ++i)
   153               cols[i].setAttribute("ordinal", (i*2)+1);
   155             // update the ordinal positions of splitters to even numbers, so that 
   156             // they are in between columns
   157             var splitters = this.getElementsByTagName("splitter");
   158             for (i = 0; i < splitters.length; ++i)
   159               splitters[i].setAttribute("ordinal", (i+1)*2);
   160           }
   161           this._columnsDirty = false;
   162         ]]></body>
   163       </method>
   165       <method name="_reorderColumn">
   166         <parameter name="aColMove"/>
   167         <parameter name="aColBefore"/>
   168         <parameter name="aBefore"/>
   169         <body><![CDATA[
   170           this._ensureColumnOrder();
   172           var i;
   173           var cols = [];
   174           var col = this.columns.getColumnFor(aColBefore);
   175           if (parseInt(aColBefore.ordinal) < parseInt(aColMove.ordinal)) {
   176             if (aBefore)
   177               cols.push(aColBefore);
   178             for (col = col.getNext(); col.element != aColMove;
   179                  col = col.getNext())
   180               cols.push(col.element);
   182             aColMove.ordinal = cols[0].ordinal;
   183             for (i = 0; i < cols.length; ++i)
   184               cols[i].ordinal = parseInt(cols[i].ordinal) + 2;
   185           } else if (aColBefore.ordinal != aColMove.ordinal) {
   186             if (!aBefore)
   187               cols.push(aColBefore);
   188             for (col = col.getPrevious(); col.element != aColMove;
   189                  col = col.getPrevious())
   190               cols.push(col.element);
   192             aColMove.ordinal = cols[0].ordinal;
   193             for (i = 0; i < cols.length; ++i)
   194               cols[i].ordinal = parseInt(cols[i].ordinal) - 2;
   195           }
   196         ]]></body>
   197       </method>
   199       <method name="_getColumnAtX">
   200         <parameter name="aX"/>
   201         <parameter name="aThresh"/>
   202         <parameter name="aPos"/>
   203         <body><![CDATA[
   204           var isRTL = document.defaultView.getComputedStyle(this, "")
   205                               .direction == "rtl";
   207           if (aPos)
   208             aPos.value = isRTL ? "after" : "before";
   210           var columns = [];
   211           var col = this.columns.getFirstColumn();
   212           while (col) {
   213             columns.push(col);
   214             col = col.getNext();
   215           }
   216           if (isRTL)
   217             columns.reverse();
   218           var currentX = this.boxObject.x;
   219           var adjustedX = aX + this.treeBoxObject.horizontalPosition;
   220           for (var i = 0; i < columns.length; ++i) {
   221             col = columns[i];
   222             var cw = col.element.boxObject.width;
   223             if (cw > 0) {
   224               currentX += cw;
   225               if (currentX - (cw * aThresh) > adjustedX)
   226                 return col.element;
   227             }
   228           }
   230           if (aPos)
   231             aPos.value = isRTL ? "before" : "after";
   232           return columns.pop().element;
   233         ]]></body>
   234       </method>
   236       <method name="changeOpenState">
   237         <parameter name="row"/>
   238         <!-- Optional parameter openState == true or false to set. 
   239              No openState param == toggle -->
   240         <parameter name="openState"/>
   241         <body><![CDATA[
   242           if (row < 0 || !this.view.isContainer(row)) {
   243             return false;
   244           }
   245           if (this.view.isContainerOpen(row) != openState) {
   246             this.view.toggleOpenState(row);
   247             if (row == this.currentIndex) {
   248               // Only fire event when current row is expanded or collapsed
   249               // because that's all the assistive technology really cares about.
   250               var event = document.createEvent('Events');
   251               event.initEvent('OpenStateChange', true, true);
   252               this.dispatchEvent(event);
   253             }
   254             return true;
   255           }
   256           return false;
   257         ]]></body>
   258       </method>
   260       <property name="_cellSelType">
   261         <getter>
   262           <![CDATA[
   263             var seltype = this.selType;
   264             if (seltype == "cell" || seltype == "text")
   265               return seltype;
   266             return null;
   267           ]]>
   268         </getter>
   269       </property>
   271       <method name="_getNextColumn">
   272         <parameter name="row"/>
   273         <parameter name="left"/>
   274         <body><![CDATA[
   275           var col = this.view.selection.currentColumn;
   276           if (col) {
   277             col = left ? col.getPrevious() : col.getNext();
   278           }
   279           else {
   280             col = this.columns.getKeyColumn();
   281           }
   282           while (col && (col.width == 0 || !col.selectable ||
   283                  !this.view.isSelectable(row, col)))
   284             col = left ? col.getPrevious() : col.getNext();
   285           return col;
   286         ]]></body>
   287       </method>
   289       <method name="_keyNavigate">
   290         <parameter name="event"/>
   291         <body><![CDATA[
   292           var key = String.fromCharCode(event.charCode).toLowerCase();
   293           if (event.timeStamp - this._lastKeyTime > 1000)
   294             this._incrementalString = key;
   295           else
   296             this._incrementalString += key;
   297           this._lastKeyTime = event.timeStamp;
   299           var length = this._incrementalString.length;
   300           var incrementalString = this._incrementalString;
   301           var charIndex = 1;
   302           while (charIndex < length && incrementalString[charIndex] == incrementalString[charIndex - 1])
   303             charIndex++;
   304           // If all letters in incremental string are same, just try to match the first one
   305           if (charIndex == length) {
   306             length = 1;
   307             incrementalString = incrementalString.substring(0, length);
   308           }
   310           var keyCol = this.columns.getKeyColumn();
   311           var rowCount = this.view.rowCount;
   312           var start = 1;
   314           var c = this.currentIndex;
   315           if (length > 1) {
   316             start = 0;
   317             if (c < 0)
   318               c = 0;
   319           }
   321           for (var i = 0; i < rowCount; i++) {
   322             var l = (i + start + c) % rowCount;
   323             var cellText = this.view.getCellText(l, keyCol);
   324             cellText = cellText.substring(0, length).toLowerCase();
   325             if (cellText == incrementalString)
   326               return l;
   327           }
   328           return -1;
   329         ]]></body>
   330       </method>
   332       <method name="startEditing">
   333         <parameter name="row"/>
   334         <parameter name="column"/>
   335         <body>
   336           <![CDATA[
   337             if (!this.editable)
   338               return false;
   339             if (row < 0 || row >= this.view.rowCount || !column)
   340               return false;
   341             if (column.type != Components.interfaces.nsITreeColumn.TYPE_TEXT ||
   342                 column.cycler || !this.view.isEditable(row, column))
   343               return false;
   345             // Beyond this point, we are going to edit the cell.
   346             if (this._editingColumn)
   347               this.stopEditing();
   349             var input = this.inputField;
   351             var box = this.treeBoxObject;
   352             box.ensureCellIsVisible(row, column);
   354             // Get the coordinates of the text inside the cell.
   355             var textx = {}, texty = {}, textwidth = {}, textheight = {};
   356             var coords = box.getCoordsForCellItem(row, column, "text",
   357                                                   textx, texty, textwidth, textheight);
   359             // Get the coordinates of the cell itself.
   360             var cellx = {}, cellwidth = {};
   361             coords = box.getCoordsForCellItem(row, column, "cell",
   362                                               cellx, {}, cellwidth, {});
   364             // Calculate the top offset of the textbox.
   365             var style = window.getComputedStyle(input, "");
   366             var topadj = parseInt(style.borderTopWidth) + parseInt(style.paddingTop);
   367             input.top = texty.value - topadj;
   369             // The leftside of the textbox is aligned to the left side of the text
   370             // in LTR mode, and left side of the cell in RTL mode.
   371             var left, widthdiff;
   372             if (style.direction == "rtl") {
   373               left = cellx.value;
   374               widthdiff = cellx.value + cellwidth.value - textx.value - textwidth.value;
   375             } else {
   376               left = textx.value;
   377               widthdiff = textx.value - cellx.value;
   378             }
   380             input.left = left;
   381             input.height = textheight.value + topadj +
   382                            parseInt(style.borderBottomWidth) +
   383                            parseInt(style.paddingBottom);
   384             input.width = cellwidth.value - widthdiff;
   385             input.hidden = false;
   387             input.value = this.view.getCellText(row, column);
   388             var selectText = function selectText() {
   389               input.select();
   390               input.inputField.focus();
   391             }
   392             setTimeout(selectText, 0);
   394             this._editingRow = row;
   395             this._editingColumn = column;
   397             this.setAttribute("editing", "true");
   398             return true;
   399           ]]>
   400         </body>
   401       </method>
   403       <method name="stopEditing">
   404         <parameter name="accept"/>
   405         <body>
   406           <![CDATA[
   407             if (!this._editingColumn)
   408               return;
   410             var input = this.inputField;
   411             var editingRow = this._editingRow;
   412             var editingColumn = this._editingColumn;
   413             this._editingRow = -1;
   414             this._editingColumn = null;
   415             if (accept) {
   416               var value = input.value;
   417               this.view.setCellText(editingRow, editingColumn, value);
   418             }
   420             input.hidden = true;
   421             input.value = "";
   422             this.removeAttribute("editing");
   423           ]]>
   424         </body>
   425       </method>
   427       <method name="_moveByOffset">
   428         <parameter name="offset"/>
   429         <parameter name="edge"/>
   430         <parameter name="event"/>
   431         <body>
   432           <![CDATA[
   433             if (this._editingColumn || this.view.rowCount == 0)
   434               return;
   436             if (this._isAccelPressed(event) && this.view.selection.single) {
   437               this.treeBoxObject.scrollByLines(offset);
   438               return;
   439             }
   441             var c = this.currentIndex + offset;
   442             if (offset > 0 ? c > edge : c < edge) {
   443               if (this.view.selection.isSelected(edge) && this.view.selection.count <= 1)
   444                 return;
   445               c = edge;
   446             }
   448             var cellSelType = this._cellSelType;
   449             if (cellSelType) {
   450               var column = this.view.selection.currentColumn;
   451               if (!column)
   452                 return;
   454               while ((offset > 0 ? c <= edge : c >= edge) && !this.view.isSelectable(c, column))
   455                 c += offset;
   456               if (offset > 0 ? c > edge : c < edge)
   457                 return;
   458             }
   460             if (!this._isAccelPressed(event))
   461               this.view.selection.timedSelect(c, this._selectDelay);
   462             else // Ctrl+Up/Down moves the anchor without selecting
   463               this.currentIndex = c;
   464             this.treeBoxObject.ensureRowIsVisible(c);
   465           ]]>
   466         </body>
   467       </method>
   469       <method name="_moveByOffsetShift">
   470         <parameter name="offset"/>
   471         <parameter name="edge"/>
   472         <parameter name="event"/>
   473         <body>
   474           <![CDATA[
   475             if (this._editingColumn || this.view.rowCount == 0)
   476               return;
   478             if (this.view.selection.single) {
   479               this.treeBoxObject.scrollByLines(offset);
   480               return;
   481             }
   483             if (this.view.rowCount == 1 && !this.view.selection.isSelected(0)) {
   484               this.view.selection.timedSelect(0, this._selectDelay);
   485               return;
   486             }
   488             var c = this.currentIndex;
   489             if (c == -1)
   490                 c = 0;
   492             if (c == edge) {
   493               if (this.view.selection.isSelected(c))
   494                 return;
   495             }
   497             // Extend the selection from the existing pivot, if any
   498             this.view.selection.rangedSelect(-1, c + offset,
   499                                              this._isAccelPressed(event));
   500             this.treeBoxObject.ensureRowIsVisible(c + offset);
   502           ]]>
   503         </body>
   504       </method>
   506       <method name="_moveByPage">
   507         <parameter name="offset"/>
   508         <parameter name="edge"/>
   509         <parameter name="event"/>
   510         <body>
   511           <![CDATA[
   512             if (this._editingColumn || this.view.rowCount == 0)
   513               return;
   515             if (this.pageUpOrDownMovesSelection == this._isAccelPressed(event)) {
   516                this.treeBoxObject.scrollByPages(offset);
   517                return;
   518             }
   520             if (this.view.rowCount == 1 && !this.view.selection.isSelected(0)) {
   521               this.view.selection.timedSelect(0, this._selectDelay);
   522               return;
   523             }
   525             var c = this.currentIndex;
   526             if (c == -1)
   527               return;
   529             if (c == edge && this.view.selection.isSelected(c)) {
   530               this.treeBoxObject.ensureRowIsVisible(c);
   531               return;
   532             }
   533             var i = this.treeBoxObject.getFirstVisibleRow();
   534             var p = this.treeBoxObject.getPageLength();
   536             if (offset > 0) {
   537               i += p - 1;
   538               if (c >= i) {
   539                  i = c + p;
   540                  this.treeBoxObject.ensureRowIsVisible(i > edge ? edge : i);
   541               }
   542               i = i > edge ? edge : i;
   544             } else {
   545               if (c <= i) {
   546                  i = c <= p ? 0 : c - p;
   547                  this.treeBoxObject.ensureRowIsVisible(i);
   548               }
   549             }
   550             this.view.selection.timedSelect(i, this._selectDelay);
   551           ]]>
   552         </body>
   553       </method>
   555       <method name="_moveByPageShift">
   556         <parameter name="offset"/>
   557         <parameter name="edge"/>
   558         <parameter name="event"/>
   559         <body>
   560           <![CDATA[
   561             if (this._editingColumn || this.view.rowCount == 0)
   562               return;
   564             if (this.view.rowCount == 1 && !this.view.selection.isSelected(0) &&
   565                 !(this.pageUpOrDownMovesSelection == this._isAccelPressed(event))) {
   566               this.view.selection.timedSelect(0, this._selectDelay);
   567               return;
   568             }
   570             if (this.view.selection.single)
   571               return;
   573             var c = this.currentIndex;
   574             if (c == -1)
   575               return;
   576             if (c == edge && this.view.selection.isSelected(c)) {
   577               this.treeBoxObject.ensureRowIsVisible(edge);
   578               return;
   579             }
   580             var i = this.treeBoxObject.getFirstVisibleRow();
   581             var p = this.treeBoxObject.getPageLength();
   583             if (offset > 0) {
   584               i += p - 1;
   585               if (c >= i) {
   586                  i = c + p;
   587                  this.treeBoxObject.ensureRowIsVisible(i > edge ? edge : i);
   588               }
   589               // Extend the selection from the existing pivot, if any
   590               this.view.selection.rangedSelect(-1, i > edge ? edge : i, this._isAccelPressed(event));
   592             } else {
   594               if (c <= i) {
   595                  i = c <= p ? 0 : c - p;
   596                  this.treeBoxObject.ensureRowIsVisible(i);
   597               }
   598               // Extend the selection from the existing pivot, if any
   599               this.view.selection.rangedSelect(-1, i, this._isAccelPressed(event));
   600             }
   602           ]]>
   603         </body>
   604       </method>
   606       <method name="_moveToEdge">
   607         <parameter name="edge"/>
   608         <parameter name="event"/>
   609         <body>
   610           <![CDATA[
   611             if (this._editingColumn || this.view.rowCount == 0)
   612               return;
   614             if (this.view.selection.isSelected(edge) && this.view.selection.count == 1) {
   615               this.currentIndex = edge;
   616               return;
   617             }
   619             // Normal behaviour is to select the first/last row
   620             if (!this._isAccelPressed(event))
   621               this.view.selection.timedSelect(edge, this._selectDelay);
   623             // In a multiselect tree Ctrl+Home/End moves the anchor
   624             else if (!this.view.selection.single)
   625               this.currentIndex = edge;
   627             this.treeBoxObject.ensureRowIsVisible(edge);
   628           ]]>
   629         </body>
   630       </method>
   632       <method name="_moveToEdgeShift">
   633         <parameter name="edge"/>
   634         <parameter name="event"/>
   635         <body>
   636           <![CDATA[
   637             if (this._editingColumn || this.view.rowCount == 0)
   638               return;
   640             if (this.view.rowCount == 1 && !this.view.selection.isSelected(0)) {
   641               this.view.selection.timedSelect(0, this._selectDelay);
   642               return;
   643             }
   645             if (this.view.selection.single ||
   646                 (this.view.selection.isSelected(edge)) && this.view.selection.isSelected(this.currentIndex))
   647               return;
   649             // Extend the selection from the existing pivot, if any.
   650             // -1 doesn't work here, so using currentIndex instead
   651             this.view.selection.rangedSelect(this.currentIndex, edge, this._isAccelPressed(event));
   653             this.treeBoxObject.ensureRowIsVisible(edge);
   654           ]]>
   655         </body>
   656       </method>
   657       <method name="_handleEnter">
   658         <parameter name="event"/>
   659         <body><![CDATA[
   660           if (this._editingColumn) {
   661             this.stopEditing(true);
   662             this.focus();
   663             return true;
   664           }
   666 #ifdef XP_MACOSX
   667           // See if we can edit the cell.
   668           var row = this.currentIndex;
   669           if (this._cellSelType) {
   670             var column = this.view.selection.currentColumn;
   671             var startedEditing = this.startEditing(row, column);
   672             if (startedEditing)
   673               return true;
   674           }
   675 #endif
   676           return this.changeOpenState(this.currentIndex);
   677         ]]></body>
   678       </method>
   679     </implementation>
   681     <handlers>
   682       <handler event="MozMousePixelScroll" preventdefault="true"/>
   683       <handler event="DOMMouseScroll" preventdefault="true">
   684         <![CDATA[
   685           if (this._editingColumn)
   686             return;
   687           if (event.axis == event.HORIZONTAL_AXIS)
   688             return;
   690           var rows = event.detail;
   691           if (rows == UIEvent.SCROLL_PAGE_UP)
   692             this.treeBoxObject.scrollByPages(-1);
   693           else if (rows == UIEvent.SCROLL_PAGE_DOWN)
   694             this.treeBoxObject.scrollByPages(1);
   695           else
   696             this.treeBoxObject.scrollByLines(rows);
   697         ]]>
   698       </handler>
   699       <handler event="MozSwipeGesture" preventdefault="true">
   700         <![CDATA[
   701           // Figure out which row to show
   702           let targetRow = 0;
   704           // Only handle swipe gestures up and down
   705           switch (event.direction) {
   706             case event.DIRECTION_DOWN:
   707               targetRow = this.view.rowCount - 1;
   708               // Fall through for actual action
   709             case event.DIRECTION_UP:
   710               this.treeBoxObject.ensureRowIsVisible(targetRow);
   711               break;
   712           }
   713         ]]>
   714       </handler>
   715       <handler event="select" phase="target"
   716                action="if (event.originalTarget == this) this.stopEditing(true);"/>
   717       <handler event="focus">
   718         <![CDATA[
   719           this.treeBoxObject.focused = true;
   720           if (this.currentIndex == -1 && this.view.rowCount > 0) {
   721             this.currentIndex = this.treeBoxObject.getFirstVisibleRow();
   722           }
   723           if (this._cellSelType && !this.view.selection.currentColumn) {
   724             var col = this._getNextColumn(this.currentIndex, false);
   725             this.view.selection.currentColumn = col;
   726           }
   727         ]]>
   728       </handler>
   729       <handler event="blur" action="this.treeBoxObject.focused = false;"/>
   730       <handler event="blur" phase="capturing"
   731                action="if (event.originalTarget == this.inputField.inputField) this.stopEditing(true);"/>
   732       <handler event="keydown" keycode="VK_RETURN">
   733         if (this._handleEnter(event)) {
   734           event.stopPropagation();
   735           event.preventDefault();
   736         }
   737       </handler>
   738 #ifndef XP_MACOSX
   739       <!-- Use F2 key to enter text editing. -->
   740       <handler event="keydown" keycode="VK_F2">
   741         <![CDATA[
   742           if (!this._cellSelType)
   743             return;
   744           var row = this.currentIndex;
   745           var column = this.view.selection.currentColumn;
   746           if (this.startEditing(row, column))
   747             event.preventDefault();
   748         ]]>
   749       </handler>
   750 #endif // XP_MACOSX
   752       <handler event="keydown" keycode="VK_ESCAPE">
   753         <![CDATA[
   754           if (this._editingColumn) {
   755             this.stopEditing(false);
   756             this.focus();
   757             event.stopPropagation();
   758             event.preventDefault();
   759           }
   760         ]]>
   761       </handler>
   762       <handler event="keydown" keycode="VK_LEFT">
   763         <![CDATA[
   764          if (this._editingColumn)
   765            return;
   767          var row = this.currentIndex;
   768          if (row < 0)
   769            return;
   771          var cellSelType = this._cellSelType;
   772          var checkContainers = true;
   774          var currentColumn;
   775          if (cellSelType) {
   776            currentColumn = this.view.selection.currentColumn;
   777            if (currentColumn && !currentColumn.primary)
   778              checkContainers = false;
   779          }
   781          if (checkContainers) {
   782            if (this.changeOpenState(this.currentIndex, false)) {
   783              event.preventDefault();
   784              return;
   785            }
   786            else {
   787              var parentIndex = this.view.getParentIndex(this.currentIndex);
   788              if (parentIndex >= 0) {
   789                if (cellSelType && !this.view.isSelectable(parentIndex, currentColumn)) {
   790                  return;
   791                }
   792                this.view.selection.select(parentIndex);
   793                this.treeBoxObject.ensureRowIsVisible(parentIndex);
   794                event.preventDefault();
   795                return;
   796              }
   797            }
   798          }
   800          if (cellSelType) {
   801            var col = this._getNextColumn(row, true);
   802            if (col) {
   803              this.view.selection.currentColumn = col;
   804              this.treeBoxObject.ensureCellIsVisible(row, col);
   805              event.preventDefault();
   806            }
   807          }
   808         ]]>
   809       </handler>
   810       <handler event="keydown" keycode="VK_RIGHT">
   811         <![CDATA[
   812          if (this._editingColumn)
   813            return;
   815           var row = this.currentIndex;
   816           if (row < 0)
   817             return;
   819           var cellSelType = this._cellSelType;
   820           var checkContainers = true;
   822           var currentColumn;
   823           if (cellSelType) {
   824             currentColumn = this.view.selection.currentColumn;
   825             if (currentColumn && !currentColumn.primary)
   826               checkContainers = false;
   827           }
   829           if (checkContainers) {
   830             if (this.changeOpenState(row, true)) {
   831               event.preventDefault();
   832               return;
   833             }
   834             else {
   835               var c = row + 1;
   836               var view = this.view;
   837               if (c < view.rowCount &&
   838                   view.getParentIndex(c) == row) {
   839                 // If already opened, select the first child.
   840                 // The getParentIndex test above ensures that the children
   841                 // are already populated and ready.
   842                 if (cellSelType && !this.view.isSelectable(c , currentColumn)) {
   843                   var col = this._getNextColumn(c, false);
   844                   if (col) {
   845                     this.view.selection.currentColumn = col;
   846                   }
   847                 }
   848                 this.view.selection.timedSelect(c, this._selectDelay);
   849                 this.treeBoxObject.ensureRowIsVisible(c);
   850                 event.preventDefault();
   851                 return;
   852               }
   853             }
   854           }
   856           if (cellSelType) {
   857             var col = this._getNextColumn(row, false);
   858             if (col) {
   859               this.view.selection.currentColumn = col;
   860               this.treeBoxObject.ensureCellIsVisible(row, col);
   861               event.preventDefault();
   862             }
   863           }
   864         ]]>
   865       </handler>
   866       <handler event="keydown" keycode="VK_UP" preventdefault="true"
   867                modifiers="accel any" action="_moveByOffset(-1, 0, event);"/>
   868       <handler event="keydown" keycode="VK_DOWN" preventdefault="true"
   869                modifiers="accel any" action="_moveByOffset(1, this.view.rowCount - 1, event);"/>
   870       <handler event="keydown" keycode="VK_UP" preventdefault="true"
   871                modifiers="accel any, shift" action="_moveByOffsetShift(-1, 0, event);"/>
   872       <handler event="keydown" keycode="VK_DOWN" preventdefault="true"
   873                modifiers="accel any, shift" action="_moveByOffsetShift(1, this.view.rowCount - 1, event);"/>
   874       <handler event="keydown" keycode="VK_PAGE_UP" preventdefault="true"
   875                modifiers="accel any" action="_moveByPage(-1, 0, event);"/>
   876       <handler event="keydown" keycode="VK_PAGE_DOWN" preventdefault="true"
   877                modifiers="accel any" action="_moveByPage(1, this.view.rowCount - 1, event);"/>
   878       <handler event="keydown" keycode="VK_PAGE_UP" preventdefault="true"
   879                modifiers="accel any, shift" action="_moveByPageShift(-1, 0, event);"/>
   880       <handler event="keydown" keycode="VK_PAGE_DOWN" preventdefault="true"
   881                modifiers="accel any, shift" action="_moveByPageShift(1, this.view.rowCount - 1, event);"/>
   882       <handler event="keydown" keycode="VK_HOME" preventdefault="true"
   883                modifiers="accel any" action="_moveToEdge(0, event);"/>
   884       <handler event="keydown" keycode="VK_END" preventdefault="true"
   885                modifiers="accel any" action="_moveToEdge(this.view.rowCount - 1, event);"/>
   886       <handler event="keydown" keycode="VK_HOME" preventdefault="true"
   887                modifiers="accel any, shift" action="_moveToEdgeShift(0, event);"/>
   888       <handler event="keydown" keycode="VK_END" preventdefault="true"
   889                modifiers="accel any, shift" action="_moveToEdgeShift(this.view.rowCount - 1, event);"/>
   890       <handler event="keypress">
   891         <![CDATA[
   892          if (this._editingColumn)
   893            return;
   895          if (event.charCode == ' '.charCodeAt(0)) {
   896            var c = this.currentIndex;
   897            if (!this.view.selection.isSelected(c) ||
   898                (!this.view.selection.single && this._isAccelPressed(event))) {
   899              this.view.selection.toggleSelect(c);
   900              event.preventDefault();
   901            }
   902          }
   903          else if (!this.disableKeyNavigation && event.charCode > 0 &&
   904                   !event.altKey && !this._isAccelPressed(event) &&
   905                   !event.metaKey && !event.ctrlKey) {
   906            var l = this._keyNavigate(event);
   907            if (l >= 0) {
   908              this.view.selection.timedSelect(l, this._selectDelay);
   909              this.treeBoxObject.ensureRowIsVisible(l);
   910            }
   911            event.preventDefault();
   912          }
   913          ]]>
   914       </handler>
   915     </handlers>    
   916   </binding>
   918   <binding id="treecols" role="xul:treecolumns">
   919     <resources>
   920       <stylesheet src="chrome://global/skin/tree.css"/>
   921     </resources>
   922     <content orient="horizontal">
   923       <xul:hbox class="tree-scrollable-columns" flex="1">
   924         <children includes="treecol|splitter"/>
   925       </xul:hbox>
   926       <xul:treecolpicker class="treecol-image" fixed="true" xbl:inherits="tooltiptext=pickertooltiptext"/>
   927     </content>
   928     <implementation>
   929       <constructor><![CDATA[
   930         // Set resizeafter="farthest" on the splitters if nothing else has been
   931         // specified.
   932         Array.forEach(this.getElementsByTagName("splitter"), function (splitter) {
   933           if (!splitter.hasAttribute("resizeafter"))
   934             splitter.setAttribute("resizeafter", "farthest");
   935         });
   936       ]]></constructor>
   937     </implementation>
   938   </binding>
   940   <binding id="treerows" extends="chrome://global/content/bindings/tree.xml#tree-base">
   941     <content>
   942       <xul:hbox flex="1" class="tree-bodybox">
   943         <children/>
   944       </xul:hbox>
   945       <xul:scrollbar height="0" minwidth="0" minheight="0" orient="vertical" xbl:inherits="collapsed=hidevscroll" style="position:relative; z-index:2147483647;"/>
   946     </content>
   947     <handlers>
   948       <handler event="underflow">
   949         <![CDATA[
   950           // Scrollport event orientation
   951           // 0: vertical
   952           // 1: horizontal
   953           // 2: both (not used)
   954           var tree = document.getBindingParent(this);
   955           if (event.detail == 1)
   956             tree.setAttribute("hidehscroll", "true");
   957           else if (event.detail == 0)
   958             tree.setAttribute("hidevscroll", "true");
   959           event.stopPropagation();
   960         ]]>
   961       </handler>
   962       <handler event="overflow">
   963         <![CDATA[
   964           var tree = document.getBindingParent(this);
   965           if (event.detail == 1)
   966             tree.removeAttribute("hidehscroll");
   967           else if (event.detail == 0)
   968             tree.removeAttribute("hidevscroll");
   969           event.stopPropagation();
   970         ]]>
   971       </handler>
   972     </handlers>
   973   </binding>
   975   <binding id="treebody" extends="chrome://global/content/bindings/tree.xml#tree-base">
   976     <implementation>
   977       <constructor>
   978         if ("_ensureColumnOrder" in this.parentNode)
   979           this.parentNode._ensureColumnOrder();
   980       </constructor>
   982       <field name="_lastSelectedRow">
   983         -1
   984       </field>
   985     </implementation>
   986     <handlers>
   987       <!-- If there is no modifier key, we select on mousedown, not
   988            click, so that drags work correctly. -->
   989       <handler event="mousedown" clickcount="1">
   990       <![CDATA[
   991          if (this.parentNode.disabled)
   992            return;
   993          if (((!this._isAccelPressed(event) ||
   994              !this.parentNode.pageUpOrDownMovesSelection) &&
   995              !event.shiftKey && !event.metaKey) ||
   996              this.parentNode.view.selection.single) {
   997            var row = {};
   998            var col = {};
   999            var obj = {};
  1000            var b = this.parentNode.treeBoxObject;
  1001            b.getCellAt(event.clientX, event.clientY, row, col, obj);
  1003            // save off the last selected row
  1004            this._lastSelectedRow = row.value;
  1006            if (row.value == -1)
  1007              return;
  1009            if (obj.value == "twisty")
  1010              return;
  1012            if (col.value) {
  1013              if (col.value.cycler) {
  1014                b.view.cycleCell(row.value, col.value);
  1015                return;
  1016              } else if (col.value.type == Components.interfaces.nsITreeColumn.TYPE_CHECKBOX) {
  1017                if (this.parentNode.editable && col.value.editable &&
  1018                    b.view.isEditable(row.value, col.value)) {
  1019                  var value = b.view.getCellValue(row.value, col.value);
  1020                  value = value == "true" ? "false" : "true";
  1021                  b.view.setCellValue(row.value, col.value, value);
  1022                  return;
  1027            var cellSelType = this.parentNode._cellSelType;
  1028            if (cellSelType == "text" && obj.value != "text" && obj.value != "image")
  1029              return;
  1031            if (cellSelType) {
  1032              if (!col.value.selectable ||
  1033                  !b.view.isSelectable(row.value, col.value)) {
  1034                return;
  1038            if (!b.view.selection.isSelected(row.value)) {
  1039              b.view.selection.select(row.value);
  1040              b.ensureRowIsVisible(row.value);
  1043            if (cellSelType) {
  1044              b.view.selection.currentColumn = col.value;
  1047       ]]>
  1048       </handler>
  1050       <!-- On a click (up+down on the same item), deselect everything
  1051            except this item. -->
  1052       <handler event="click" button="0" clickcount="1">
  1053       <![CDATA[
  1054         if (this.parentNode.disabled)
  1055           return;
  1056         var row = {};
  1057         var col = {};
  1058         var obj = {};
  1059         var b = this.parentNode.treeBoxObject;
  1060         b.getCellAt(event.clientX, event.clientY, row, col, obj);
  1062         if (row.value == -1)
  1063           return;
  1065         if (obj.value == "twisty") {
  1066           if (b.view.selection.currentIndex >= 0 &&
  1067               b.view.isContainerOpen(row.value)) {
  1068             var parentIndex = b.view.getParentIndex(b.view.selection.currentIndex);
  1069             while (parentIndex >= 0 && parentIndex != row.value)
  1070               parentIndex = b.view.getParentIndex(parentIndex);
  1071             if (parentIndex == row.value) {
  1072               var parentSelectable = true;
  1073               if (this.parentNode._cellSelType) {
  1074                 var currentColumn = b.view.selection.currentColumn;
  1075                 if (!b.view.isSelectable(parentIndex, currentColumn))
  1076                   parentSelectable = false;
  1078               if (parentSelectable)
  1079                 b.view.selection.select(parentIndex);
  1082           this.parentNode.changeOpenState(row.value);
  1083           return;
  1086         if (! b.view.selection.single) {
  1087           var augment = this._isAccelPressed(event);
  1088           if (event.shiftKey) {
  1089             b.view.selection.rangedSelect(-1, row.value, augment);
  1090             b.ensureRowIsVisible(row.value);
  1091             return;
  1093           if (augment) {
  1094             b.view.selection.toggleSelect(row.value);
  1095             b.ensureRowIsVisible(row.value);
  1096             b.view.selection.currentIndex = row.value;
  1097             return;
  1101         /* We want to deselect all the selected items except what was
  1102           clicked, UNLESS it was a right-click.  We have to do this
  1103           in click rather than mousedown so that you can drag a
  1104           selected group of items */
  1106         if (!col.value) return;
  1108         // if the last row has changed in between the time we 
  1109         // mousedown and the time we click, don't fire the select handler.
  1110         // see bug #92366
  1111         if (!col.value.cycler && this._lastSelectedRow == row.value &&
  1112             col.value.type != Components.interfaces.nsITreeColumn.TYPE_CHECKBOX) {
  1114           var cellSelType = this.parentNode._cellSelType;
  1115           if (cellSelType == "text" && obj.value != "text" && obj.value != "image")
  1116             return;
  1118           if (cellSelType) {
  1119             if (!col.value.selectable ||
  1120                 !b.view.isSelectable(row.value, col.value)) {
  1121               return;
  1125           b.view.selection.select(row.value);  
  1126           b.ensureRowIsVisible(row.value);
  1128           if (cellSelType) {
  1129             b.view.selection.currentColumn = col.value;
  1132       ]]>
  1133       </handler>
  1135       <!-- double-click -->
  1136       <handler event="click" clickcount="2">
  1137       <![CDATA[
  1138         if (this.parentNode.disabled)
  1139           return;
  1140         var tbo = this.parentNode.treeBoxObject;
  1141         var row = tbo.view.selection.currentIndex;
  1142         if (row == -1)
  1143           return;
  1145         var col = {};
  1146         var obj = {};
  1147         tbo.getCellAt(event.clientX, event.clientY, {}, col, obj);
  1149         if (obj.value != "twisty")
  1150           this.parentNode.startEditing(row, col.value);
  1152         if (this.parentNode._editingColumn || !tbo.view.isContainer(row))
  1153           return;
  1155         // Cyclers and twisties respond to single clicks, not double clicks
  1156         if (col.value != -1 && !col.value.cycler && obj.value != "twisty")
  1157           this.parentNode.changeOpenState(row);
  1158       ]]>
  1159       </handler>
  1161     </handlers>
  1162   </binding>
  1164   <binding id="treecol-base" role="xul:treecolumnitem"
  1165            extends="chrome://global/content/bindings/tree.xml#tree-base">
  1166     <implementation>
  1167       <constructor>
  1168         this.parentNode.parentNode._columnsDirty = true;
  1169       </constructor>
  1171       <property name="ordinal">
  1172         <getter><![CDATA[
  1173           var val = this.getAttribute("ordinal");
  1174           return "" + (val == "" ? 1 : (val == "0" ? 0 : parseInt(val)));
  1175         ]]></getter>
  1176         <setter><![CDATA[
  1177           this.setAttribute("ordinal", val);
  1178           return val;
  1179         ]]></setter>
  1180       </property>
  1182       <property name="_previousVisibleColumn">
  1183         <getter><![CDATA[
  1184           var sib = this.boxObject.previousSibling;
  1185           while (sib) {
  1186             if (sib.localName == "treecol" && sib.boxObject.width > 0 && sib.parentNode == this.parentNode)
  1187               return sib;
  1188             sib = sib.boxObject.previousSibling;
  1190           return null;
  1191         ]]></getter>
  1192       </property>
  1194       <method name="_onDragMouseMove">
  1195         <parameter name="aEvent"/>
  1196         <body><![CDATA[
  1197           var col = document.treecolDragging;
  1198           if (!col) return;
  1200           // determine if we have moved the mouse far enough
  1201           // to initiate a drag
  1202           if (col.mDragGesturing) {
  1203             if (Math.abs(aEvent.clientX - col.mStartDragX) < 5 &&
  1204                 Math.abs(aEvent.clientY - col.mStartDragY) < 5) {
  1205               return;
  1206             } else {
  1207               col.mDragGesturing = false;
  1208               col.setAttribute("dragging", "true");
  1209               window.addEventListener("click", col._onDragMouseClick, true);
  1213           var pos = {};
  1214           var targetCol = col.parentNode.parentNode._getColumnAtX(aEvent.clientX, 0.5, pos);
  1216           // bail if we haven't mousemoved to a different column
  1217           if (col.mTargetCol == targetCol && col.mTargetDir == pos.value)
  1218             return;
  1220           var tree = col.parentNode.parentNode;
  1221           var sib;
  1222           var column;
  1223           if (col.mTargetCol) {
  1224             // remove previous insertbefore/after attributes
  1225             col.mTargetCol.removeAttribute("insertbefore");
  1226             col.mTargetCol.removeAttribute("insertafter");
  1227             column = tree.columns.getColumnFor(col.mTargetCol);
  1228             tree.treeBoxObject.invalidateColumn(column);
  1229             sib = col.mTargetCol._previousVisibleColumn;
  1230             if (sib) {
  1231               sib.removeAttribute("insertafter");
  1232               column = tree.columns.getColumnFor(sib);
  1233               tree.treeBoxObject.invalidateColumn(column);
  1235             col.mTargetCol = null;
  1236             col.mTargetDir = null;
  1239           if (targetCol) {
  1240             // set insertbefore/after attributes
  1241             if (pos.value == "after") {
  1242               targetCol.setAttribute("insertafter", "true");
  1243             } else {
  1244               targetCol.setAttribute("insertbefore", "true");
  1245               sib = targetCol._previousVisibleColumn;
  1246               if (sib) {
  1247                 sib.setAttribute("insertafter", "true");
  1248                 column = tree.columns.getColumnFor(sib);
  1249                 tree.treeBoxObject.invalidateColumn(column);
  1252             column = tree.columns.getColumnFor(targetCol);
  1253             tree.treeBoxObject.invalidateColumn(column);
  1254             col.mTargetCol = targetCol;
  1255             col.mTargetDir = pos.value;
  1257         ]]></body>        
  1258       </method>
  1260       <method name="_onDragMouseUp">
  1261         <parameter name="aEvent"/>
  1262         <body><![CDATA[
  1263           var col = document.treecolDragging;
  1264           if (!col) return;
  1266           if (!col.mDragGesturing) {
  1267             if (col.mTargetCol) {
  1268               // remove insertbefore/after attributes
  1269               var before = col.mTargetCol.hasAttribute("insertbefore");
  1270               col.mTargetCol.removeAttribute(before ? "insertbefore" : "insertafter");
  1272               var sib = col.mTargetCol._previousVisibleColumn;
  1273               if (before && sib) {
  1274                 sib.removeAttribute("insertafter");
  1277               // Move the column only if it will result in a different column
  1278               // ordering
  1279               var move = true;
  1281               // If this is a before move and the previous visible column is
  1282               // the same as the column we're moving, don't move
  1283               if (before && col == sib) {
  1284                 move = false;
  1286               else if (!before && col == col.mTargetCol) {
  1287                 // If this is an after move and the column we're moving is
  1288                 // the same as the target column, don't move.
  1289                 move = false;
  1292               if (move) {
  1293                 col.parentNode.parentNode._reorderColumn(col, col.mTargetCol, before);
  1296               // repaint to remove lines
  1297               col.parentNode.parentNode.treeBoxObject.invalidate();
  1299               col.mTargetCol = null;
  1301           } else
  1302             col.mDragGesturing = false;
  1304           document.treecolDragging = null;
  1305           col.removeAttribute("dragging");
  1307           window.removeEventListener("mousemove", col._onDragMouseMove, true);
  1308           window.removeEventListener("mouseup", col._onDragMouseUp, true);
  1309           // we have to wait for the click event to fire before removing
  1310           // cancelling handler
  1311           var clickHandler = function(handler) { 
  1312             window.removeEventListener("click", handler, true);
  1313           };
  1314           window.setTimeout(clickHandler, 0, col._onDragMouseClick);
  1315         ]]></body>        
  1316       </method>
  1318       <method name="_onDragMouseClick">
  1319         <parameter name="aEvent"/>
  1320         <body><![CDATA[
  1321           // prevent click event from firing after column drag and drop
  1322           aEvent.stopPropagation();
  1323           aEvent.preventDefault();
  1324         ]]></body>        
  1325       </method>
  1326     </implementation>
  1328     <handlers>
  1329       <handler event="mousedown" button="0"><![CDATA[
  1330         if (this.parentNode.parentNode.enableColumnDrag) {
  1331           var xulns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
  1332           var cols = this.parentNode.getElementsByTagNameNS(xulns, "treecol");
  1334           // only start column drag operation if there are at least 2 visible columns
  1335           var visible = 0;
  1336           for (var i = 0; i < cols.length; ++i)
  1337             if (cols[i].boxObject.width > 0) ++visible;
  1339           if (visible > 1) {
  1340             window.addEventListener("mousemove", this._onDragMouseMove, true);
  1341             window.addEventListener("mouseup", this._onDragMouseUp, true);
  1342             document.treecolDragging = this;
  1343             this.mDragGesturing = true;
  1344             this.mStartDragX = event.clientX;
  1345             this.mStartDragY = event.clientY;
  1348       ]]></handler>
  1349       <handler event="click" button="0" phase="target">
  1350         <![CDATA[
  1351           if (event.target != event.originalTarget)
  1352             return;
  1354 #ifdef XP_WIN
  1355           // On Windows multiple clicking on tree columns only cycles one time
  1356           // every 2 clicks.
  1357           if (event.detail % 2 == 0)
  1358             return;
  1359 #endif
  1361           var tree = this.parentNode.parentNode;
  1362           var column = tree.columns.getColumnFor(this);
  1363           tree.view.cycleHeader(column);
  1364         ]]>
  1365       </handler>
  1366     </handlers>
  1367   </binding>
  1369   <binding id="treecol" extends="chrome://global/content/bindings/tree.xml#treecol-base">
  1370     <content>
  1371       <xul:label class="treecol-text" xbl:inherits="crop,value=label" flex="1" crop="right"/>
  1372       <xul:image class="treecol-sortdirection" xbl:inherits="sortDirection,hidden=hideheader"/>
  1373     </content>
  1374   </binding>
  1376   <binding id="treecol-image" extends="chrome://global/content/bindings/tree.xml#treecol-base">
  1377     <content>
  1378       <xul:image class="treecol-icon" xbl:inherits="src"/>
  1379     </content>
  1380   </binding>
  1382   <binding id="columnpicker" display="xul:button" role="xul:button"
  1383            extends="chrome://global/content/bindings/tree.xml#tree-base">
  1384     <content>
  1385       <xul:image class="tree-columnpicker-icon"/>
  1386       <xul:menupopup anonid="popup">
  1387         <xul:menuseparator anonid="menuseparator"/>
  1388         <xul:menuitem anonid="menuitem" label="&restoreColumnOrder.label;"/>
  1389       </xul:menupopup>
  1390     </content>
  1392     <implementation>
  1393       <method name="buildPopup">
  1394         <parameter name="aPopup"/>
  1395         <body>
  1396           <![CDATA[
  1397             // We no longer cache the picker content, remove the old content.
  1398             while (aPopup.childNodes.length > 2)
  1399               aPopup.removeChild(aPopup.firstChild);
  1401             var refChild = aPopup.firstChild;
  1403             var tree = this.parentNode.parentNode;
  1404             for (var currCol = tree.columns.getFirstColumn(); currCol;
  1405                  currCol = currCol.getNext()) {
  1406               // Construct an entry for each column in the row, unless
  1407               // it is not being shown.
  1408               var currElement = currCol.element;
  1409               if (!currElement.hasAttribute("ignoreincolumnpicker")) {
  1410                 var popupChild = document.createElement("menuitem");
  1411                 popupChild.setAttribute("type", "checkbox");
  1412                 var columnName = currElement.getAttribute("display") ||
  1413                                  currElement.getAttribute("label");
  1414                 popupChild.setAttribute("label", columnName);
  1415                 popupChild.setAttribute("colindex", currCol.index);
  1416                 if (currElement.getAttribute("hidden") != "true")
  1417                   popupChild.setAttribute("checked", "true");
  1418                 if (currCol.primary)
  1419                   popupChild.setAttribute("disabled", "true");
  1420                 aPopup.insertBefore(popupChild, refChild);
  1424             var hidden = !tree.enableColumnDrag;
  1425             const anonids = ["menuseparator", "menuitem"];
  1426             for (var i = 0; i < anonids.length; i++) {
  1427               var element = document.getAnonymousElementByAttribute(this, "anonid", anonids[i]);
  1428               element.hidden = hidden;
  1430           ]]>
  1431         </body>
  1432       </method>
  1433     </implementation>
  1435     <handlers>
  1436       <handler event="command">
  1437         <![CDATA[
  1438           if (event.originalTarget == this) {
  1439             var popup = document.getAnonymousElementByAttribute(this, "anonid", "popup");
  1440             this.buildPopup(popup);
  1441             popup.showPopup(this, -1, -1, "popup", "bottomright", "topright");
  1443           else {
  1444             var tree = this.parentNode.parentNode;
  1445             tree.stopEditing(true);
  1446             var menuitem = document.getAnonymousElementByAttribute(this, "anonid", "menuitem");
  1447             if (event.originalTarget == menuitem) {
  1448               tree.columns.restoreNaturalOrder();
  1449               tree._ensureColumnOrder();
  1451             else {
  1452               var colindex = event.originalTarget.getAttribute("colindex");
  1453               var column = tree.columns[colindex];
  1454               if (column) {
  1455                 var element = column.element;
  1456                 if (element.getAttribute("hidden") == "true")
  1457                   element.setAttribute("hidden", "false");
  1458                 else
  1459                   element.setAttribute("hidden", "true");
  1463         ]]>
  1464       </handler>
  1465     </handlers>
  1466   </binding>
  1467 </bindings>

mercurial