| 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 |