| Index: chrome/browser/resources/md_bookmarks/store.js
|
| diff --git a/chrome/browser/resources/md_bookmarks/store.js b/chrome/browser/resources/md_bookmarks/store.js
|
| index a5f3790860df23d81c4a276fef5d107f6ad26afe..8f0ef849e334c115d6178bff4e4628950a34fcd8 100644
|
| --- a/chrome/browser/resources/md_bookmarks/store.js
|
| +++ b/chrome/browser/resources/md_bookmarks/store.js
|
| @@ -37,7 +37,14 @@ var BookmarksStore = Polymer({
|
| readOnly: true,
|
| },
|
|
|
| + /** @type {Object<?string, !BookmarkTreeNode>} */
|
| idToNodeMap_: Object,
|
| +
|
| + /** @type {?number} */
|
| + anchorIndex_: Number,
|
| +
|
| + /** @type {Set<string>} */
|
| + searchResultSet_: Object,
|
| },
|
|
|
| /** @private {Object} */
|
| @@ -46,9 +53,10 @@ var BookmarksStore = Polymer({
|
| /** @override */
|
| attached: function() {
|
| this.documentListeners_ = {
|
| - 'selected-folder-changed': this.onSelectedFolderChanged_.bind(this),
|
| 'folder-open-changed': this.onFolderOpenChanged_.bind(this),
|
| 'search-term-changed': this.onSearchTermChanged_.bind(this),
|
| + 'select-item': this.onItemSelected_.bind(this),
|
| + 'selected-folder-changed': this.onSelectedFolderChanged_.bind(this),
|
| };
|
| for (var event in this.documentListeners_)
|
| document.addEventListener(event, this.documentListeners_[event]);
|
| @@ -97,7 +105,8 @@ var BookmarksStore = Polymer({
|
| /** @private */
|
| deselectFolders_: function() {
|
| this.unlinkPaths('displayedList');
|
| - this.set(this.idToNodeMap_[this.selectedId].path + '.isSelected', false);
|
| + this.set(
|
| + this.idToNodeMap_[this.selectedId].path + '.isSelectedFolder', false);
|
| this.selectedId = null;
|
| },
|
|
|
| @@ -123,10 +132,14 @@ var BookmarksStore = Polymer({
|
| this.fire('selected-folder-changed', this.rootNode.children[0].id);
|
| } else {
|
| chrome.bookmarks.search(this.searchTerm, function(results) {
|
| + this.anchorIndex_ = null;
|
| + this.clearSelectedItems_();
|
| + this.searchResultSet_ = new Set();
|
| +
|
| if (this.selectedId)
|
| this.deselectFolders_();
|
|
|
| - this._setDisplayedList(results);
|
| + this.setupSearchResults_(results);
|
| }.bind(this));
|
| }
|
| },
|
| @@ -137,9 +150,13 @@ var BookmarksStore = Polymer({
|
| if (!this.selectedId)
|
| return;
|
|
|
| + this.clearSelectedItems_();
|
| + this.anchorIndex_ = null;
|
| +
|
| var selectedNode = this.idToNodeMap_[this.selectedId];
|
| this.linkPaths('displayedList', selectedNode.path + '.children');
|
| - this._setDisplayedList(selectedNode.children);
|
| + this._setDisplayedList(
|
| + /** @type {Array<BookmarkTreeNode>} */ (selectedNode.children));
|
| },
|
|
|
| /**
|
| @@ -159,6 +176,91 @@ var BookmarksStore = Polymer({
|
| delete this.idToNodeMap_[id];
|
| },
|
|
|
| + /**
|
| + * Remove all selected items in the list.
|
| + * @private
|
| + */
|
| + clearSelectedItems_: function() {
|
| + if (!this.displayedList)
|
| + return;
|
| +
|
| + for (var i = 0; i < this.displayedList.length; i++) {
|
| + if (!this.displayedList[i].isSelectedItem)
|
| + continue;
|
| +
|
| + this.set('displayedList.#' + i + '.isSelectedItem', false);
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Return the index in the search result of an item.
|
| + * @param {BookmarkTreeNode} item
|
| + * @return {number}
|
| + * @private
|
| + */
|
| + getIndexInList_: function(item) {
|
| + return this.searchTerm ? item.searchResultIndex : item.index;
|
| + },
|
| +
|
| + /**
|
| + * @param {string} id
|
| + * @return {boolean}
|
| + * @private
|
| + */
|
| + isInDisplayedList_: function(id) {
|
| + return this.searchTerm ? this.searchResultSet_.has(id) :
|
| + this.idToNodeMap_[id].parentId == this.selectedId;
|
| + },
|
| +
|
| + /**
|
| + * Initializes the search results returned by the API as follows:
|
| + * - Populates |searchResultSet_| with a mapping of all result ids to
|
| + * their corresponding result.
|
| + * - Sets up the |searchResultIndex|.
|
| + * @param {Array<BookmarkTreeNode>} results
|
| + * @private
|
| + */
|
| + setupSearchResults_: function(results) {
|
| + for (var i = 0; i < results.length; i++) {
|
| + results[i].searchResultIndex = i;
|
| + results[i].isSelectedItem = false;
|
| + this.searchResultSet_.add(results[i].id);
|
| + }
|
| +
|
| + this._setDisplayedList(results);
|
| + },
|
| +
|
| + /**
|
| + * Select multiple items based on |anchorIndex_| and the selected
|
| + * item. If |anchorIndex_| is not set, single select the item.
|
| + * @param {BookmarkTreeNode} item
|
| + * @private
|
| + */
|
| + selectRange_: function(item) {
|
| + var startIndex, endIndex;
|
| + if (this.anchorIndex_ == null) {
|
| + this.anchorIndex_ = this.getIndexInList_(item);
|
| + startIndex = this.anchorIndex_;
|
| + endIndex = this.anchorIndex_;
|
| + } else {
|
| + var selectedIndex = this.getIndexInList_(item);
|
| + startIndex = Math.min(this.anchorIndex_, selectedIndex);
|
| + endIndex = Math.max(this.anchorIndex_, selectedIndex);
|
| + }
|
| + for (var i = startIndex; i <= endIndex; i++)
|
| + this.set('displayedList.#' + i + '.isSelectedItem', true);
|
| + },
|
| +
|
| + /**
|
| + * Selects a single item in the displayedList.
|
| + * @param {BookmarkTreeNode} item
|
| + * @private
|
| + */
|
| + selectItem_: function(item) {
|
| + this.anchorIndex_ = this.getIndexInList_(item);
|
| + this.set('displayedList.#' + this.anchorIndex_ + '.isSelectedItem', true);
|
| + },
|
| +
|
| //////////////////////////////////////////////////////////////////////////////
|
| // bookmarks-store, bookmarks API event listeners:
|
|
|
| @@ -172,17 +274,41 @@ var BookmarksStore = Polymer({
|
| * node: BookmarkTreeNode}} removeInfo
|
| */
|
| onBookmarkRemoved_: function(id, removeInfo) {
|
| - if (this.isAncestorOfSelected_(this.idToNodeMap_[id]))
|
| - this.fire('selected-folder-changed', removeInfo.parentId);
|
| -
|
| - var parentNode = this.idToNodeMap_[removeInfo.parentId];
|
| - this.splice(parentNode.path + '.children', removeInfo.index, 1);
|
| - this.removeDescendantsFromMap_(id);
|
| - BookmarksStore.generatePaths(parentNode, removeInfo.index);
|
| -
|
| - // Regenerate the search list if its displayed.
|
| - if (this.searchTerm)
|
| - this.updateSearchDisplay_();
|
| + chrome.bookmarks.getSubTree(removeInfo.parentId, function(parentNodes) {
|
| + var parentNode = parentNodes[0];
|
| + var isAncestor = this.isAncestorOfSelected_(this.idToNodeMap_[id]);
|
| + var wasInDisplayedList = this.isInDisplayedList_(id);
|
| +
|
| + // Refresh the parent node's data from the backend as its children's
|
| + // indexes will have changed and Polymer doesn't update them.
|
| + this.removeDescendantsFromMap_(id);
|
| + parentNode.path = this.idToNodeMap_[parentNode.id].path;
|
| + BookmarksStore.generatePaths(parentNode, 0);
|
| + BookmarksStore.initNodes(parentNode, this.idToNodeMap_);
|
| + this.set(parentNode.path, parentNode);
|
| +
|
| + // Updates selectedId if the removed node is an ancestor of the current
|
| + // selected node.
|
| + if (isAncestor)
|
| + this.fire('selected-folder-changed', removeInfo.parentId);
|
| +
|
| + // Only update the displayedList if the removed node is in the
|
| + // displayedList.
|
| + if (!wasInDisplayedList)
|
| + return;
|
| +
|
| + this.anchorIndex_ = null;
|
| +
|
| + // Update the currently displayed list.
|
| + if (this.searchTerm) {
|
| + this.updateSearchDisplay_();
|
| + } else {
|
| + if (!isAncestor)
|
| + this.fire('selected-folder-changed', this.selectedId);
|
| +
|
| + this._setDisplayedList(parentNode.children);
|
| + }
|
| + }.bind(this));
|
| },
|
|
|
| /**
|
| @@ -222,8 +348,9 @@ var BookmarksStore = Polymer({
|
| this.searchTerm = '';
|
|
|
| // Deselect the old folder if defined.
|
| - if (this.selectedId)
|
| - this.set(this.idToNodeMap_[this.selectedId].path + '.isSelected', false);
|
| + if (this.selectedId && this.idToNodeMap_[this.selectedId])
|
| + this.set(
|
| + this.idToNodeMap_[this.selectedId].path + '.isSelectedFolder', false);
|
|
|
| // Check if the selected id is that of a defined folder.
|
| var id = /** @type {string} */ (e.detail);
|
| @@ -231,7 +358,7 @@ var BookmarksStore = Polymer({
|
| id = this.rootNode.children[0].id;
|
|
|
| var newFolder = this.idToNodeMap_[id];
|
| - this.set(newFolder.path + '.isSelected', true);
|
| + this.set(newFolder.path + '.isSelectedFolder', true);
|
| this.selectedId = id;
|
| },
|
|
|
| @@ -246,6 +373,21 @@ var BookmarksStore = Polymer({
|
| if (!folder.isOpen && this.isAncestorOfSelected_(folder))
|
| this.fire('selected-folder-changed', folder.id);
|
| },
|
| +
|
| + /**
|
| + * Selects items according to keyboard behaviours.
|
| + * @param {CustomEvent} e
|
| + * @private
|
| + */
|
| + onItemSelected_: function(e) {
|
| + if (!e.detail.add)
|
| + this.clearSelectedItems_();
|
| +
|
| + if (e.detail.range)
|
| + this.selectRange_(e.detail.item);
|
| + else
|
| + this.selectItem_(e.detail.item);
|
| + },
|
| });
|
|
|
| ////////////////////////////////////////////////////////////////////////////////
|
| @@ -275,13 +417,14 @@ BookmarksStore.generatePaths = function(bookmarkNode, startIndex) {
|
| * @param {Object=} idToNodeMap
|
| */
|
| BookmarksStore.initNodes = function(bookmarkNode, idToNodeMap) {
|
| + bookmarkNode.isSelectedItem = false;
|
| if (idToNodeMap)
|
| idToNodeMap[bookmarkNode.id] = bookmarkNode;
|
|
|
| if (bookmarkNode.url)
|
| return;
|
|
|
| - bookmarkNode.isSelected = false;
|
| + bookmarkNode.isSelectedFolder = false;
|
| bookmarkNode.isOpen = true;
|
| for (var i = 0; i < bookmarkNode.children.length; i++)
|
| BookmarksStore.initNodes(bookmarkNode.children[i], idToNodeMap);
|
|
|