OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007 Apple Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * | 7 * |
8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
222 while (nextSelectedElement && !nextSelectedElement.selectabl
e) | 222 while (nextSelectedElement && !nextSelectedElement.selectabl
e) |
223 nextSelectedElement = nextSelectedElement.parent; | 223 nextSelectedElement = nextSelectedElement.parent; |
224 handled = nextSelectedElement ? true : false; | 224 handled = nextSelectedElement ? true : false; |
225 } else if (this.selectedTreeElement.parent) | 225 } else if (this.selectedTreeElement.parent) |
226 this.selectedTreeElement.parent.collapse(); | 226 this.selectedTreeElement.parent.collapse(); |
227 } | 227 } |
228 } else if (event.keyIdentifier === "Right") { | 228 } else if (event.keyIdentifier === "Right") { |
229 if (!this.selectedTreeElement.revealed()) { | 229 if (!this.selectedTreeElement.revealed()) { |
230 this.selectedTreeElement.reveal(); | 230 this.selectedTreeElement.reveal(); |
231 handled = true; | 231 handled = true; |
232 } else if (this.selectedTreeElement.hasChildren) { | 232 } else if (this.selectedTreeElement._expandable) { |
233 handled = true; | 233 handled = true; |
234 if (this.selectedTreeElement.expanded) { | 234 if (this.selectedTreeElement.expanded) { |
235 nextSelectedElement = this.selectedTreeElement.firstChild(); | 235 nextSelectedElement = this.selectedTreeElement.firstChild(); |
236 while (nextSelectedElement && !nextSelectedElement.selectabl
e) | 236 while (nextSelectedElement && !nextSelectedElement.selectabl
e) |
237 nextSelectedElement = nextSelectedElement.nextSibling; | 237 nextSelectedElement = nextSelectedElement.nextSibling; |
238 handled = nextSelectedElement ? true : false; | 238 handled = nextSelectedElement ? true : false; |
239 } else { | 239 } else { |
240 if (event.altKey) | 240 if (event.altKey) |
241 this.selectedTreeElement.expandRecursively(); | 241 this.selectedTreeElement.expandRecursively(); |
242 else | 242 else |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
281 this._renderSelection = true; | 281 this._renderSelection = true; |
282 } | 282 } |
283 | 283 |
284 TreeOutlineInShadow.prototype = { | 284 TreeOutlineInShadow.prototype = { |
285 __proto__: TreeOutline.prototype | 285 __proto__: TreeOutline.prototype |
286 } | 286 } |
287 | 287 |
288 /** | 288 /** |
289 * @constructor | 289 * @constructor |
290 * @param {(string|!Node)=} title | 290 * @param {(string|!Node)=} title |
291 * @param {boolean=} hasChildren | 291 * @param {boolean=} expandable |
292 */ | 292 */ |
293 function TreeElement(title, hasChildren) | 293 function TreeElement(title, expandable) |
294 { | 294 { |
295 /** @type {?TreeOutline} */ | 295 /** @type {?TreeOutline} */ |
296 this.treeOutline = null; | 296 this.treeOutline = null; |
297 this.parent = null; | 297 this.parent = null; |
298 this.previousSibling = null; | 298 this.previousSibling = null; |
299 this.nextSibling = null; | 299 this.nextSibling = null; |
300 | 300 |
301 this._listItemNode = createElement("li"); | 301 this._listItemNode = createElement("li"); |
302 this._listItemNode.treeElement = this; | 302 this._listItemNode.treeElement = this; |
303 if (title) | 303 if (title) |
304 this.title = title; | 304 this.title = title; |
305 if (typeof title === "string") | 305 if (typeof title === "string") |
306 this.tooltip = title; | 306 this.tooltip = title; |
307 this._listItemNode.addEventListener("mousedown", this._handleMouseDown.bind(
this), false); | 307 this._listItemNode.addEventListener("mousedown", this._handleMouseDown.bind(
this), false); |
308 this._listItemNode.addEventListener("selectstart", this._treeElementSelectSt
art.bind(this), false); | 308 this._listItemNode.addEventListener("selectstart", this._treeElementSelectSt
art.bind(this), false); |
309 this._listItemNode.addEventListener("click", this._treeElementToggled.bind(t
his), false); | 309 this._listItemNode.addEventListener("click", this._treeElementToggled.bind(t
his), false); |
310 this._listItemNode.addEventListener("dblclick", this._handleDoubleClick.bind
(this), false); | 310 this._listItemNode.addEventListener("dblclick", this._handleDoubleClick.bind
(this), false); |
311 | 311 |
312 this._childrenListNode = createElement("ol"); | 312 this._childrenListNode = createElement("ol"); |
313 this._childrenListNode.parentTreeElement = this; | 313 this._childrenListNode.parentTreeElement = this; |
314 this._childrenListNode.classList.add("children"); | 314 this._childrenListNode.classList.add("children"); |
315 | 315 |
316 this._hidden = false; | 316 this._hidden = false; |
317 this._selectable = true; | 317 this._selectable = true; |
318 this.expanded = false; | 318 this.expanded = false; |
319 this.selected = false; | 319 this.selected = false; |
320 this.hasChildren = hasChildren || false; | 320 this.setExpandable(expandable || false); |
321 } | 321 } |
322 | 322 |
323 /** @const */ | 323 /** @const */ |
324 TreeElement._ArrowToggleWidth = 10; | 324 TreeElement._ArrowToggleWidth = 10; |
325 | 325 |
326 TreeElement.prototype = { | 326 TreeElement.prototype = { |
327 /** | 327 /** |
328 * @param {?TreeElement} ancestor | 328 * @param {?TreeElement} ancestor |
329 * @return {boolean} | 329 * @return {boolean} |
330 */ | 330 */ |
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
443 var nextChild = this._children[index]; | 443 var nextChild = this._children[index]; |
444 if (nextChild) { | 444 if (nextChild) { |
445 nextChild.previousSibling = child; | 445 nextChild.previousSibling = child; |
446 child.nextSibling = nextChild; | 446 child.nextSibling = nextChild; |
447 } else { | 447 } else { |
448 child.nextSibling = null; | 448 child.nextSibling = null; |
449 } | 449 } |
450 | 450 |
451 this._children.splice(index, 0, child); | 451 this._children.splice(index, 0, child); |
452 | 452 |
453 this.hasChildren = true; | 453 this.setExpandable(true); |
454 child.parent = this; | 454 child.parent = this; |
455 | 455 |
456 if (this.treeOutline) | 456 if (this.treeOutline) |
457 this.treeOutline._bindTreeElement(child); | 457 this.treeOutline._bindTreeElement(child); |
458 for (var current = child.firstChild(); this.treeOutline && current; curr
ent = current.traverseNextTreeElement(false, child, true)) | 458 for (var current = child.firstChild(); this.treeOutline && current; curr
ent = current.traverseNextTreeElement(false, child, true)) |
459 this.treeOutline._bindTreeElement(current); | 459 this.treeOutline._bindTreeElement(current); |
460 child.onattach(); | 460 child.onattach(); |
461 child._ensureSelection(); | 461 child._ensureSelection(); |
462 if (this.treeOutline) | 462 if (this.treeOutline) |
463 this.treeOutline.dispatchEventToListeners(TreeOutline.Events.Element
Attached, child); | 463 this.treeOutline.dispatchEventToListeners(TreeOutline.Events.Element
Attached, child); |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
586 * @param {string} x | 586 * @param {string} x |
587 */ | 587 */ |
588 set tooltip(x) | 588 set tooltip(x) |
589 { | 589 { |
590 if (x) | 590 if (x) |
591 this._listItemNode.setAttribute("title", x); | 591 this._listItemNode.setAttribute("title", x); |
592 else | 592 else |
593 this._listItemNode.removeAttribute("title"); | 593 this._listItemNode.removeAttribute("title"); |
594 }, | 594 }, |
595 | 595 |
596 get hasChildren() | 596 /** |
| 597 * @return {boolean} |
| 598 */ |
| 599 isExpandable: function() |
597 { | 600 { |
598 return this._hasChildren; | 601 return this._expandable; |
599 }, | 602 }, |
600 | 603 |
601 /** | 604 /** |
602 * Used inside subclasses. | 605 * @param {boolean} expandable |
603 * | |
604 * @param {boolean} hasChildren | |
605 */ | 606 */ |
606 setHasChildren: function(hasChildren) | 607 setExpandable: function(expandable) |
607 { | 608 { |
608 this.hasChildren = hasChildren; | 609 if (this._expandable === expandable) |
609 }, | |
610 | |
611 set hasChildren(x) | |
612 { | |
613 if (this._hasChildren === x) | |
614 return; | 610 return; |
615 | 611 |
616 this._hasChildren = x; | 612 this._expandable = expandable; |
617 | 613 |
618 this._listItemNode.classList.toggle("parent", x); | 614 this._listItemNode.classList.toggle("parent", expandable); |
619 if (!x) | 615 if (!expandable) |
620 this.collapse(); | 616 this.collapse(); |
621 }, | 617 }, |
622 | 618 |
623 get hidden() | 619 get hidden() |
624 { | 620 { |
625 return this._hidden; | 621 return this._hidden; |
626 }, | 622 }, |
627 | 623 |
628 set hidden(x) | 624 set hidden(x) |
629 { | 625 { |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
725 */ | 721 */ |
726 _handleDoubleClick: function(event) | 722 _handleDoubleClick: function(event) |
727 { | 723 { |
728 var element = event.currentTarget; | 724 var element = event.currentTarget; |
729 if (!element || element.treeElement !== this) | 725 if (!element || element.treeElement !== this) |
730 return; | 726 return; |
731 | 727 |
732 var handled = this.ondblclick(event); | 728 var handled = this.ondblclick(event); |
733 if (handled) | 729 if (handled) |
734 return; | 730 return; |
735 if (this.hasChildren && !this.expanded) | 731 if (this._expandable && !this.expanded) |
736 this.expand(); | 732 this.expand(); |
737 }, | 733 }, |
738 | 734 |
739 _detach: function() | 735 _detach: function() |
740 { | 736 { |
741 this._listItemNode.remove(); | 737 this._listItemNode.remove(); |
742 this._childrenListNode.remove(); | 738 this._childrenListNode.remove(); |
743 }, | 739 }, |
744 | 740 |
745 collapse: function() | 741 collapse: function() |
(...skipping 13 matching lines...) Expand all Loading... |
759 var item = this; | 755 var item = this; |
760 while (item) { | 756 while (item) { |
761 if (item.expanded) | 757 if (item.expanded) |
762 item.collapse(); | 758 item.collapse(); |
763 item = item.traverseNextTreeElement(false, this, true); | 759 item = item.traverseNextTreeElement(false, this, true); |
764 } | 760 } |
765 }, | 761 }, |
766 | 762 |
767 expand: function() | 763 expand: function() |
768 { | 764 { |
769 if (!this.hasChildren || (this.expanded && this._children)) | 765 if (!this._expandable || (this.expanded && this._children)) |
770 return; | 766 return; |
771 | 767 |
772 // Set this before onpopulate. Since onpopulate can add elements, this m
akes | 768 // Set this before onpopulate. Since onpopulate can add elements, this m
akes |
773 // sure the expanded flag is true before calling those functions. This p
revents the possibility | 769 // sure the expanded flag is true before calling those functions. This p
revents the possibility |
774 // of an infinite loop if onpopulate were to call expand. | 770 // of an infinite loop if onpopulate were to call expand. |
775 | 771 |
776 this.expanded = true; | 772 this.expanded = true; |
777 | 773 |
778 if (!this._children) { | 774 this._populateIfNeeded(); |
779 this._children = []; | |
780 this.onpopulate(); | |
781 } | |
782 | |
783 this._listItemNode.classList.add("expanded"); | 775 this._listItemNode.classList.add("expanded"); |
784 this._childrenListNode.classList.add("expanded"); | 776 this._childrenListNode.classList.add("expanded"); |
785 | 777 |
786 this.onexpand(); | 778 this.onexpand(); |
787 if (this.treeOutline) | 779 if (this.treeOutline) |
788 this.treeOutline.dispatchEventToListeners(TreeOutline.Events.Element
Expanded, this); | 780 this.treeOutline.dispatchEventToListeners(TreeOutline.Events.Element
Expanded, this); |
789 }, | 781 }, |
790 | 782 |
791 /** | 783 /** |
792 * @param {number=} maxDepth | 784 * @param {number=} maxDepth |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
892 deselect: function(supressOnDeselect) | 884 deselect: function(supressOnDeselect) |
893 { | 885 { |
894 if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this |
| !this.selected) | 886 if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this |
| !this.selected) |
895 return; | 887 return; |
896 | 888 |
897 this.selected = false; | 889 this.selected = false; |
898 this.treeOutline.selectedTreeElement = null; | 890 this.treeOutline.selectedTreeElement = null; |
899 this._listItemNode.classList.remove("selected"); | 891 this._listItemNode.classList.remove("selected"); |
900 }, | 892 }, |
901 | 893 |
| 894 _populateIfNeeded: function() |
| 895 { |
| 896 if (this._expandable && !this._children) { |
| 897 this._children = []; |
| 898 this.onpopulate(); |
| 899 } |
| 900 }, |
| 901 |
902 onpopulate: function() | 902 onpopulate: function() |
903 { | 903 { |
904 // Overridden by subclasses. | 904 // Overridden by subclasses. |
905 }, | 905 }, |
906 | 906 |
907 /** | 907 /** |
908 * @return {boolean} | 908 * @return {boolean} |
909 */ | 909 */ |
910 onenter: function() | 910 onenter: function() |
911 { | 911 { |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
972 | 972 |
973 /** | 973 /** |
974 * @param {boolean} skipUnrevealed | 974 * @param {boolean} skipUnrevealed |
975 * @param {?TreeElement=} stayWithin | 975 * @param {?TreeElement=} stayWithin |
976 * @param {boolean=} dontPopulate | 976 * @param {boolean=} dontPopulate |
977 * @param {!Object=} info | 977 * @param {!Object=} info |
978 * @return {?TreeElement} | 978 * @return {?TreeElement} |
979 */ | 979 */ |
980 traverseNextTreeElement: function(skipUnrevealed, stayWithin, dontPopulate,
info) | 980 traverseNextTreeElement: function(skipUnrevealed, stayWithin, dontPopulate,
info) |
981 { | 981 { |
982 if (!dontPopulate && this.hasChildren) | 982 if (!dontPopulate) |
983 this.onpopulate(); | 983 this._populateIfNeeded(); |
984 | 984 |
985 if (info) | 985 if (info) |
986 info.depthChange = 0; | 986 info.depthChange = 0; |
987 | 987 |
988 var element = skipUnrevealed ? (this.revealed() ? this.firstChild() : nu
ll) : this.firstChild(); | 988 var element = skipUnrevealed ? (this.revealed() ? this.firstChild() : nu
ll) : this.firstChild(); |
989 if (element && (!skipUnrevealed || (skipUnrevealed && this.expanded))) { | 989 if (element && (!skipUnrevealed || (skipUnrevealed && this.expanded))) { |
990 if (info) | 990 if (info) |
991 info.depthChange = 1; | 991 info.depthChange = 1; |
992 return element; | 992 return element; |
993 } | 993 } |
(...skipping 19 matching lines...) Expand all Loading... |
1013 }, | 1013 }, |
1014 | 1014 |
1015 /** | 1015 /** |
1016 * @param {boolean} skipUnrevealed | 1016 * @param {boolean} skipUnrevealed |
1017 * @param {boolean=} dontPopulate | 1017 * @param {boolean=} dontPopulate |
1018 * @return {?TreeElement} | 1018 * @return {?TreeElement} |
1019 */ | 1019 */ |
1020 traversePreviousTreeElement: function(skipUnrevealed, dontPopulate) | 1020 traversePreviousTreeElement: function(skipUnrevealed, dontPopulate) |
1021 { | 1021 { |
1022 var element = skipUnrevealed ? (this.revealed() ? this.previousSibling :
null) : this.previousSibling; | 1022 var element = skipUnrevealed ? (this.revealed() ? this.previousSibling :
null) : this.previousSibling; |
1023 if (!dontPopulate && element && element.hasChildren) | 1023 if (!dontPopulate && element) |
1024 element.onpopulate(); | 1024 element._populateIfNeeded(); |
1025 | 1025 |
1026 while (element && (skipUnrevealed ? (element.revealed() && element.expan
ded ? element.lastChild() : null) : element.lastChild())) { | 1026 while (element && (skipUnrevealed ? (element.revealed() && element.expan
ded ? element.lastChild() : null) : element.lastChild())) { |
1027 if (!dontPopulate && element.hasChildren) | 1027 if (!dontPopulate) |
1028 element.onpopulate(); | 1028 element._populateIfNeeded(); |
1029 element = (skipUnrevealed ? (element.revealed() && element.expanded
? element.lastChild() : null) : element.lastChild()); | 1029 element = (skipUnrevealed ? (element.revealed() && element.expanded
? element.lastChild() : null) : element.lastChild()); |
1030 } | 1030 } |
1031 | 1031 |
1032 if (element) | 1032 if (element) |
1033 return element; | 1033 return element; |
1034 | 1034 |
1035 if (!this.parent || this.parent.root) | 1035 if (!this.parent || this.parent.root) |
1036 return null; | 1036 return null; |
1037 | 1037 |
1038 return this.parent; | 1038 return this.parent; |
1039 }, | 1039 }, |
1040 | 1040 |
1041 /** | 1041 /** |
1042 * @return {boolean} | 1042 * @return {boolean} |
1043 */ | 1043 */ |
1044 isEventWithinDisclosureTriangle: function(event) | 1044 isEventWithinDisclosureTriangle: function(event) |
1045 { | 1045 { |
1046 // FIXME: We should not use getComputedStyle(). For that we need to get
rid of using ::before for disclosure triangle. (http://webk.it/74446) | 1046 // FIXME: We should not use getComputedStyle(). For that we need to get
rid of using ::before for disclosure triangle. (http://webk.it/74446) |
1047 var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddi
ngLeft; | 1047 var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddi
ngLeft; |
1048 console.assert(paddingLeftValue.endsWith("px")); | 1048 console.assert(paddingLeftValue.endsWith("px")); |
1049 var computedLeftPadding = parseFloat(paddingLeftValue); | 1049 var computedLeftPadding = parseFloat(paddingLeftValue); |
1050 var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; | 1050 var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; |
1051 return event.pageX >= left && event.pageX <= left + TreeElement._ArrowTo
ggleWidth && this.hasChildren; | 1051 return event.pageX >= left && event.pageX <= left + TreeElement._ArrowTo
ggleWidth && this._expandable; |
1052 } | 1052 } |
1053 } | 1053 } |
OLD | NEW |