1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/content/widgets/tree.xml Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1468 @@ 1.4 +<?xml version="1.0"?> 1.5 +<!-- This Source Code Form is subject to the terms of the Mozilla Public 1.6 + - License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> 1.8 + 1.9 + 1.10 +<!DOCTYPE bindings [ 1.11 +<!ENTITY % treeDTD SYSTEM "chrome://global/locale/tree.dtd"> 1.12 +%treeDTD; 1.13 +]> 1.14 + 1.15 +<bindings id="treeBindings" 1.16 + xmlns="http://www.mozilla.org/xbl" 1.17 + xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" 1.18 + xmlns:xbl="http://www.mozilla.org/xbl"> 1.19 + 1.20 + <binding id="tree-base" extends="chrome://global/content/bindings/general.xml#basecontrol"> 1.21 + <resources> 1.22 + <stylesheet src="chrome://global/skin/tree.css"/> 1.23 + </resources> 1.24 + <implementation> 1.25 + <method name="_isAccelPressed"> 1.26 + <parameter name="aEvent"/> 1.27 + <body><![CDATA[ 1.28 +# Workaround until bug 302174 is fixed 1.29 +#ifdef XP_MACOSX 1.30 + return aEvent.metaKey; 1.31 +#else 1.32 + return aEvent.ctrlKey; 1.33 +#endif 1.34 + ]]></body> 1.35 + </method> 1.36 + </implementation> 1.37 + </binding> 1.38 + 1.39 + <binding id="tree" extends="chrome://global/content/bindings/tree.xml#tree-base" role="xul:tree"> 1.40 + <content hidevscroll="true" hidehscroll="true" clickthrough="never"> 1.41 + <children includes="treecols"/> 1.42 + <xul:stack class="tree-stack" flex="1"> 1.43 + <xul:treerows class="tree-rows" flex="1" xbl:inherits="hidevscroll"> 1.44 + <children/> 1.45 + </xul:treerows> 1.46 + <xul:textbox anonid="input" class="tree-input" left="0" top="0" hidden="true"/> 1.47 + </xul:stack> 1.48 + <xul:hbox xbl:inherits="collapsed=hidehscroll"> 1.49 + <xul:scrollbar orient="horizontal" flex="1" increment="16" style="position:relative; z-index:2147483647;"/> 1.50 + <xul:scrollcorner xbl:inherits="collapsed=hidevscroll"/> 1.51 + </xul:hbox> 1.52 + </content> 1.53 + 1.54 + <implementation implements="nsIDOMXULTreeElement, nsIDOMXULMultiSelectControlElement"> 1.55 + 1.56 + <!-- ///////////////// nsIDOMXULTreeElement ///////////////// --> 1.57 + 1.58 + <property name="columns" 1.59 + onget="return this.treeBoxObject.columns;"/> 1.60 + 1.61 + <property name="view" 1.62 + onget="return this.treeBoxObject.view;" 1.63 + onset="return this.treeBoxObject.view = val;"/> 1.64 + 1.65 + <property name="body" 1.66 + onget="return this.treeBoxObject.treeBody;"/> 1.67 + 1.68 + <property name="editable" 1.69 + onget="return this.getAttribute('editable') == 'true';" 1.70 + onset="if (val) this.setAttribute('editable', 'true'); 1.71 + else this.removeAttribute('editable'); return val;"/> 1.72 + 1.73 + <!-- ///////////////// nsIDOMXULSelectControlElement ///////////////// --> 1.74 + 1.75 + <!-- ///////////////// nsIDOMXULMultiSelectControlElement ///////////////// --> 1.76 + 1.77 + <property name="selType" 1.78 + onget="return this.getAttribute('seltype')" 1.79 + onset="this.setAttribute('seltype', val); return val;"/> 1.80 + 1.81 + <property name="currentIndex" 1.82 + onget="return this.view ? this.view.selection.currentIndex: - 1;" 1.83 + onset="if (this.view) return this.view.selection.currentIndex = val; return val;"/> 1.84 + 1.85 + <property name="treeBoxObject" 1.86 + onget="return this.boxObject.QueryInterface(Components.interfaces.nsITreeBoxObject);" 1.87 + readonly="true"/> 1.88 +# contentView is obsolete (see bug 202391) 1.89 + <property name="contentView" 1.90 + onget="return this.view; /*.QueryInterface(Components.interfaces.nsITreeContentView)*/" 1.91 + readonly="true"/> 1.92 +# builderView is obsolete (see bug 202393) 1.93 + <property name="builderView" 1.94 + onget="return this.view; /*.QueryInterface(Components.interfaces.nsIXULTreeBuilder)*/" 1.95 + readonly="true"/> 1.96 + <field name="pageUpOrDownMovesSelection"> 1.97 +#ifdef XP_MACOSX 1.98 + false 1.99 +#else 1.100 + true 1.101 +#endif 1.102 + </field> 1.103 + <property name="keepCurrentInView" 1.104 + onget="return (this.getAttribute('keepcurrentinview') == 'true');" 1.105 + onset="if (val) this.setAttribute('keepcurrentinview', 'true'); 1.106 + else this.removeAttribute('keepcurrentinview'); return val;"/> 1.107 + 1.108 + <property name="enableColumnDrag" 1.109 + onget="return this.hasAttribute('enableColumnDrag');" 1.110 + onset="if (val) this.setAttribute('enableColumnDrag', 'true'); 1.111 + else this.removeAttribute('enableColumnDrag'); return val;"/> 1.112 + 1.113 + <field name="_inputField">null</field> 1.114 + 1.115 + <property name="inputField" readonly="true"> 1.116 + <getter><![CDATA[ 1.117 + if (!this._inputField) 1.118 + this._inputField = document.getAnonymousElementByAttribute(this, "anonid", "input"); 1.119 + return this._inputField; 1.120 + ]]></getter> 1.121 + </property> 1.122 + 1.123 + <property name="disableKeyNavigation" 1.124 + onget="return this.hasAttribute('disableKeyNavigation');" 1.125 + onset="if (val) this.setAttribute('disableKeyNavigation', 'true'); 1.126 + else this.removeAttribute('disableKeyNavigation'); return val;"/> 1.127 + 1.128 + <field name="_editingRow">-1</field> 1.129 + <field name="_editingColumn">null</field> 1.130 + 1.131 + <property name="editingRow" readonly="true" 1.132 + onget="return this._editingRow;"/> 1.133 + <property name="editingColumn" readonly="true" 1.134 + onget="return this._editingColumn;"/> 1.135 + 1.136 + <property name="_selectDelay" 1.137 + onset="this.setAttribute('_selectDelay', val);" 1.138 + onget="return this.getAttribute('_selectDelay') || 50;"/> 1.139 + <field name="_columnsDirty">true</field> 1.140 + <field name="_lastKeyTime">0</field> 1.141 + <field name="_incrementalString">""</field> 1.142 + 1.143 + <method name="_ensureColumnOrder"> 1.144 + <body><![CDATA[ 1.145 + if (!this._columnsDirty) 1.146 + return; 1.147 + 1.148 + if (this.columns) { 1.149 + // update the ordinal position of each column to assure that it is 1.150 + // an odd number and 2 positions above its next sibling 1.151 + var cols = []; 1.152 + var i; 1.153 + for (var col = this.columns.getFirstColumn(); col; col = col.getNext()) 1.154 + cols.push(col.element); 1.155 + for (i = 0; i < cols.length; ++i) 1.156 + cols[i].setAttribute("ordinal", (i*2)+1); 1.157 + 1.158 + // update the ordinal positions of splitters to even numbers, so that 1.159 + // they are in between columns 1.160 + var splitters = this.getElementsByTagName("splitter"); 1.161 + for (i = 0; i < splitters.length; ++i) 1.162 + splitters[i].setAttribute("ordinal", (i+1)*2); 1.163 + } 1.164 + this._columnsDirty = false; 1.165 + ]]></body> 1.166 + </method> 1.167 + 1.168 + <method name="_reorderColumn"> 1.169 + <parameter name="aColMove"/> 1.170 + <parameter name="aColBefore"/> 1.171 + <parameter name="aBefore"/> 1.172 + <body><![CDATA[ 1.173 + this._ensureColumnOrder(); 1.174 + 1.175 + var i; 1.176 + var cols = []; 1.177 + var col = this.columns.getColumnFor(aColBefore); 1.178 + if (parseInt(aColBefore.ordinal) < parseInt(aColMove.ordinal)) { 1.179 + if (aBefore) 1.180 + cols.push(aColBefore); 1.181 + for (col = col.getNext(); col.element != aColMove; 1.182 + col = col.getNext()) 1.183 + cols.push(col.element); 1.184 + 1.185 + aColMove.ordinal = cols[0].ordinal; 1.186 + for (i = 0; i < cols.length; ++i) 1.187 + cols[i].ordinal = parseInt(cols[i].ordinal) + 2; 1.188 + } else if (aColBefore.ordinal != aColMove.ordinal) { 1.189 + if (!aBefore) 1.190 + cols.push(aColBefore); 1.191 + for (col = col.getPrevious(); col.element != aColMove; 1.192 + col = col.getPrevious()) 1.193 + cols.push(col.element); 1.194 + 1.195 + aColMove.ordinal = cols[0].ordinal; 1.196 + for (i = 0; i < cols.length; ++i) 1.197 + cols[i].ordinal = parseInt(cols[i].ordinal) - 2; 1.198 + } 1.199 + ]]></body> 1.200 + </method> 1.201 + 1.202 + <method name="_getColumnAtX"> 1.203 + <parameter name="aX"/> 1.204 + <parameter name="aThresh"/> 1.205 + <parameter name="aPos"/> 1.206 + <body><![CDATA[ 1.207 + var isRTL = document.defaultView.getComputedStyle(this, "") 1.208 + .direction == "rtl"; 1.209 + 1.210 + if (aPos) 1.211 + aPos.value = isRTL ? "after" : "before"; 1.212 + 1.213 + var columns = []; 1.214 + var col = this.columns.getFirstColumn(); 1.215 + while (col) { 1.216 + columns.push(col); 1.217 + col = col.getNext(); 1.218 + } 1.219 + if (isRTL) 1.220 + columns.reverse(); 1.221 + var currentX = this.boxObject.x; 1.222 + var adjustedX = aX + this.treeBoxObject.horizontalPosition; 1.223 + for (var i = 0; i < columns.length; ++i) { 1.224 + col = columns[i]; 1.225 + var cw = col.element.boxObject.width; 1.226 + if (cw > 0) { 1.227 + currentX += cw; 1.228 + if (currentX - (cw * aThresh) > adjustedX) 1.229 + return col.element; 1.230 + } 1.231 + } 1.232 + 1.233 + if (aPos) 1.234 + aPos.value = isRTL ? "before" : "after"; 1.235 + return columns.pop().element; 1.236 + ]]></body> 1.237 + </method> 1.238 + 1.239 + <method name="changeOpenState"> 1.240 + <parameter name="row"/> 1.241 + <!-- Optional parameter openState == true or false to set. 1.242 + No openState param == toggle --> 1.243 + <parameter name="openState"/> 1.244 + <body><![CDATA[ 1.245 + if (row < 0 || !this.view.isContainer(row)) { 1.246 + return false; 1.247 + } 1.248 + if (this.view.isContainerOpen(row) != openState) { 1.249 + this.view.toggleOpenState(row); 1.250 + if (row == this.currentIndex) { 1.251 + // Only fire event when current row is expanded or collapsed 1.252 + // because that's all the assistive technology really cares about. 1.253 + var event = document.createEvent('Events'); 1.254 + event.initEvent('OpenStateChange', true, true); 1.255 + this.dispatchEvent(event); 1.256 + } 1.257 + return true; 1.258 + } 1.259 + return false; 1.260 + ]]></body> 1.261 + </method> 1.262 + 1.263 + <property name="_cellSelType"> 1.264 + <getter> 1.265 + <![CDATA[ 1.266 + var seltype = this.selType; 1.267 + if (seltype == "cell" || seltype == "text") 1.268 + return seltype; 1.269 + return null; 1.270 + ]]> 1.271 + </getter> 1.272 + </property> 1.273 + 1.274 + <method name="_getNextColumn"> 1.275 + <parameter name="row"/> 1.276 + <parameter name="left"/> 1.277 + <body><![CDATA[ 1.278 + var col = this.view.selection.currentColumn; 1.279 + if (col) { 1.280 + col = left ? col.getPrevious() : col.getNext(); 1.281 + } 1.282 + else { 1.283 + col = this.columns.getKeyColumn(); 1.284 + } 1.285 + while (col && (col.width == 0 || !col.selectable || 1.286 + !this.view.isSelectable(row, col))) 1.287 + col = left ? col.getPrevious() : col.getNext(); 1.288 + return col; 1.289 + ]]></body> 1.290 + </method> 1.291 + 1.292 + <method name="_keyNavigate"> 1.293 + <parameter name="event"/> 1.294 + <body><![CDATA[ 1.295 + var key = String.fromCharCode(event.charCode).toLowerCase(); 1.296 + if (event.timeStamp - this._lastKeyTime > 1000) 1.297 + this._incrementalString = key; 1.298 + else 1.299 + this._incrementalString += key; 1.300 + this._lastKeyTime = event.timeStamp; 1.301 + 1.302 + var length = this._incrementalString.length; 1.303 + var incrementalString = this._incrementalString; 1.304 + var charIndex = 1; 1.305 + while (charIndex < length && incrementalString[charIndex] == incrementalString[charIndex - 1]) 1.306 + charIndex++; 1.307 + // If all letters in incremental string are same, just try to match the first one 1.308 + if (charIndex == length) { 1.309 + length = 1; 1.310 + incrementalString = incrementalString.substring(0, length); 1.311 + } 1.312 + 1.313 + var keyCol = this.columns.getKeyColumn(); 1.314 + var rowCount = this.view.rowCount; 1.315 + var start = 1; 1.316 + 1.317 + var c = this.currentIndex; 1.318 + if (length > 1) { 1.319 + start = 0; 1.320 + if (c < 0) 1.321 + c = 0; 1.322 + } 1.323 + 1.324 + for (var i = 0; i < rowCount; i++) { 1.325 + var l = (i + start + c) % rowCount; 1.326 + var cellText = this.view.getCellText(l, keyCol); 1.327 + cellText = cellText.substring(0, length).toLowerCase(); 1.328 + if (cellText == incrementalString) 1.329 + return l; 1.330 + } 1.331 + return -1; 1.332 + ]]></body> 1.333 + </method> 1.334 + 1.335 + <method name="startEditing"> 1.336 + <parameter name="row"/> 1.337 + <parameter name="column"/> 1.338 + <body> 1.339 + <![CDATA[ 1.340 + if (!this.editable) 1.341 + return false; 1.342 + if (row < 0 || row >= this.view.rowCount || !column) 1.343 + return false; 1.344 + if (column.type != Components.interfaces.nsITreeColumn.TYPE_TEXT || 1.345 + column.cycler || !this.view.isEditable(row, column)) 1.346 + return false; 1.347 + 1.348 + // Beyond this point, we are going to edit the cell. 1.349 + if (this._editingColumn) 1.350 + this.stopEditing(); 1.351 + 1.352 + var input = this.inputField; 1.353 + 1.354 + var box = this.treeBoxObject; 1.355 + box.ensureCellIsVisible(row, column); 1.356 + 1.357 + // Get the coordinates of the text inside the cell. 1.358 + var textx = {}, texty = {}, textwidth = {}, textheight = {}; 1.359 + var coords = box.getCoordsForCellItem(row, column, "text", 1.360 + textx, texty, textwidth, textheight); 1.361 + 1.362 + // Get the coordinates of the cell itself. 1.363 + var cellx = {}, cellwidth = {}; 1.364 + coords = box.getCoordsForCellItem(row, column, "cell", 1.365 + cellx, {}, cellwidth, {}); 1.366 + 1.367 + // Calculate the top offset of the textbox. 1.368 + var style = window.getComputedStyle(input, ""); 1.369 + var topadj = parseInt(style.borderTopWidth) + parseInt(style.paddingTop); 1.370 + input.top = texty.value - topadj; 1.371 + 1.372 + // The leftside of the textbox is aligned to the left side of the text 1.373 + // in LTR mode, and left side of the cell in RTL mode. 1.374 + var left, widthdiff; 1.375 + if (style.direction == "rtl") { 1.376 + left = cellx.value; 1.377 + widthdiff = cellx.value + cellwidth.value - textx.value - textwidth.value; 1.378 + } else { 1.379 + left = textx.value; 1.380 + widthdiff = textx.value - cellx.value; 1.381 + } 1.382 + 1.383 + input.left = left; 1.384 + input.height = textheight.value + topadj + 1.385 + parseInt(style.borderBottomWidth) + 1.386 + parseInt(style.paddingBottom); 1.387 + input.width = cellwidth.value - widthdiff; 1.388 + input.hidden = false; 1.389 + 1.390 + input.value = this.view.getCellText(row, column); 1.391 + var selectText = function selectText() { 1.392 + input.select(); 1.393 + input.inputField.focus(); 1.394 + } 1.395 + setTimeout(selectText, 0); 1.396 + 1.397 + this._editingRow = row; 1.398 + this._editingColumn = column; 1.399 + 1.400 + this.setAttribute("editing", "true"); 1.401 + return true; 1.402 + ]]> 1.403 + </body> 1.404 + </method> 1.405 + 1.406 + <method name="stopEditing"> 1.407 + <parameter name="accept"/> 1.408 + <body> 1.409 + <![CDATA[ 1.410 + if (!this._editingColumn) 1.411 + return; 1.412 + 1.413 + var input = this.inputField; 1.414 + var editingRow = this._editingRow; 1.415 + var editingColumn = this._editingColumn; 1.416 + this._editingRow = -1; 1.417 + this._editingColumn = null; 1.418 + if (accept) { 1.419 + var value = input.value; 1.420 + this.view.setCellText(editingRow, editingColumn, value); 1.421 + } 1.422 + 1.423 + input.hidden = true; 1.424 + input.value = ""; 1.425 + this.removeAttribute("editing"); 1.426 + ]]> 1.427 + </body> 1.428 + </method> 1.429 + 1.430 + <method name="_moveByOffset"> 1.431 + <parameter name="offset"/> 1.432 + <parameter name="edge"/> 1.433 + <parameter name="event"/> 1.434 + <body> 1.435 + <![CDATA[ 1.436 + if (this._editingColumn || this.view.rowCount == 0) 1.437 + return; 1.438 + 1.439 + if (this._isAccelPressed(event) && this.view.selection.single) { 1.440 + this.treeBoxObject.scrollByLines(offset); 1.441 + return; 1.442 + } 1.443 + 1.444 + var c = this.currentIndex + offset; 1.445 + if (offset > 0 ? c > edge : c < edge) { 1.446 + if (this.view.selection.isSelected(edge) && this.view.selection.count <= 1) 1.447 + return; 1.448 + c = edge; 1.449 + } 1.450 + 1.451 + var cellSelType = this._cellSelType; 1.452 + if (cellSelType) { 1.453 + var column = this.view.selection.currentColumn; 1.454 + if (!column) 1.455 + return; 1.456 + 1.457 + while ((offset > 0 ? c <= edge : c >= edge) && !this.view.isSelectable(c, column)) 1.458 + c += offset; 1.459 + if (offset > 0 ? c > edge : c < edge) 1.460 + return; 1.461 + } 1.462 + 1.463 + if (!this._isAccelPressed(event)) 1.464 + this.view.selection.timedSelect(c, this._selectDelay); 1.465 + else // Ctrl+Up/Down moves the anchor without selecting 1.466 + this.currentIndex = c; 1.467 + this.treeBoxObject.ensureRowIsVisible(c); 1.468 + ]]> 1.469 + </body> 1.470 + </method> 1.471 + 1.472 + <method name="_moveByOffsetShift"> 1.473 + <parameter name="offset"/> 1.474 + <parameter name="edge"/> 1.475 + <parameter name="event"/> 1.476 + <body> 1.477 + <![CDATA[ 1.478 + if (this._editingColumn || this.view.rowCount == 0) 1.479 + return; 1.480 + 1.481 + if (this.view.selection.single) { 1.482 + this.treeBoxObject.scrollByLines(offset); 1.483 + return; 1.484 + } 1.485 + 1.486 + if (this.view.rowCount == 1 && !this.view.selection.isSelected(0)) { 1.487 + this.view.selection.timedSelect(0, this._selectDelay); 1.488 + return; 1.489 + } 1.490 + 1.491 + var c = this.currentIndex; 1.492 + if (c == -1) 1.493 + c = 0; 1.494 + 1.495 + if (c == edge) { 1.496 + if (this.view.selection.isSelected(c)) 1.497 + return; 1.498 + } 1.499 + 1.500 + // Extend the selection from the existing pivot, if any 1.501 + this.view.selection.rangedSelect(-1, c + offset, 1.502 + this._isAccelPressed(event)); 1.503 + this.treeBoxObject.ensureRowIsVisible(c + offset); 1.504 + 1.505 + ]]> 1.506 + </body> 1.507 + </method> 1.508 + 1.509 + <method name="_moveByPage"> 1.510 + <parameter name="offset"/> 1.511 + <parameter name="edge"/> 1.512 + <parameter name="event"/> 1.513 + <body> 1.514 + <![CDATA[ 1.515 + if (this._editingColumn || this.view.rowCount == 0) 1.516 + return; 1.517 + 1.518 + if (this.pageUpOrDownMovesSelection == this._isAccelPressed(event)) { 1.519 + this.treeBoxObject.scrollByPages(offset); 1.520 + return; 1.521 + } 1.522 + 1.523 + if (this.view.rowCount == 1 && !this.view.selection.isSelected(0)) { 1.524 + this.view.selection.timedSelect(0, this._selectDelay); 1.525 + return; 1.526 + } 1.527 + 1.528 + var c = this.currentIndex; 1.529 + if (c == -1) 1.530 + return; 1.531 + 1.532 + if (c == edge && this.view.selection.isSelected(c)) { 1.533 + this.treeBoxObject.ensureRowIsVisible(c); 1.534 + return; 1.535 + } 1.536 + var i = this.treeBoxObject.getFirstVisibleRow(); 1.537 + var p = this.treeBoxObject.getPageLength(); 1.538 + 1.539 + if (offset > 0) { 1.540 + i += p - 1; 1.541 + if (c >= i) { 1.542 + i = c + p; 1.543 + this.treeBoxObject.ensureRowIsVisible(i > edge ? edge : i); 1.544 + } 1.545 + i = i > edge ? edge : i; 1.546 + 1.547 + } else { 1.548 + if (c <= i) { 1.549 + i = c <= p ? 0 : c - p; 1.550 + this.treeBoxObject.ensureRowIsVisible(i); 1.551 + } 1.552 + } 1.553 + this.view.selection.timedSelect(i, this._selectDelay); 1.554 + ]]> 1.555 + </body> 1.556 + </method> 1.557 + 1.558 + <method name="_moveByPageShift"> 1.559 + <parameter name="offset"/> 1.560 + <parameter name="edge"/> 1.561 + <parameter name="event"/> 1.562 + <body> 1.563 + <![CDATA[ 1.564 + if (this._editingColumn || this.view.rowCount == 0) 1.565 + return; 1.566 + 1.567 + if (this.view.rowCount == 1 && !this.view.selection.isSelected(0) && 1.568 + !(this.pageUpOrDownMovesSelection == this._isAccelPressed(event))) { 1.569 + this.view.selection.timedSelect(0, this._selectDelay); 1.570 + return; 1.571 + } 1.572 + 1.573 + if (this.view.selection.single) 1.574 + return; 1.575 + 1.576 + var c = this.currentIndex; 1.577 + if (c == -1) 1.578 + return; 1.579 + if (c == edge && this.view.selection.isSelected(c)) { 1.580 + this.treeBoxObject.ensureRowIsVisible(edge); 1.581 + return; 1.582 + } 1.583 + var i = this.treeBoxObject.getFirstVisibleRow(); 1.584 + var p = this.treeBoxObject.getPageLength(); 1.585 + 1.586 + if (offset > 0) { 1.587 + i += p - 1; 1.588 + if (c >= i) { 1.589 + i = c + p; 1.590 + this.treeBoxObject.ensureRowIsVisible(i > edge ? edge : i); 1.591 + } 1.592 + // Extend the selection from the existing pivot, if any 1.593 + this.view.selection.rangedSelect(-1, i > edge ? edge : i, this._isAccelPressed(event)); 1.594 + 1.595 + } else { 1.596 + 1.597 + if (c <= i) { 1.598 + i = c <= p ? 0 : c - p; 1.599 + this.treeBoxObject.ensureRowIsVisible(i); 1.600 + } 1.601 + // Extend the selection from the existing pivot, if any 1.602 + this.view.selection.rangedSelect(-1, i, this._isAccelPressed(event)); 1.603 + } 1.604 + 1.605 + ]]> 1.606 + </body> 1.607 + </method> 1.608 + 1.609 + <method name="_moveToEdge"> 1.610 + <parameter name="edge"/> 1.611 + <parameter name="event"/> 1.612 + <body> 1.613 + <![CDATA[ 1.614 + if (this._editingColumn || this.view.rowCount == 0) 1.615 + return; 1.616 + 1.617 + if (this.view.selection.isSelected(edge) && this.view.selection.count == 1) { 1.618 + this.currentIndex = edge; 1.619 + return; 1.620 + } 1.621 + 1.622 + // Normal behaviour is to select the first/last row 1.623 + if (!this._isAccelPressed(event)) 1.624 + this.view.selection.timedSelect(edge, this._selectDelay); 1.625 + 1.626 + // In a multiselect tree Ctrl+Home/End moves the anchor 1.627 + else if (!this.view.selection.single) 1.628 + this.currentIndex = edge; 1.629 + 1.630 + this.treeBoxObject.ensureRowIsVisible(edge); 1.631 + ]]> 1.632 + </body> 1.633 + </method> 1.634 + 1.635 + <method name="_moveToEdgeShift"> 1.636 + <parameter name="edge"/> 1.637 + <parameter name="event"/> 1.638 + <body> 1.639 + <![CDATA[ 1.640 + if (this._editingColumn || this.view.rowCount == 0) 1.641 + return; 1.642 + 1.643 + if (this.view.rowCount == 1 && !this.view.selection.isSelected(0)) { 1.644 + this.view.selection.timedSelect(0, this._selectDelay); 1.645 + return; 1.646 + } 1.647 + 1.648 + if (this.view.selection.single || 1.649 + (this.view.selection.isSelected(edge)) && this.view.selection.isSelected(this.currentIndex)) 1.650 + return; 1.651 + 1.652 + // Extend the selection from the existing pivot, if any. 1.653 + // -1 doesn't work here, so using currentIndex instead 1.654 + this.view.selection.rangedSelect(this.currentIndex, edge, this._isAccelPressed(event)); 1.655 + 1.656 + this.treeBoxObject.ensureRowIsVisible(edge); 1.657 + ]]> 1.658 + </body> 1.659 + </method> 1.660 + <method name="_handleEnter"> 1.661 + <parameter name="event"/> 1.662 + <body><![CDATA[ 1.663 + if (this._editingColumn) { 1.664 + this.stopEditing(true); 1.665 + this.focus(); 1.666 + return true; 1.667 + } 1.668 + 1.669 +#ifdef XP_MACOSX 1.670 + // See if we can edit the cell. 1.671 + var row = this.currentIndex; 1.672 + if (this._cellSelType) { 1.673 + var column = this.view.selection.currentColumn; 1.674 + var startedEditing = this.startEditing(row, column); 1.675 + if (startedEditing) 1.676 + return true; 1.677 + } 1.678 +#endif 1.679 + return this.changeOpenState(this.currentIndex); 1.680 + ]]></body> 1.681 + </method> 1.682 + </implementation> 1.683 + 1.684 + <handlers> 1.685 + <handler event="MozMousePixelScroll" preventdefault="true"/> 1.686 + <handler event="DOMMouseScroll" preventdefault="true"> 1.687 + <![CDATA[ 1.688 + if (this._editingColumn) 1.689 + return; 1.690 + if (event.axis == event.HORIZONTAL_AXIS) 1.691 + return; 1.692 + 1.693 + var rows = event.detail; 1.694 + if (rows == UIEvent.SCROLL_PAGE_UP) 1.695 + this.treeBoxObject.scrollByPages(-1); 1.696 + else if (rows == UIEvent.SCROLL_PAGE_DOWN) 1.697 + this.treeBoxObject.scrollByPages(1); 1.698 + else 1.699 + this.treeBoxObject.scrollByLines(rows); 1.700 + ]]> 1.701 + </handler> 1.702 + <handler event="MozSwipeGesture" preventdefault="true"> 1.703 + <![CDATA[ 1.704 + // Figure out which row to show 1.705 + let targetRow = 0; 1.706 + 1.707 + // Only handle swipe gestures up and down 1.708 + switch (event.direction) { 1.709 + case event.DIRECTION_DOWN: 1.710 + targetRow = this.view.rowCount - 1; 1.711 + // Fall through for actual action 1.712 + case event.DIRECTION_UP: 1.713 + this.treeBoxObject.ensureRowIsVisible(targetRow); 1.714 + break; 1.715 + } 1.716 + ]]> 1.717 + </handler> 1.718 + <handler event="select" phase="target" 1.719 + action="if (event.originalTarget == this) this.stopEditing(true);"/> 1.720 + <handler event="focus"> 1.721 + <![CDATA[ 1.722 + this.treeBoxObject.focused = true; 1.723 + if (this.currentIndex == -1 && this.view.rowCount > 0) { 1.724 + this.currentIndex = this.treeBoxObject.getFirstVisibleRow(); 1.725 + } 1.726 + if (this._cellSelType && !this.view.selection.currentColumn) { 1.727 + var col = this._getNextColumn(this.currentIndex, false); 1.728 + this.view.selection.currentColumn = col; 1.729 + } 1.730 + ]]> 1.731 + </handler> 1.732 + <handler event="blur" action="this.treeBoxObject.focused = false;"/> 1.733 + <handler event="blur" phase="capturing" 1.734 + action="if (event.originalTarget == this.inputField.inputField) this.stopEditing(true);"/> 1.735 + <handler event="keydown" keycode="VK_RETURN"> 1.736 + if (this._handleEnter(event)) { 1.737 + event.stopPropagation(); 1.738 + event.preventDefault(); 1.739 + } 1.740 + </handler> 1.741 +#ifndef XP_MACOSX 1.742 + <!-- Use F2 key to enter text editing. --> 1.743 + <handler event="keydown" keycode="VK_F2"> 1.744 + <![CDATA[ 1.745 + if (!this._cellSelType) 1.746 + return; 1.747 + var row = this.currentIndex; 1.748 + var column = this.view.selection.currentColumn; 1.749 + if (this.startEditing(row, column)) 1.750 + event.preventDefault(); 1.751 + ]]> 1.752 + </handler> 1.753 +#endif // XP_MACOSX 1.754 + 1.755 + <handler event="keydown" keycode="VK_ESCAPE"> 1.756 + <![CDATA[ 1.757 + if (this._editingColumn) { 1.758 + this.stopEditing(false); 1.759 + this.focus(); 1.760 + event.stopPropagation(); 1.761 + event.preventDefault(); 1.762 + } 1.763 + ]]> 1.764 + </handler> 1.765 + <handler event="keydown" keycode="VK_LEFT"> 1.766 + <![CDATA[ 1.767 + if (this._editingColumn) 1.768 + return; 1.769 + 1.770 + var row = this.currentIndex; 1.771 + if (row < 0) 1.772 + return; 1.773 + 1.774 + var cellSelType = this._cellSelType; 1.775 + var checkContainers = true; 1.776 + 1.777 + var currentColumn; 1.778 + if (cellSelType) { 1.779 + currentColumn = this.view.selection.currentColumn; 1.780 + if (currentColumn && !currentColumn.primary) 1.781 + checkContainers = false; 1.782 + } 1.783 + 1.784 + if (checkContainers) { 1.785 + if (this.changeOpenState(this.currentIndex, false)) { 1.786 + event.preventDefault(); 1.787 + return; 1.788 + } 1.789 + else { 1.790 + var parentIndex = this.view.getParentIndex(this.currentIndex); 1.791 + if (parentIndex >= 0) { 1.792 + if (cellSelType && !this.view.isSelectable(parentIndex, currentColumn)) { 1.793 + return; 1.794 + } 1.795 + this.view.selection.select(parentIndex); 1.796 + this.treeBoxObject.ensureRowIsVisible(parentIndex); 1.797 + event.preventDefault(); 1.798 + return; 1.799 + } 1.800 + } 1.801 + } 1.802 + 1.803 + if (cellSelType) { 1.804 + var col = this._getNextColumn(row, true); 1.805 + if (col) { 1.806 + this.view.selection.currentColumn = col; 1.807 + this.treeBoxObject.ensureCellIsVisible(row, col); 1.808 + event.preventDefault(); 1.809 + } 1.810 + } 1.811 + ]]> 1.812 + </handler> 1.813 + <handler event="keydown" keycode="VK_RIGHT"> 1.814 + <![CDATA[ 1.815 + if (this._editingColumn) 1.816 + return; 1.817 + 1.818 + var row = this.currentIndex; 1.819 + if (row < 0) 1.820 + return; 1.821 + 1.822 + var cellSelType = this._cellSelType; 1.823 + var checkContainers = true; 1.824 + 1.825 + var currentColumn; 1.826 + if (cellSelType) { 1.827 + currentColumn = this.view.selection.currentColumn; 1.828 + if (currentColumn && !currentColumn.primary) 1.829 + checkContainers = false; 1.830 + } 1.831 + 1.832 + if (checkContainers) { 1.833 + if (this.changeOpenState(row, true)) { 1.834 + event.preventDefault(); 1.835 + return; 1.836 + } 1.837 + else { 1.838 + var c = row + 1; 1.839 + var view = this.view; 1.840 + if (c < view.rowCount && 1.841 + view.getParentIndex(c) == row) { 1.842 + // If already opened, select the first child. 1.843 + // The getParentIndex test above ensures that the children 1.844 + // are already populated and ready. 1.845 + if (cellSelType && !this.view.isSelectable(c , currentColumn)) { 1.846 + var col = this._getNextColumn(c, false); 1.847 + if (col) { 1.848 + this.view.selection.currentColumn = col; 1.849 + } 1.850 + } 1.851 + this.view.selection.timedSelect(c, this._selectDelay); 1.852 + this.treeBoxObject.ensureRowIsVisible(c); 1.853 + event.preventDefault(); 1.854 + return; 1.855 + } 1.856 + } 1.857 + } 1.858 + 1.859 + if (cellSelType) { 1.860 + var col = this._getNextColumn(row, false); 1.861 + if (col) { 1.862 + this.view.selection.currentColumn = col; 1.863 + this.treeBoxObject.ensureCellIsVisible(row, col); 1.864 + event.preventDefault(); 1.865 + } 1.866 + } 1.867 + ]]> 1.868 + </handler> 1.869 + <handler event="keydown" keycode="VK_UP" preventdefault="true" 1.870 + modifiers="accel any" action="_moveByOffset(-1, 0, event);"/> 1.871 + <handler event="keydown" keycode="VK_DOWN" preventdefault="true" 1.872 + modifiers="accel any" action="_moveByOffset(1, this.view.rowCount - 1, event);"/> 1.873 + <handler event="keydown" keycode="VK_UP" preventdefault="true" 1.874 + modifiers="accel any, shift" action="_moveByOffsetShift(-1, 0, event);"/> 1.875 + <handler event="keydown" keycode="VK_DOWN" preventdefault="true" 1.876 + modifiers="accel any, shift" action="_moveByOffsetShift(1, this.view.rowCount - 1, event);"/> 1.877 + <handler event="keydown" keycode="VK_PAGE_UP" preventdefault="true" 1.878 + modifiers="accel any" action="_moveByPage(-1, 0, event);"/> 1.879 + <handler event="keydown" keycode="VK_PAGE_DOWN" preventdefault="true" 1.880 + modifiers="accel any" action="_moveByPage(1, this.view.rowCount - 1, event);"/> 1.881 + <handler event="keydown" keycode="VK_PAGE_UP" preventdefault="true" 1.882 + modifiers="accel any, shift" action="_moveByPageShift(-1, 0, event);"/> 1.883 + <handler event="keydown" keycode="VK_PAGE_DOWN" preventdefault="true" 1.884 + modifiers="accel any, shift" action="_moveByPageShift(1, this.view.rowCount - 1, event);"/> 1.885 + <handler event="keydown" keycode="VK_HOME" preventdefault="true" 1.886 + modifiers="accel any" action="_moveToEdge(0, event);"/> 1.887 + <handler event="keydown" keycode="VK_END" preventdefault="true" 1.888 + modifiers="accel any" action="_moveToEdge(this.view.rowCount - 1, event);"/> 1.889 + <handler event="keydown" keycode="VK_HOME" preventdefault="true" 1.890 + modifiers="accel any, shift" action="_moveToEdgeShift(0, event);"/> 1.891 + <handler event="keydown" keycode="VK_END" preventdefault="true" 1.892 + modifiers="accel any, shift" action="_moveToEdgeShift(this.view.rowCount - 1, event);"/> 1.893 + <handler event="keypress"> 1.894 + <![CDATA[ 1.895 + if (this._editingColumn) 1.896 + return; 1.897 + 1.898 + if (event.charCode == ' '.charCodeAt(0)) { 1.899 + var c = this.currentIndex; 1.900 + if (!this.view.selection.isSelected(c) || 1.901 + (!this.view.selection.single && this._isAccelPressed(event))) { 1.902 + this.view.selection.toggleSelect(c); 1.903 + event.preventDefault(); 1.904 + } 1.905 + } 1.906 + else if (!this.disableKeyNavigation && event.charCode > 0 && 1.907 + !event.altKey && !this._isAccelPressed(event) && 1.908 + !event.metaKey && !event.ctrlKey) { 1.909 + var l = this._keyNavigate(event); 1.910 + if (l >= 0) { 1.911 + this.view.selection.timedSelect(l, this._selectDelay); 1.912 + this.treeBoxObject.ensureRowIsVisible(l); 1.913 + } 1.914 + event.preventDefault(); 1.915 + } 1.916 + ]]> 1.917 + </handler> 1.918 + </handlers> 1.919 + </binding> 1.920 + 1.921 + <binding id="treecols" role="xul:treecolumns"> 1.922 + <resources> 1.923 + <stylesheet src="chrome://global/skin/tree.css"/> 1.924 + </resources> 1.925 + <content orient="horizontal"> 1.926 + <xul:hbox class="tree-scrollable-columns" flex="1"> 1.927 + <children includes="treecol|splitter"/> 1.928 + </xul:hbox> 1.929 + <xul:treecolpicker class="treecol-image" fixed="true" xbl:inherits="tooltiptext=pickertooltiptext"/> 1.930 + </content> 1.931 + <implementation> 1.932 + <constructor><![CDATA[ 1.933 + // Set resizeafter="farthest" on the splitters if nothing else has been 1.934 + // specified. 1.935 + Array.forEach(this.getElementsByTagName("splitter"), function (splitter) { 1.936 + if (!splitter.hasAttribute("resizeafter")) 1.937 + splitter.setAttribute("resizeafter", "farthest"); 1.938 + }); 1.939 + ]]></constructor> 1.940 + </implementation> 1.941 + </binding> 1.942 + 1.943 + <binding id="treerows" extends="chrome://global/content/bindings/tree.xml#tree-base"> 1.944 + <content> 1.945 + <xul:hbox flex="1" class="tree-bodybox"> 1.946 + <children/> 1.947 + </xul:hbox> 1.948 + <xul:scrollbar height="0" minwidth="0" minheight="0" orient="vertical" xbl:inherits="collapsed=hidevscroll" style="position:relative; z-index:2147483647;"/> 1.949 + </content> 1.950 + <handlers> 1.951 + <handler event="underflow"> 1.952 + <![CDATA[ 1.953 + // Scrollport event orientation 1.954 + // 0: vertical 1.955 + // 1: horizontal 1.956 + // 2: both (not used) 1.957 + var tree = document.getBindingParent(this); 1.958 + if (event.detail == 1) 1.959 + tree.setAttribute("hidehscroll", "true"); 1.960 + else if (event.detail == 0) 1.961 + tree.setAttribute("hidevscroll", "true"); 1.962 + event.stopPropagation(); 1.963 + ]]> 1.964 + </handler> 1.965 + <handler event="overflow"> 1.966 + <![CDATA[ 1.967 + var tree = document.getBindingParent(this); 1.968 + if (event.detail == 1) 1.969 + tree.removeAttribute("hidehscroll"); 1.970 + else if (event.detail == 0) 1.971 + tree.removeAttribute("hidevscroll"); 1.972 + event.stopPropagation(); 1.973 + ]]> 1.974 + </handler> 1.975 + </handlers> 1.976 + </binding> 1.977 + 1.978 + <binding id="treebody" extends="chrome://global/content/bindings/tree.xml#tree-base"> 1.979 + <implementation> 1.980 + <constructor> 1.981 + if ("_ensureColumnOrder" in this.parentNode) 1.982 + this.parentNode._ensureColumnOrder(); 1.983 + </constructor> 1.984 + 1.985 + <field name="_lastSelectedRow"> 1.986 + -1 1.987 + </field> 1.988 + </implementation> 1.989 + <handlers> 1.990 + <!-- If there is no modifier key, we select on mousedown, not 1.991 + click, so that drags work correctly. --> 1.992 + <handler event="mousedown" clickcount="1"> 1.993 + <![CDATA[ 1.994 + if (this.parentNode.disabled) 1.995 + return; 1.996 + if (((!this._isAccelPressed(event) || 1.997 + !this.parentNode.pageUpOrDownMovesSelection) && 1.998 + !event.shiftKey && !event.metaKey) || 1.999 + this.parentNode.view.selection.single) { 1.1000 + var row = {}; 1.1001 + var col = {}; 1.1002 + var obj = {}; 1.1003 + var b = this.parentNode.treeBoxObject; 1.1004 + b.getCellAt(event.clientX, event.clientY, row, col, obj); 1.1005 + 1.1006 + // save off the last selected row 1.1007 + this._lastSelectedRow = row.value; 1.1008 + 1.1009 + if (row.value == -1) 1.1010 + return; 1.1011 + 1.1012 + if (obj.value == "twisty") 1.1013 + return; 1.1014 + 1.1015 + if (col.value) { 1.1016 + if (col.value.cycler) { 1.1017 + b.view.cycleCell(row.value, col.value); 1.1018 + return; 1.1019 + } else if (col.value.type == Components.interfaces.nsITreeColumn.TYPE_CHECKBOX) { 1.1020 + if (this.parentNode.editable && col.value.editable && 1.1021 + b.view.isEditable(row.value, col.value)) { 1.1022 + var value = b.view.getCellValue(row.value, col.value); 1.1023 + value = value == "true" ? "false" : "true"; 1.1024 + b.view.setCellValue(row.value, col.value, value); 1.1025 + return; 1.1026 + } 1.1027 + } 1.1028 + } 1.1029 + 1.1030 + var cellSelType = this.parentNode._cellSelType; 1.1031 + if (cellSelType == "text" && obj.value != "text" && obj.value != "image") 1.1032 + return; 1.1033 + 1.1034 + if (cellSelType) { 1.1035 + if (!col.value.selectable || 1.1036 + !b.view.isSelectable(row.value, col.value)) { 1.1037 + return; 1.1038 + } 1.1039 + } 1.1040 + 1.1041 + if (!b.view.selection.isSelected(row.value)) { 1.1042 + b.view.selection.select(row.value); 1.1043 + b.ensureRowIsVisible(row.value); 1.1044 + } 1.1045 + 1.1046 + if (cellSelType) { 1.1047 + b.view.selection.currentColumn = col.value; 1.1048 + } 1.1049 + } 1.1050 + ]]> 1.1051 + </handler> 1.1052 + 1.1053 + <!-- On a click (up+down on the same item), deselect everything 1.1054 + except this item. --> 1.1055 + <handler event="click" button="0" clickcount="1"> 1.1056 + <![CDATA[ 1.1057 + if (this.parentNode.disabled) 1.1058 + return; 1.1059 + var row = {}; 1.1060 + var col = {}; 1.1061 + var obj = {}; 1.1062 + var b = this.parentNode.treeBoxObject; 1.1063 + b.getCellAt(event.clientX, event.clientY, row, col, obj); 1.1064 + 1.1065 + if (row.value == -1) 1.1066 + return; 1.1067 + 1.1068 + if (obj.value == "twisty") { 1.1069 + if (b.view.selection.currentIndex >= 0 && 1.1070 + b.view.isContainerOpen(row.value)) { 1.1071 + var parentIndex = b.view.getParentIndex(b.view.selection.currentIndex); 1.1072 + while (parentIndex >= 0 && parentIndex != row.value) 1.1073 + parentIndex = b.view.getParentIndex(parentIndex); 1.1074 + if (parentIndex == row.value) { 1.1075 + var parentSelectable = true; 1.1076 + if (this.parentNode._cellSelType) { 1.1077 + var currentColumn = b.view.selection.currentColumn; 1.1078 + if (!b.view.isSelectable(parentIndex, currentColumn)) 1.1079 + parentSelectable = false; 1.1080 + } 1.1081 + if (parentSelectable) 1.1082 + b.view.selection.select(parentIndex); 1.1083 + } 1.1084 + } 1.1085 + this.parentNode.changeOpenState(row.value); 1.1086 + return; 1.1087 + } 1.1088 + 1.1089 + if (! b.view.selection.single) { 1.1090 + var augment = this._isAccelPressed(event); 1.1091 + if (event.shiftKey) { 1.1092 + b.view.selection.rangedSelect(-1, row.value, augment); 1.1093 + b.ensureRowIsVisible(row.value); 1.1094 + return; 1.1095 + } 1.1096 + if (augment) { 1.1097 + b.view.selection.toggleSelect(row.value); 1.1098 + b.ensureRowIsVisible(row.value); 1.1099 + b.view.selection.currentIndex = row.value; 1.1100 + return; 1.1101 + } 1.1102 + } 1.1103 + 1.1104 + /* We want to deselect all the selected items except what was 1.1105 + clicked, UNLESS it was a right-click. We have to do this 1.1106 + in click rather than mousedown so that you can drag a 1.1107 + selected group of items */ 1.1108 + 1.1109 + if (!col.value) return; 1.1110 + 1.1111 + // if the last row has changed in between the time we 1.1112 + // mousedown and the time we click, don't fire the select handler. 1.1113 + // see bug #92366 1.1114 + if (!col.value.cycler && this._lastSelectedRow == row.value && 1.1115 + col.value.type != Components.interfaces.nsITreeColumn.TYPE_CHECKBOX) { 1.1116 + 1.1117 + var cellSelType = this.parentNode._cellSelType; 1.1118 + if (cellSelType == "text" && obj.value != "text" && obj.value != "image") 1.1119 + return; 1.1120 + 1.1121 + if (cellSelType) { 1.1122 + if (!col.value.selectable || 1.1123 + !b.view.isSelectable(row.value, col.value)) { 1.1124 + return; 1.1125 + } 1.1126 + } 1.1127 + 1.1128 + b.view.selection.select(row.value); 1.1129 + b.ensureRowIsVisible(row.value); 1.1130 + 1.1131 + if (cellSelType) { 1.1132 + b.view.selection.currentColumn = col.value; 1.1133 + } 1.1134 + } 1.1135 + ]]> 1.1136 + </handler> 1.1137 + 1.1138 + <!-- double-click --> 1.1139 + <handler event="click" clickcount="2"> 1.1140 + <![CDATA[ 1.1141 + if (this.parentNode.disabled) 1.1142 + return; 1.1143 + var tbo = this.parentNode.treeBoxObject; 1.1144 + var row = tbo.view.selection.currentIndex; 1.1145 + if (row == -1) 1.1146 + return; 1.1147 + 1.1148 + var col = {}; 1.1149 + var obj = {}; 1.1150 + tbo.getCellAt(event.clientX, event.clientY, {}, col, obj); 1.1151 + 1.1152 + if (obj.value != "twisty") 1.1153 + this.parentNode.startEditing(row, col.value); 1.1154 + 1.1155 + if (this.parentNode._editingColumn || !tbo.view.isContainer(row)) 1.1156 + return; 1.1157 + 1.1158 + // Cyclers and twisties respond to single clicks, not double clicks 1.1159 + if (col.value != -1 && !col.value.cycler && obj.value != "twisty") 1.1160 + this.parentNode.changeOpenState(row); 1.1161 + ]]> 1.1162 + </handler> 1.1163 + 1.1164 + </handlers> 1.1165 + </binding> 1.1166 + 1.1167 + <binding id="treecol-base" role="xul:treecolumnitem" 1.1168 + extends="chrome://global/content/bindings/tree.xml#tree-base"> 1.1169 + <implementation> 1.1170 + <constructor> 1.1171 + this.parentNode.parentNode._columnsDirty = true; 1.1172 + </constructor> 1.1173 + 1.1174 + <property name="ordinal"> 1.1175 + <getter><![CDATA[ 1.1176 + var val = this.getAttribute("ordinal"); 1.1177 + return "" + (val == "" ? 1 : (val == "0" ? 0 : parseInt(val))); 1.1178 + ]]></getter> 1.1179 + <setter><![CDATA[ 1.1180 + this.setAttribute("ordinal", val); 1.1181 + return val; 1.1182 + ]]></setter> 1.1183 + </property> 1.1184 + 1.1185 + <property name="_previousVisibleColumn"> 1.1186 + <getter><![CDATA[ 1.1187 + var sib = this.boxObject.previousSibling; 1.1188 + while (sib) { 1.1189 + if (sib.localName == "treecol" && sib.boxObject.width > 0 && sib.parentNode == this.parentNode) 1.1190 + return sib; 1.1191 + sib = sib.boxObject.previousSibling; 1.1192 + } 1.1193 + return null; 1.1194 + ]]></getter> 1.1195 + </property> 1.1196 + 1.1197 + <method name="_onDragMouseMove"> 1.1198 + <parameter name="aEvent"/> 1.1199 + <body><![CDATA[ 1.1200 + var col = document.treecolDragging; 1.1201 + if (!col) return; 1.1202 + 1.1203 + // determine if we have moved the mouse far enough 1.1204 + // to initiate a drag 1.1205 + if (col.mDragGesturing) { 1.1206 + if (Math.abs(aEvent.clientX - col.mStartDragX) < 5 && 1.1207 + Math.abs(aEvent.clientY - col.mStartDragY) < 5) { 1.1208 + return; 1.1209 + } else { 1.1210 + col.mDragGesturing = false; 1.1211 + col.setAttribute("dragging", "true"); 1.1212 + window.addEventListener("click", col._onDragMouseClick, true); 1.1213 + } 1.1214 + } 1.1215 + 1.1216 + var pos = {}; 1.1217 + var targetCol = col.parentNode.parentNode._getColumnAtX(aEvent.clientX, 0.5, pos); 1.1218 + 1.1219 + // bail if we haven't mousemoved to a different column 1.1220 + if (col.mTargetCol == targetCol && col.mTargetDir == pos.value) 1.1221 + return; 1.1222 + 1.1223 + var tree = col.parentNode.parentNode; 1.1224 + var sib; 1.1225 + var column; 1.1226 + if (col.mTargetCol) { 1.1227 + // remove previous insertbefore/after attributes 1.1228 + col.mTargetCol.removeAttribute("insertbefore"); 1.1229 + col.mTargetCol.removeAttribute("insertafter"); 1.1230 + column = tree.columns.getColumnFor(col.mTargetCol); 1.1231 + tree.treeBoxObject.invalidateColumn(column); 1.1232 + sib = col.mTargetCol._previousVisibleColumn; 1.1233 + if (sib) { 1.1234 + sib.removeAttribute("insertafter"); 1.1235 + column = tree.columns.getColumnFor(sib); 1.1236 + tree.treeBoxObject.invalidateColumn(column); 1.1237 + } 1.1238 + col.mTargetCol = null; 1.1239 + col.mTargetDir = null; 1.1240 + } 1.1241 + 1.1242 + if (targetCol) { 1.1243 + // set insertbefore/after attributes 1.1244 + if (pos.value == "after") { 1.1245 + targetCol.setAttribute("insertafter", "true"); 1.1246 + } else { 1.1247 + targetCol.setAttribute("insertbefore", "true"); 1.1248 + sib = targetCol._previousVisibleColumn; 1.1249 + if (sib) { 1.1250 + sib.setAttribute("insertafter", "true"); 1.1251 + column = tree.columns.getColumnFor(sib); 1.1252 + tree.treeBoxObject.invalidateColumn(column); 1.1253 + } 1.1254 + } 1.1255 + column = tree.columns.getColumnFor(targetCol); 1.1256 + tree.treeBoxObject.invalidateColumn(column); 1.1257 + col.mTargetCol = targetCol; 1.1258 + col.mTargetDir = pos.value; 1.1259 + } 1.1260 + ]]></body> 1.1261 + </method> 1.1262 + 1.1263 + <method name="_onDragMouseUp"> 1.1264 + <parameter name="aEvent"/> 1.1265 + <body><![CDATA[ 1.1266 + var col = document.treecolDragging; 1.1267 + if (!col) return; 1.1268 + 1.1269 + if (!col.mDragGesturing) { 1.1270 + if (col.mTargetCol) { 1.1271 + // remove insertbefore/after attributes 1.1272 + var before = col.mTargetCol.hasAttribute("insertbefore"); 1.1273 + col.mTargetCol.removeAttribute(before ? "insertbefore" : "insertafter"); 1.1274 + 1.1275 + var sib = col.mTargetCol._previousVisibleColumn; 1.1276 + if (before && sib) { 1.1277 + sib.removeAttribute("insertafter"); 1.1278 + } 1.1279 + 1.1280 + // Move the column only if it will result in a different column 1.1281 + // ordering 1.1282 + var move = true; 1.1283 + 1.1284 + // If this is a before move and the previous visible column is 1.1285 + // the same as the column we're moving, don't move 1.1286 + if (before && col == sib) { 1.1287 + move = false; 1.1288 + } 1.1289 + else if (!before && col == col.mTargetCol) { 1.1290 + // If this is an after move and the column we're moving is 1.1291 + // the same as the target column, don't move. 1.1292 + move = false; 1.1293 + } 1.1294 + 1.1295 + if (move) { 1.1296 + col.parentNode.parentNode._reorderColumn(col, col.mTargetCol, before); 1.1297 + } 1.1298 + 1.1299 + // repaint to remove lines 1.1300 + col.parentNode.parentNode.treeBoxObject.invalidate(); 1.1301 + 1.1302 + col.mTargetCol = null; 1.1303 + } 1.1304 + } else 1.1305 + col.mDragGesturing = false; 1.1306 + 1.1307 + document.treecolDragging = null; 1.1308 + col.removeAttribute("dragging"); 1.1309 + 1.1310 + window.removeEventListener("mousemove", col._onDragMouseMove, true); 1.1311 + window.removeEventListener("mouseup", col._onDragMouseUp, true); 1.1312 + // we have to wait for the click event to fire before removing 1.1313 + // cancelling handler 1.1314 + var clickHandler = function(handler) { 1.1315 + window.removeEventListener("click", handler, true); 1.1316 + }; 1.1317 + window.setTimeout(clickHandler, 0, col._onDragMouseClick); 1.1318 + ]]></body> 1.1319 + </method> 1.1320 + 1.1321 + <method name="_onDragMouseClick"> 1.1322 + <parameter name="aEvent"/> 1.1323 + <body><![CDATA[ 1.1324 + // prevent click event from firing after column drag and drop 1.1325 + aEvent.stopPropagation(); 1.1326 + aEvent.preventDefault(); 1.1327 + ]]></body> 1.1328 + </method> 1.1329 + </implementation> 1.1330 + 1.1331 + <handlers> 1.1332 + <handler event="mousedown" button="0"><![CDATA[ 1.1333 + if (this.parentNode.parentNode.enableColumnDrag) { 1.1334 + var xulns = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; 1.1335 + var cols = this.parentNode.getElementsByTagNameNS(xulns, "treecol"); 1.1336 + 1.1337 + // only start column drag operation if there are at least 2 visible columns 1.1338 + var visible = 0; 1.1339 + for (var i = 0; i < cols.length; ++i) 1.1340 + if (cols[i].boxObject.width > 0) ++visible; 1.1341 + 1.1342 + if (visible > 1) { 1.1343 + window.addEventListener("mousemove", this._onDragMouseMove, true); 1.1344 + window.addEventListener("mouseup", this._onDragMouseUp, true); 1.1345 + document.treecolDragging = this; 1.1346 + this.mDragGesturing = true; 1.1347 + this.mStartDragX = event.clientX; 1.1348 + this.mStartDragY = event.clientY; 1.1349 + } 1.1350 + } 1.1351 + ]]></handler> 1.1352 + <handler event="click" button="0" phase="target"> 1.1353 + <![CDATA[ 1.1354 + if (event.target != event.originalTarget) 1.1355 + return; 1.1356 + 1.1357 +#ifdef XP_WIN 1.1358 + // On Windows multiple clicking on tree columns only cycles one time 1.1359 + // every 2 clicks. 1.1360 + if (event.detail % 2 == 0) 1.1361 + return; 1.1362 +#endif 1.1363 + 1.1364 + var tree = this.parentNode.parentNode; 1.1365 + var column = tree.columns.getColumnFor(this); 1.1366 + tree.view.cycleHeader(column); 1.1367 + ]]> 1.1368 + </handler> 1.1369 + </handlers> 1.1370 + </binding> 1.1371 + 1.1372 + <binding id="treecol" extends="chrome://global/content/bindings/tree.xml#treecol-base"> 1.1373 + <content> 1.1374 + <xul:label class="treecol-text" xbl:inherits="crop,value=label" flex="1" crop="right"/> 1.1375 + <xul:image class="treecol-sortdirection" xbl:inherits="sortDirection,hidden=hideheader"/> 1.1376 + </content> 1.1377 + </binding> 1.1378 + 1.1379 + <binding id="treecol-image" extends="chrome://global/content/bindings/tree.xml#treecol-base"> 1.1380 + <content> 1.1381 + <xul:image class="treecol-icon" xbl:inherits="src"/> 1.1382 + </content> 1.1383 + </binding> 1.1384 + 1.1385 + <binding id="columnpicker" display="xul:button" role="xul:button" 1.1386 + extends="chrome://global/content/bindings/tree.xml#tree-base"> 1.1387 + <content> 1.1388 + <xul:image class="tree-columnpicker-icon"/> 1.1389 + <xul:menupopup anonid="popup"> 1.1390 + <xul:menuseparator anonid="menuseparator"/> 1.1391 + <xul:menuitem anonid="menuitem" label="&restoreColumnOrder.label;"/> 1.1392 + </xul:menupopup> 1.1393 + </content> 1.1394 + 1.1395 + <implementation> 1.1396 + <method name="buildPopup"> 1.1397 + <parameter name="aPopup"/> 1.1398 + <body> 1.1399 + <![CDATA[ 1.1400 + // We no longer cache the picker content, remove the old content. 1.1401 + while (aPopup.childNodes.length > 2) 1.1402 + aPopup.removeChild(aPopup.firstChild); 1.1403 + 1.1404 + var refChild = aPopup.firstChild; 1.1405 + 1.1406 + var tree = this.parentNode.parentNode; 1.1407 + for (var currCol = tree.columns.getFirstColumn(); currCol; 1.1408 + currCol = currCol.getNext()) { 1.1409 + // Construct an entry for each column in the row, unless 1.1410 + // it is not being shown. 1.1411 + var currElement = currCol.element; 1.1412 + if (!currElement.hasAttribute("ignoreincolumnpicker")) { 1.1413 + var popupChild = document.createElement("menuitem"); 1.1414 + popupChild.setAttribute("type", "checkbox"); 1.1415 + var columnName = currElement.getAttribute("display") || 1.1416 + currElement.getAttribute("label"); 1.1417 + popupChild.setAttribute("label", columnName); 1.1418 + popupChild.setAttribute("colindex", currCol.index); 1.1419 + if (currElement.getAttribute("hidden") != "true") 1.1420 + popupChild.setAttribute("checked", "true"); 1.1421 + if (currCol.primary) 1.1422 + popupChild.setAttribute("disabled", "true"); 1.1423 + aPopup.insertBefore(popupChild, refChild); 1.1424 + } 1.1425 + } 1.1426 + 1.1427 + var hidden = !tree.enableColumnDrag; 1.1428 + const anonids = ["menuseparator", "menuitem"]; 1.1429 + for (var i = 0; i < anonids.length; i++) { 1.1430 + var element = document.getAnonymousElementByAttribute(this, "anonid", anonids[i]); 1.1431 + element.hidden = hidden; 1.1432 + } 1.1433 + ]]> 1.1434 + </body> 1.1435 + </method> 1.1436 + </implementation> 1.1437 + 1.1438 + <handlers> 1.1439 + <handler event="command"> 1.1440 + <![CDATA[ 1.1441 + if (event.originalTarget == this) { 1.1442 + var popup = document.getAnonymousElementByAttribute(this, "anonid", "popup"); 1.1443 + this.buildPopup(popup); 1.1444 + popup.showPopup(this, -1, -1, "popup", "bottomright", "topright"); 1.1445 + } 1.1446 + else { 1.1447 + var tree = this.parentNode.parentNode; 1.1448 + tree.stopEditing(true); 1.1449 + var menuitem = document.getAnonymousElementByAttribute(this, "anonid", "menuitem"); 1.1450 + if (event.originalTarget == menuitem) { 1.1451 + tree.columns.restoreNaturalOrder(); 1.1452 + tree._ensureColumnOrder(); 1.1453 + } 1.1454 + else { 1.1455 + var colindex = event.originalTarget.getAttribute("colindex"); 1.1456 + var column = tree.columns[colindex]; 1.1457 + if (column) { 1.1458 + var element = column.element; 1.1459 + if (element.getAttribute("hidden") == "true") 1.1460 + element.setAttribute("hidden", "false"); 1.1461 + else 1.1462 + element.setAttribute("hidden", "true"); 1.1463 + } 1.1464 + } 1.1465 + } 1.1466 + ]]> 1.1467 + </handler> 1.1468 + </handlers> 1.1469 + </binding> 1.1470 +</bindings> 1.1471 +