1c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Copyright (c) 2010 The Chromium Authors. All rights reserved. 2c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// Use of this source code is governed by a BSD-style license that can be 3c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch// found in the LICENSE file. 4c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 5c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdochcr.define('cr.ui', function() { 6c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // require cr.ui.define 7c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // require cr.ui.limitInputWidth 8c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 9c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 10c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The number of pixels to indent per level. 11c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {number} 12c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 13c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch const INDENT = 20; 14c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 15c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 16c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Returns the computed style for an element. 17c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!Element} el The element to get the computed style for. 18c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @return {!CSSStyleDeclaration} The computed style. 19c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 20c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function getComputedStyle(el) { 21c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return el.ownerDocument.defaultView.getComputedStyle(el); 22c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 23c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 24c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 25c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Helper function that finds the first ancestor tree item. 26c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!Element} el The element to start searching from. 27c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @return {cr.ui.TreeItem} The found tree item or null if not found. 28c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 29c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function findTreeItem(el) { 30c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (el && !(el instanceof TreeItem)) { 31c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch el = el.parentNode; 32c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 33c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return el; 34c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 35c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 36c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 37c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Creates a new tree element. 38c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {Object=} opt_propertyBag Optional properties. 39c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @constructor 40c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @extends {HTMLElement} 41c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 42c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var Tree = cr.ui.define('tree'); 43c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 44c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Tree.prototype = { 45c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch __proto__: HTMLElement.prototype, 46c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 47c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 48c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Initializes the element. 49c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 50c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch decorate: function() { 51c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make list focusable 52c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!this.hasAttribute('tabindex')) 53c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.tabIndex = 0; 54c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 55c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.addEventListener('click', this.handleClick); 56c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.addEventListener('mousedown', this.handleMouseDown); 57c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.addEventListener('dblclick', this.handleDblClick); 58c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.addEventListener('keydown', this.handleKeyDown); 59c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 60c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 61c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 62c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Returns the tree item that are children of this tree. 63c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 64c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get items() { 65c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.children; 66c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 67c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 68c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 69c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Adds a tree item to the tree. 70c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!cr.ui.TreeItem} treeItem The item to add. 71c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 72c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch add: function(treeItem) { 73c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.addAt(treeItem, 0xffffffff); 74c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 75c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 76c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 77c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Adds a tree item at the given index. 78c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!cr.ui.TreeItem} treeItem The item to add. 79c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {number} index The index where we want to add the item. 80c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 81c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch addAt: function(treeItem, index) { 82c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.insertBefore(treeItem, this.children[index]); 83c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch treeItem.setDepth_(this.depth + 1); 84c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 85c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 86c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 87c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Removes a tree item child. 88c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!cr.ui.TreeItem} treeItem The tree item to remove. 89c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 90c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch remove: function(treeItem) { 91c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.removeChild(treeItem); 92c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 93c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 94c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 95c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The depth of the node. This is 0 for the tree itself. 96c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {number} 97c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 98c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get depth() { 99c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return 0; 100c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 101c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 102c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 103c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Handles click events on the tree and forwards the event to the relevant 104c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * tree items as necesary. 105c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {Event} e The click event object. 106c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 107c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handleClick: function(e) { 108c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var treeItem = findTreeItem(e.target); 109c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (treeItem) 110c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch treeItem.handleClick(e); 111c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 112c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 113c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handleMouseDown: function(e) { 114c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (e.button == 2) // right 115c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.handleClick(e); 116c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 117c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 118c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 119c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Handles double click events on the tree. 120c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {Event} e The dblclick event object. 121c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 122c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handleDblClick: function(e) { 123c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var treeItem = findTreeItem(e.target); 124c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (treeItem) 125c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch treeItem.expanded = !treeItem.expanded; 126c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 127c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 128c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 129c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Handles keydown events on the tree and updates selection and exanding 130c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * of tree items. 131c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {Event} e The click event object. 132c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 133c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handleKeyDown: function(e) { 134c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var itemToSelect; 135c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (e.ctrlKey) 136c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 137c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 138c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var item = this.selectedItem; 139c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 140c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var rtl = getComputedStyle(item).direction == 'rtl'; 141c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 142c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (e.keyIdentifier) { 143c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'Up': 144c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch itemToSelect = item ? getPrevious(item) : 145c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.items[this.items.length - 1]; 146c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 147c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'Down': 148c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch itemToSelect = item ? getNext(item) : 149c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.items[0]; 150c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 151c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'Left': 152c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'Right': 153c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Don't let back/forward keyboard shortcuts be used. 154c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!cr.isMac && e.altKey || cr.isMac && e.metaKey) 155c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 156c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 157c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (e.keyIdentifier == 'Left' && !rtl || 158c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.keyIdentifier == 'Right' && rtl) { 159c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (item.expanded) 160c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch item.expanded = false; 161c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 162c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch itemToSelect = findTreeItem(item.parentNode); 163c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 164c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!item.expanded) 165c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch item.expanded = true; 166c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 167c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch itemToSelect = item.items[0]; 168c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 169c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 170c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'Home': 171c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch itemToSelect = this.items[0]; 172c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 173c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'End': 174c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch itemToSelect = this.items[this.items.length - 1]; 175c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch break; 176c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 177c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 178c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (itemToSelect) { 179c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch itemToSelect.selected = true; 180c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.preventDefault(); 181c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 182c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 183c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 184c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 185c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The selected tree item or null if none. 186c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {cr.ui.TreeItem} 187c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 188c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get selectedItem() { 189c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.selectedItem_ || null; 190c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 191c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set selectedItem(item) { 192c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var oldSelectedItem = this.selectedItem_; 193c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (oldSelectedItem != item) { 194c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Set the selectedItem_ before deselecting the old item since we only 195c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // want one change when moving between items. 196c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.selectedItem_ = item; 197c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 198c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (oldSelectedItem) 199c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch oldSelectedItem.selected = false; 200c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 201c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (item) 202c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch item.selected = true; 203c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 204c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cr.dispatchSimpleEvent(this, 'change'); 205c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 206c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 207c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 208c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 209c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @return {!ClientRect} The rect to use for the context menu. 210c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 211c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch getRectForContextMenu: function() { 212c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // TODO(arv): Add trait support so we can share more code between trees 213c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // and lists. 214c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (this.selectedItem) 215c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.selectedItem.rowElement.getBoundingClientRect(); 216c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.getBoundingClientRect(); 217c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 218c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 219c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 220c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 221c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * This is used as a blueprint for new tree item elements. 222c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {!HTMLElement} 223c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 224c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var treeItemProto = (function() { 225c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var treeItem = cr.doc.createElement('div'); 226c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch treeItem.className = 'tree-item'; 227c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch treeItem.innerHTML = '<div class=tree-row>' + 228c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch '<span class=expand-icon></span>' + 229c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch '<span class=tree-label></span>' + 230c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch '</div>' + 231c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch '<div class=tree-children></div>'; 232c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return treeItem; 233c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch })(); 234c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 235c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 236c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Creates a new tree item. 237c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {Object=} opt_propertyBag Optional properties. 238c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @constructor 239c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @extends {HTMLElement} 240c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 241c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var TreeItem = cr.ui.define(function() { 242c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return treeItemProto.cloneNode(true); 243c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }); 244c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 245c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TreeItem.prototype = { 246c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch __proto__: HTMLElement.prototype, 247c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 248c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 249c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Initializes the element. 250c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 251c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch decorate: function() { 252c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 253c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 254c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 255c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 256c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The tree items children. 257c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 258c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get items() { 259c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.lastElementChild.children; 260c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 261c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 262c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 263c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The depth of the tree item. 264c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {number} 265c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 266c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch depth_: 0, 267c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get depth() { 268c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.depth_; 269c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 270c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 271c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 272c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Sets the depth. 273c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {number} depth The new depth. 274c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @private 275c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 276c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch setDepth_: function(depth) { 277c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (depth != this.depth_) { 278c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.rowElement.style.WebkitPaddingStart = Math.max(0, depth - 1) * 279c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch INDENT + 'px'; 280c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.depth_ = depth; 281c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var items = this.items; 282c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch for (var i = 0, item; item = items[i]; i++) { 283c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch item.setDepth_(depth + 1); 284c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 285c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 286c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 287c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 288c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 289c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Adds a tree item as a child. 290c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!cr.ui.TreeItem} child The child to add. 291c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 292c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch add: function(child) { 293c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.addAt(child, 0xffffffff); 294c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 295c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 296c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 297c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Adds a tree item as a child at a given index. 298c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!cr.ui.TreeItem} child The child to add. 299c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {number} index The index where to add the child. 300c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 301c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch addAt: function(child, index) { 302c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.lastElementChild.insertBefore(child, this.items[index]); 303c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (this.items.length == 1) 304731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick this.hasChildren = true; 305c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch child.setDepth_(this.depth + 1); 306c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 307c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 308c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 309c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Removes a child. 310c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {!cr.ui.TreeItem} child The tree item child to remove. 311c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 312c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch remove: function(child) { 313c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // If we removed the selected item we should become selected. 314c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var tree = this.tree; 315c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var selectedItem = tree.selectedItem; 316c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (selectedItem && child.contains(selectedItem)) 317c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.selected = true; 318c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 319c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.lastElementChild.removeChild(child); 320c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (this.items.length == 0) 321731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick this.hasChildren = false; 322c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 323c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 324c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 325c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The parent tree item. 326c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {!cr.ui.Tree|cr.ui.TreeItem} 327c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 328c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get parentItem() { 329c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var p = this.parentNode; 330c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (p && !(p instanceof TreeItem) && !(p instanceof Tree)) { 331c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch p = p.parentNode; 332c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 333c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return p; 334c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 335c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 336c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 337c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The tree that the tree item belongs to or null of no added to a tree. 338c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {cr.ui.Tree} 339c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 340c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get tree() { 341c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var t = this.parentItem; 342c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (t && !(t instanceof Tree)) { 343c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch t = t.parentItem; 344c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 345c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return t; 346c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 347c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 348c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 349c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Whether the tree item is expanded or not. 350c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {boolean} 351c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 352c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get expanded() { 353c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.hasAttribute('expanded'); 354c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 355c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set expanded(b) { 356c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (this.expanded == b) 357c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 358c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 359c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var treeChildren = this.lastElementChild; 360c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 361c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (b) { 362c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (this.mayHaveChildren_) { 363c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.setAttribute('expanded', ''); 364c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch treeChildren.setAttribute('expanded', ''); 365c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cr.dispatchSimpleEvent(this, 'expand', true); 366c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.scrollIntoViewIfNeeded(false); 367c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 368c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 369c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var tree = this.tree; 370c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tree && !this.selected) { 371c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var oldSelected = tree.selectedItem; 372c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (oldSelected && this.contains(oldSelected)) 373c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.selected = true; 374c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 375c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.removeAttribute('expanded'); 376c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch treeChildren.removeAttribute('expanded'); 377c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cr.dispatchSimpleEvent(this, 'collapse', true); 378c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 379c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 380c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 381c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 382c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Expands all parent items. 383c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 384c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch reveal: function() { 385c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var pi = this.parentItem; 386c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch while (pi && !(pi instanceof Tree)) { 387c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pi.expanded = true; 388c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch pi = pi.parentItem; 389c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 390c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 391c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 392c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 393c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The element representing the row that gets highlighted. 394c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {!HTMLElement} 395c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 396c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get rowElement() { 397c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.firstElementChild; 398c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 399c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 400c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 401c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The element containing the label text and the icon. 402c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {!HTMLElement} 403c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 404c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get labelElement() { 405c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.firstElementChild.lastElementChild; 406c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 407c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 408c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 409c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The label text. 410c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {string} 411c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 412c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get label() { 413c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.labelElement.textContent; 414c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 415c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set label(s) { 416c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.labelElement.textContent = s; 417c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 418c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 419c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 420c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * The URL for the icon. 421c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {string} 422c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 423c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get icon() { 424c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return getComputedStyle(this.labelElement).backgroundImage.slice(4, -1); 425c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 426c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set icon(icon) { 427c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.labelElement.style.backgroundImage = url(icon); 428c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 429c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 430c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 431c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Whether the tree item is selected or not. 432c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {boolean} 433c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 434c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get selected() { 435c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.hasAttribute('selected'); 436c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 437c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set selected(b) { 438c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (this.selected == b) 439c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 440c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var rowItem = this.firstElementChild; 441c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var tree = this.tree; 442c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (b) { 443c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.setAttribute('selected', ''); 444c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rowItem.setAttribute('selected', ''); 445c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.reveal(); 446c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.labelElement.scrollIntoViewIfNeeded(false); 447c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tree) 448c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tree.selectedItem = this; 449c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 450c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.removeAttribute('selected'); 451c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rowItem.removeAttribute('selected'); 452c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (tree && tree.selectedItem == this) 453c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch tree.selectedItem = null; 454c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 455c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 456c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 457c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 458c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Whether the tree item has children. 459c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {boolean} 460c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 461c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get mayHaveChildren_() { 462c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.hasAttribute('may-have-children'); 463c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 464c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set mayHaveChildren_(b) { 465c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var rowItem = this.firstElementChild; 466c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (b) { 467c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.setAttribute('may-have-children', ''); 468c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rowItem.setAttribute('may-have-children', ''); 469c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 470c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.removeAttribute('may-have-children'); 471c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rowItem.removeAttribute('may-have-children'); 472c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 473c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 474c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 475c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 476c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Whether the tree item has children. 477c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {boolean} 478c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 479c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get hasChildren() { 480c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return !!this.items[0]; 481c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 482c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 483c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 484c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Whether the tree item has children. 485c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {boolean} 486c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 487731df977c0511bca2206b5f333555b1205ff1f43Iain Merrick set hasChildren(b) { 488c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var rowItem = this.firstElementChild; 489c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.setAttribute('has-children', b); 490c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch rowItem.setAttribute('has-children', b); 491c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (b) 492c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.mayHaveChildren_ = true; 493c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 494c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 495c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 496c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Called when the user clicks on a tree item. This is forwarded from the 497c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * cr.ui.Tree. 498c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {Event} e The click event. 499c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 500c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch handleClick: function(e) { 501c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (e.target.className == 'expand-icon') 502c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.expanded = !this.expanded; 503c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 504c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.selected = true; 505c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 506c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 507c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 508c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Makes the tree item user editable. If the user renamed the item a 509c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * bubbling {@code rename} event is fired. 510c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @type {boolean} 511c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 512c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch set editing(editing) { 513c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var oldEditing = this.editing; 514c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (editing == oldEditing) 515c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return; 516c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 517c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var self = this; 518c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var labelEl = this.labelElement; 519c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var text = this.label; 520c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var input; 521c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 522c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Handles enter and escape which trigger reset and commit respectively. 523c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function handleKeydown(e) { 524c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure that the tree does not handle the key. 525c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.stopPropagation(); 526c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 527c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Calling tree.focus blurs the input which will make the tree item 528c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // non editable. 529c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch switch (e.keyIdentifier) { 530c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'U+001B': // Esc 531c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.value = text; 532c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // fall through 533c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch case 'Enter': 534c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch self.tree.focus(); 535c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 536c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 537c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 538c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function stopPropagation(e) { 539c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch e.stopPropagation(); 540c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 541c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 542c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (editing) { 543c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.selected = true; 544c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.setAttribute('editing', ''); 545c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.draggable = false; 546c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 547c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // We create an input[type=text] and copy over the label value. When 548c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // the input loses focus we set editing to false again. 549c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input = this.ownerDocument.createElement('input'); 550c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.value = text; 551c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (labelEl.firstChild) 552c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch labelEl.replaceChild(input, labelEl.firstChild); 553c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch else 554c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch labelEl.appendChild(input); 555c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 556c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.addEventListener('keydown', handleKeydown); 5573345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick input.addEventListener('blur', (function() { 558c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.editing = false; 5593345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick }).bind(this)); 560c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 561c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Make sure that double clicks do not expand and collapse the tree 562c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // item. 563c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var eventsToStop = ['mousedown', 'mouseup', 'contextmenu', 'dblclick']; 564c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch eventsToStop.forEach(function(type) { 565c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.addEventListener(type, stopPropagation); 566c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }); 567c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 568c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Wait for the input element to recieve focus before sizing it. 569c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var rowElement = this.rowElement; 570c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function onFocus() { 571c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.removeEventListener('focus', onFocus); 572c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // 20 = the padding and border of the tree-row 573c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cr.ui.limitInputWidth(input, rowElement, 20); 574c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 575c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.addEventListener('focus', onFocus); 576c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.focus(); 577c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input.select(); 578c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 579c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.oldLabel_ = text; 580c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 581c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.removeAttribute('editing'); 582c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch this.draggable = true; 583c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch input = labelEl.firstChild; 584c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var value = input.value; 585c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (/^\s*$/.test(value)) { 586c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch labelEl.textContent = this.oldLabel_; 587c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } else { 588c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch labelEl.textContent = value; 589c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (value != this.oldLabel_) { 590c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch cr.dispatchSimpleEvent(this, 'rename', true); 591c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 592c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 593c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch delete this.oldLabel_; 594c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 595c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }, 596c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 597c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch get editing() { 598c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return this.hasAttribute('editing'); 599c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 600c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 601c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 602c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 603c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Helper function that returns the next visible tree item. 604c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {cr.ui.TreeItem} item The tree item. 605c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @retrun {cr.ui.TreeItem} The found item or null. 606c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 607c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function getNext(item) { 608c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (item.expanded) { 609c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var firstChild = item.items[0]; 610c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (firstChild) { 611c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return firstChild; 612c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 613c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 614c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 615c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return getNextHelper(item); 616c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 617c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 618c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 619c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Another helper function that returns the next visible tree item. 620c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {cr.ui.TreeItem} item The tree item. 621c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @retrun {cr.ui.TreeItem} The found item or null. 622c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 623c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function getNextHelper(item) { 624c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!item) 625c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return null; 626c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 627c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var nextSibling = item.nextElementSibling; 628c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (nextSibling) { 629c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return nextSibling; 630c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 631c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return getNextHelper(item.parentItem); 632c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 633c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 634c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 635c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Helper function that returns the previous visible tree item. 636c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {cr.ui.TreeItem} item The tree item. 637c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @retrun {cr.ui.TreeItem} The found item or null. 638c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 639c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function getPrevious(item) { 640c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var previousSibling = item.previousElementSibling; 641c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return previousSibling ? getLastHelper(previousSibling) : item.parentItem; 642c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 643c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 644c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch /** 645c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * Helper function that returns the last visible tree item in the subtree. 646c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @param {cr.ui.TreeItem} item The item to find the last visible item for. 647c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch * @return {cr.ui.TreeItem} The found item or null. 648c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch */ 649c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch function getLastHelper(item) { 650c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (!item) 651c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return null; 652c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch if (item.expanded && item.hasChildren) { 653c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch var lastChild = item.items[item.items.length - 1]; 654c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return getLastHelper(lastChild); 655c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 656c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return item; 657c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch } 658c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch 659c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch // Export 660c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch return { 661c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch Tree: Tree, 662c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch TreeItem: TreeItem 663c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch }; 664c407dc5cd9bdc5668497f21b26b09d988ab439deBen Murdoch}); 665