Sat, 03 Jan 2015 20:18:00 +0100
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;
1023 }
1024 }
1025 }
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;
1035 }
1036 }
1038 if (!b.view.selection.isSelected(row.value)) {
1039 b.view.selection.select(row.value);
1040 b.ensureRowIsVisible(row.value);
1041 }
1043 if (cellSelType) {
1044 b.view.selection.currentColumn = col.value;
1045 }
1046 }
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;
1077 }
1078 if (parentSelectable)
1079 b.view.selection.select(parentIndex);
1080 }
1081 }
1082 this.parentNode.changeOpenState(row.value);
1083 return;
1084 }
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;
1092 }
1093 if (augment) {
1094 b.view.selection.toggleSelect(row.value);
1095 b.ensureRowIsVisible(row.value);
1096 b.view.selection.currentIndex = row.value;
1097 return;
1098 }
1099 }
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;
1122 }
1123 }
1125 b.view.selection.select(row.value);
1126 b.ensureRowIsVisible(row.value);
1128 if (cellSelType) {
1129 b.view.selection.currentColumn = col.value;
1130 }
1131 }
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;
1189 }
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);
1210 }
1211 }
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);
1234 }
1235 col.mTargetCol = null;
1236 col.mTargetDir = null;
1237 }
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);
1250 }
1251 }
1252 column = tree.columns.getColumnFor(targetCol);
1253 tree.treeBoxObject.invalidateColumn(column);
1254 col.mTargetCol = targetCol;
1255 col.mTargetDir = pos.value;
1256 }
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");
1275 }
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;
1285 }
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;
1290 }
1292 if (move) {
1293 col.parentNode.parentNode._reorderColumn(col, col.mTargetCol, before);
1294 }
1296 // repaint to remove lines
1297 col.parentNode.parentNode.treeBoxObject.invalidate();
1299 col.mTargetCol = null;
1300 }
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;
1346 }
1347 }
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);
1421 }
1422 }
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;
1429 }
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");
1442 }
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();
1450 }
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");
1460 }
1461 }
1462 }
1463 ]]>
1464 </handler>
1465 </handlers>
1466 </binding>
1467 </bindings>