Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(564)

Unified Diff: resources/bookmark_manager/js/cr/ui/tree.js

Issue 853002: Updating the Chromium reference build for Windows. The continuous... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/reference_builds/chrome/
Patch Set: Added the symbol files back. Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « resources/bookmark_manager/js/cr/ui/menuitem.js ('k') | resources/bookmark_manager/js/i18ntemplate.js » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: resources/bookmark_manager/js/cr/ui/tree.js
===================================================================
--- resources/bookmark_manager/js/cr/ui/tree.js (revision 0)
+++ resources/bookmark_manager/js/cr/ui/tree.js (revision 0)
@@ -0,0 +1,597 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+cr.define('cr.ui', function() {
+ // require cr.ui.define
+ // require cr.ui.limitInputWidth
+
+ /**
+ * Helper function that finds the first ancestor tree item.
+ * @param {!Element} el The element to start searching from.
+ * @return {cr.ui.TreeItem} The found tree item or null if not found.
+ */
+ function findTreeItem(el) {
+ while (el && !(el instanceof TreeItem)) {
+ el = el.parentNode;
+ }
+ return el;
+ }
+
+ /**
+ * Creates a new tree element.
+ * @param {Object=} opt_propertyBag Optional properties.
+ * @constructor
+ * @extends {HTMLElement}
+ */
+ var Tree = cr.ui.define('tree');
+
+ Tree.prototype = {
+ __proto__: HTMLElement.prototype,
+
+ /**
+ * Initializes the element.
+ */
+ decorate: function() {
+ // Make list focusable
+ if (!this.hasAttribute('tabindex'))
+ this.tabIndex = 0;
+
+ this.addEventListener('click', this.handleClick);
+ this.addEventListener('mousedown', this.handleMouseDown);
+ this.addEventListener('dblclick', this.handleDblClick);
+ this.addEventListener('keydown', this.handleKeyDown);
+ },
+
+ /**
+ * Returns the tree item that are children of this tree.
+ */
+ get items() {
+ return this.children;
+ },
+
+ /**
+ * Adds a tree item to the tree.
+ * @param {!cr.ui.TreeItem} treeItem The item to add.
+ */
+ add: function(treeItem) {
+ this.appendChild(treeItem);
+ },
+
+ /**
+ * Adds a tree item at the given index.
+ * @param {!cr.ui.TreeItem} treeItem The item to add.
+ * @param {number} index The index where we want to add the item.
+ */
+ addAt: function(treeItem, index) {
+ this.insertBefore(treeItem, this.children[index]);
+ },
+
+ /**
+ * Removes a tree item child.
+ * @param {!cr.ui.TreeItem} treeItem The tree item to remove.
+ */
+ remove: function(treeItem) {
+ this.removeChild(treeItem);
+ },
+
+ /**
+ * Handles click events on the tree and forwards the event to the relevant
+ * tree items as necesary.
+ * @param {Event} e The click event object.
+ */
+ handleClick: function(e) {
+ var treeItem = findTreeItem(e.target);
+ if (treeItem)
+ treeItem.handleClick(e);
+ },
+
+ handleMouseDown: function(e) {
+ if (e.button == 2) // right
+ this.handleClick(e);
+ },
+
+ /**
+ * Handles double click events on the tree.
+ * @param {Event} e The dblclick event object.
+ */
+ handleDblClick: function(e) {
+ var treeItem = findTreeItem(e.target);
+ if (treeItem)
+ treeItem.expanded = !treeItem.expanded;
+ },
+
+ /**
+ * Handles keydown events on the tree and updates selection and exanding
+ * of tree items.
+ * @param {Event} e The click event object.
+ */
+ handleKeyDown: function(e) {
+ var itemToSelect;
+ if (e.ctrlKey)
+ return;
+
+ var item = this.selectedItem;
+
+ var rtl = window.getComputedStyle(item).direction == 'rtl';
+
+ switch (e.keyIdentifier) {
+ case 'Up':
+ itemToSelect = item ? getPrevious(item) :
+ this.items[this.items.length - 1];
+ break;
+ case 'Down':
+ itemToSelect = item ? getNext(item) :
+ this.items[0];
+ break;
+ case 'Left':
+ case 'Right':
+ // Don't let back/forward keyboard shortcuts be used.
+ if (!cr.isMac && e.altKey || cr.isMac && e.metaKey)
+ break;
+
+ if (e.keyIdentifier == 'Left' && !rtl ||
+ e.keyIdentifier == 'Right' && rtl) {
+ if (item.expanded)
+ item.expanded = false;
+ else
+ itemToSelect = findTreeItem(item.parentNode);
+ } else {
+ if (!item.expanded)
+ item.expanded = true;
+ else
+ itemToSelect = item.items[0];
+ }
+ break;
+ case 'Home':
+ itemToSelect = this.items[0];
+ break;
+ case 'End':
+ itemToSelect = this.items[this.items.length - 1];
+ break;
+ }
+
+ if (itemToSelect) {
+ itemToSelect.selected = true;
+ e.preventDefault();
+ }
+ },
+
+ /**
+ * The selected tree item or null if none.
+ * @type {cr.ui.TreeItem}
+ */
+ get selectedItem() {
+ return this.selectedItem_ || null;
+ },
+ set selectedItem(item) {
+ var oldSelectedItem = this.selectedItem_;
+ if (oldSelectedItem != item) {
+ // Set the selectedItem_ before deselecting the old item since we only
+ // want one change when moving between items.
+ this.selectedItem_ = item;
+
+ if (oldSelectedItem)
+ oldSelectedItem.selected = false;
+
+ if (item)
+ item.selected = true;
+
+ cr.dispatchSimpleEvent(this, 'change');
+ }
+ }
+ };
+
+ /**
+ * This is used as a blueprint for new tree item elements.
+ * @type {!HTMLElement}
+ */
+ var treeItemProto = (function() {
+ var treeItem = cr.doc.createElement('div');
+ treeItem.className = 'tree-item';
+ treeItem.innerHTML = '<div class=tree-row>' +
+ '<span class=expand-icon></span>' +
+ '<span class=tree-label></span>' +
+ '</div>' +
+ '<div class=tree-children></div>';
+ return treeItem;
+ })();
+
+ /**
+ * Creates a new tree item.
+ * @param {Object=} opt_propertyBag Optional properties.
+ * @constructor
+ * @extends {HTMLElement}
+ */
+ var TreeItem = cr.ui.define(function() {
+ return treeItemProto.cloneNode(true);
+ });
+
+ TreeItem.prototype = {
+ __proto__: HTMLElement.prototype,
+
+ /**
+ * Initializes the element.
+ */
+ decorate: function() {
+
+ },
+
+ /**
+ * The tree items children.
+ */
+ get items() {
+ return this.lastElementChild.children;
+ },
+
+ /**
+ * Adds a tree item as a child.
+ * @param {!cr.ui.TreeItem} child The child to add.
+ */
+ add: function(child) {
+ this.addAt(child, 0xffffffff);
+ },
+
+ /**
+ * Adds a tree item as a child at a given index.
+ * @param {!cr.ui.TreeItem} child The child to add.
+ * @param {number} index The index where to add the child.
+ */
+ addAt: function(child, index) {
+ this.lastElementChild.insertBefore(child, this.items[index]);
+ if (this.items.length == 1)
+ this.hasChildren_ = true;
+ },
+
+ /**
+ * Removes a child.
+ * @param {!cr.ui.TreeItem} child The tree item child to remove.
+ */
+ remove: function(child) {
+ // If we removed the selected item we should become selected.
+ var tree = this.tree;
+ var selectedItem = tree.selectedItem;
+ if (selectedItem && child.contains(selectedItem))
+ this.selected = true;
+
+ this.lastElementChild.removeChild(child);
+ if (this.items.length == 0)
+ this.hasChildren_ = false;
+ },
+
+ /**
+ * The parent tree item.
+ * @type {!cr.ui.Tree|cr.ui.TreeItem}
+ */
+ get parentItem() {
+ var p = this.parentNode;
+ while (p && !(p instanceof TreeItem) && !(p instanceof Tree)) {
+ p = p.parentNode;
+ }
+ return p;
+ },
+
+ /**
+ * The tree that the tree item belongs to or null of no added to a tree.
+ * @type {cr.ui.Tree}
+ */
+ get tree() {
+ var t = this.parentItem;
+ while (t && !(t instanceof Tree)) {
+ t = t.parentItem;
+ }
+ return t;
+ },
+
+ /**
+ * Whether the tree item is expanded or not.
+ * @type {boolean}
+ */
+ get expanded() {
+ return this.hasAttribute('expanded');
+ },
+ set expanded(b) {
+ if (this.expanded == b)
+ return;
+
+ var treeChildren = this.lastElementChild;
+
+ if (b) {
+ if (this.mayHaveChildren_) {
+ this.setAttribute('expanded', '');
+ treeChildren.setAttribute('expanded', '');
+ cr.dispatchSimpleEvent(this, 'expand', true);
+ this.scrollIntoViewIfNeeded(false);
+ }
+ } else {
+ var tree = this.tree;
+ if (tree && !this.selected) {
+ var oldSelected = tree.selectedItem;
+ if (oldSelected && this.contains(oldSelected))
+ this.selected = true;
+ }
+ this.removeAttribute('expanded');
+ treeChildren.removeAttribute('expanded');
+ cr.dispatchSimpleEvent(this, 'collapse', true);
+ }
+ },
+
+ /**
+ * Expands all parent items.
+ */
+ reveal: function() {
+ var pi = this.parentItem;
+ while (pi && !(pi instanceof Tree)) {
+ pi.expanded = true;
+ pi = pi.parentItem;
+ }
+ },
+
+ /**
+ * The element representing the row that gets highlighted.
+ * @type {!HTMLElement}
+ */
+ get rowElement() {
+ return this.firstElementChild;
+ },
+
+ /**
+ * The element containing the label text and the icon.
+ * @type {!HTMLElement}
+ */
+ get labelElement() {
+ return this.firstElementChild.lastElementChild;
+ },
+
+ /**
+ * The label text.
+ * @type {string}
+ */
+ get label() {
+ return this.labelElement.textContent;
+ },
+ set label(s) {
+ this.labelElement.textContent = s;
+ },
+
+ /**
+ * The URL for the icon.
+ * @type {string}
+ */
+ get icon() {
+ return window.getComputedStyle(this.labelElement).
+ backgroundImage.slice(4, -1);
+ },
+ set icon(icon) {
+ return this.labelElement.style.backgroundImage = url(icon);
+ },
+
+ /**
+ * Whether the tree item is selected or not.
+ * @type {boolean}
+ */
+ get selected() {
+ return this.hasAttribute('selected');
+ },
+ set selected(b) {
+ if (this.selected == b)
+ return;
+ var rowItem = this.firstElementChild;
+ var tree = this.tree;
+ if (b) {
+ this.setAttribute('selected', '');
+ rowItem.setAttribute('selected', '');
+ this.labelElement.scrollIntoViewIfNeeded(false);
+ if (tree)
+ tree.selectedItem = this;
+ } else {
+ this.removeAttribute('selected');
+ rowItem.removeAttribute('selected');
+ if (tree && tree.selectedItem == this)
+ tree.selectedItem = null;
+ }
+ },
+
+ /**
+ * Whether the tree item has children.
+ * @type {boolean}
+ */
+ get mayHaveChildren_() {
+ return this.hasAttribute('may-have-children');
+ },
+ set mayHaveChildren_(b) {
+ var rowItem = this.firstElementChild;
+ if (b) {
+ this.setAttribute('may-have-children', '');
+ rowItem.setAttribute('may-have-children', '');
+ } else {
+ this.removeAttribute('may-have-children');
+ rowItem.removeAttribute('may-have-children');
+ }
+ },
+
+ /**
+ * Whether the tree item has children.
+ * @type {boolean}
+ */
+ get hasChildren() {
+ return !!this.items[0];
+ },
+
+ /**
+ * Whether the tree item has children.
+ * @type {boolean}
+ * @private
+ */
+ set hasChildren_(b) {
+ var rowItem = this.firstElementChild;
+ this.setAttribute('has-children', b);
+ rowItem.setAttribute('has-children', b);
+ if (b)
+ this.mayHaveChildren_ = true;
+ },
+
+ /**
+ * Called when the user clicks on a tree item. This is forwarded from the
+ * cr.ui.Tree.
+ * @param {Event} e The click event.
+ */
+ handleClick: function(e) {
+ if (e.target.className == 'expand-icon')
+ this.expanded = !this.expanded;
+ else
+ this.selected = true;
+ },
+
+ /**
+ * Makes the tree item user editable. If the user renamed the item a
+ * bubbling {@code rename} event is fired.
+ * @type {boolean}
+ */
+ set editing(editing) {
+ var oldEditing = this.editing;
+ if (editing == oldEditing)
+ return;
+
+ var self = this;
+ var labelEl = this.labelElement;
+ var text = this.label;
+ var input;
+
+ // Handles enter and escape which trigger reset and commit respectively.
+ function handleKeydown(e) {
+ // Make sure that the tree does not handle the key.
+ e.stopPropagation();
+
+ // Calling tree.focus blurs the input which will make the tree item
+ // non editable.
+ switch (e.keyIdentifier) {
+ case 'U+001B': // Esc
+ input.value = text;
+ // fall through
+ case 'Enter':
+ self.tree.focus();
+ }
+ }
+
+ function stopPropagation(e) {
+ e.stopPropagation();
+ }
+
+ if (editing) {
+ this.selected = true;
+ this.setAttribute('editing', '');
+ this.draggable = false;
+
+ // We create an input[type=text] and copy over the label value. When
+ // the input loses focus we set editing to false again.
+ input = this.ownerDocument.createElement('input');
+ input.value = text;
+ if (labelEl.firstChild)
+ labelEl.replaceChild(input, labelEl.firstChild);
+ else
+ labelEl.appendChild(input);
+
+ input.addEventListener('keydown', handleKeydown);
+ input.addEventListener('blur', cr.bind(function() {
+ this.editing = false;
+ }, this));
+
+ // Make sure that double clicks do not expand and collapse the tree
+ // item.
+ var eventsToStop = ['mousedown', 'mouseup', 'contextmenu', 'dblclick'];
+ eventsToStop.forEach(function(type) {
+ input.addEventListener(type, stopPropagation);
+ });
+
+ input.focus();
+ input.select();
+ cr.ui.limitInputWidth(input, this.rowElement, 20);
+ // the padding and border of the tree-row
+
+ this.oldLabel_ = text;
+ } else {
+ this.removeAttribute('editing');
+ this.draggable = true;
+ input = labelEl.firstChild;
+ var value = input.value;
+ if (/^\s*$/.test(value)) {
+ labelEl.textContent = this.oldLabel_;
+ } else {
+ labelEl.textContent = value;
+ if (value != this.oldLabel_) {
+ cr.dispatchSimpleEvent(this, 'rename', true);
+ }
+ }
+ delete this.oldLabel_;
+ }
+ },
+
+ get editing() {
+ return this.hasAttribute('editing');
+ }
+ };
+
+ /**
+ * Helper function that returns the next visible tree item.
+ * @param {cr.ui.TreeItem} item The tree item.
+ * @retrun {cr.ui.TreeItem} The found item or null.
+ */
+ function getNext(item) {
+ if (item.expanded) {
+ var firstChild = item.items[0];
+ if (firstChild) {
+ return firstChild;
+ }
+ }
+
+ return getNextHelper(item);
+ }
+
+ /**
+ * Another helper function that returns the next visible tree item.
+ * @param {cr.ui.TreeItem} item The tree item.
+ * @retrun {cr.ui.TreeItem} The found item or null.
+ */
+ function getNextHelper(item) {
+ if (!item)
+ return null;
+
+ var nextSibling = item.nextElementSibling;
+ if (nextSibling) {
+ return nextSibling;
+ }
+ return getNextHelper(item.parentItem);
+ }
+
+ /**
+ * Helper function that returns the previous visible tree item.
+ * @param {cr.ui.TreeItem} item The tree item.
+ * @retrun {cr.ui.TreeItem} The found item or null.
+ */
+ function getPrevious(item) {
+ var previousSibling = item.previousElementSibling;
+ return previousSibling ? getLastHelper(previousSibling) : item.parentItem;
+ }
+
+ /**
+ * Helper function that returns the last visible tree item in the subtree.
+ * @param {cr.ui.TreeItem} item The item to find the last visible item for.
+ * @return {cr.ui.TreeItem} The found item or null.
+ */
+ function getLastHelper(item) {
+ if (!item)
+ return null;
+ if (item.expanded && item.hasChildren) {
+ var lastChild = item.items[item.items.length - 1];
+ return getLastHelper(lastChild);
+ }
+ return item;
+ }
+
+ // Export
+ return {
+ Tree: Tree,
+ TreeItem: TreeItem
+ };
+});
« no previous file with comments | « resources/bookmark_manager/js/cr/ui/menuitem.js ('k') | resources/bookmark_manager/js/i18ntemplate.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698