Commit 98f40af6 authored by jiaxi's avatar jiaxi Committed by Commit bot

[MD Bookmarks] Add Delete and Copy URL for Material Bookmarks.

This CL adds delete bookmarks and folders function and copy URL function.

BUG=651980
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation

Review-Url: https://codereview.chromium.org/2613683002
Cr-Commit-Position: refs/heads/master@{#441864}
parent fc294079
......@@ -9,14 +9,14 @@ Polymer({
/** @type {BookmarkTreeNode} */
item: {
type: Object,
observer: 'onItemChanged_'
observer: 'onItemChanged_',
},
isFolder_: Boolean,
},
observers: [
'updateFavicon_(item.url)'
'updateFavicon_(item.url)',
],
/**
......@@ -24,8 +24,9 @@ Polymer({
* @private
*/
onMenuButtonOpenTap_: function(e) {
this.fire('toggle-menu', {
target: e.target
this.fire('open-item-menu', {
target: e.target,
item: this.item
});
},
......@@ -37,5 +38,5 @@ Polymer({
/** @private */
updateFavicon_: function(url) {
this.$.icon.style.backgroundImage = cr.icon.getFavicon(url);
}
},
});
......@@ -8,17 +8,21 @@ Polymer({
properties: {
/** @type {BookmarkTreeNode} */
selectedNode: Object,
/** @type {BookmarkTreeNode} */
menuItem_: Object,
},
listeners: {
'toggle-menu': 'onToggleMenu_'
'open-item-menu': 'onOpenItemMenu_',
},
/**
* @param {Event} e
* @private
*/
onToggleMenu_: function(e) {
onOpenItemMenu_: function(e) {
this.menuItem_ = e.detail.item;
var menu = /** @type {!CrActionMenuElement} */ (
this.$.dropdown);
menu.showAt(/** @type {!Element} */ (e.detail.target));
......@@ -32,11 +36,24 @@ Polymer({
/** @private */
onCopyURLTap_: function() {
var idList = [this.menuItem_.id];
chrome.bookmarkManagerPrivate.copy(idList, function() {
// TODO(jiaxi): Add toast later.
});
this.closeDropdownMenu_();
},
/** @private */
onDeleteTap_: function() {
if (this.menuItem_.children) {
chrome.bookmarks.removeTree(this.menuItem_.id, function() {
// TODO(jiaxi): Add toast later.
}.bind(this));
} else {
chrome.bookmarks.remove(this.menuItem_.id, function() {
// TODO(jiaxi): Add toast later.
}.bind(this));
}
this.closeDropdownMenu_();
},
......
......@@ -55,6 +55,7 @@ Polymer({
chrome.bookmarks.getTree(function(results) {
this.setupStore_(results[0]);
}.bind(this));
chrome.bookmarks.onRemoved.addListener(this.onBookmarkRemoved_.bind(this));
},
/**
......@@ -65,6 +66,7 @@ Polymer({
this.rootNode = rootNode;
this.idToNodeMap_ = {};
this.rootNode.path = 'rootNode';
this.generatePaths_(rootNode, 0);
this.initNodes_(this.rootNode);
this.fire('selected-folder-changed', this.rootNode.children[0].id);
},
......@@ -114,11 +116,29 @@ Polymer({
this._setSelectedNode(selectedNode);
},
/**
* Callback for when a bookmark node is removed.
* If a folder is selected or is an ancestor of a selected folder, the parent
* of the removed folder will be selected.
* @param {string} id The id of the removed bookmark node.
* @param {!{index: number,
* parentId: string,
* 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);
this.generatePaths_(parentNode, removeInfo.index);
},
/**
* Initializes the nodes in the bookmarks tree as follows:
* - Populates |idToNodeMap_| with a mapping of all node ids to their
* corresponding BookmarkTreeNode.
* - Stores the path from the store to a node inside the node.
* - Sets all the nodes to not selected and open by default.
* @param {BookmarkTreeNode} bookmarkNode
* @private
......@@ -131,8 +151,40 @@ Polymer({
bookmarkNode.isSelected = false;
bookmarkNode.isOpen = true;
for (var i = 0; i < bookmarkNode.children.length; i++) {
bookmarkNode.children[i].path = bookmarkNode.path + '.children.' + i;
this.initNodes_(bookmarkNode.children[i]);
}
},
/**
* Stores the path from the store to a node inside the node.
* @param {BookmarkTreeNode} bookmarkNode
* @param {number} startIndex
* @private
*/
generatePaths_: function(bookmarkNode, startIndex) {
if (!bookmarkNode.children)
return;
for (var i = startIndex; i < bookmarkNode.children.length; i++) {
bookmarkNode.children[i].path = bookmarkNode.path + '.children.#' + i;
this.generatePaths_(bookmarkNode.children[i], 0);
}
},
/**
* Remove all descendants of a given node from the map.
* @param {string} id
* @private
*/
removeDescendantsFromMap_: function(id) {
var node = this.idToNodeMap_[id];
if (!node)
return;
if (node.children) {
for (var i = 0; i < node.children.length; i++)
this.removeDescendantsFromMap_(node.children[i].id);
}
delete this.idToNodeMap_[id];
}
});
......@@ -4,9 +4,12 @@
suite('<bookmarks-store>', function() {
var store;
var TEST_TREE = {
id: '0',
children: [
var TEST_TREE;
setup(function() {
TEST_TREE = {
id: '0',
children: [
{
id: '1',
children: [
......@@ -19,9 +22,7 @@ suite('<bookmarks-store>', function() {
]
};
setup(function() {
store = document.createElement('bookmarks-store');
store.isTesting_ = true;
replaceBody(store);
store.setupStore_(TEST_TREE);
});
......@@ -53,11 +54,11 @@ suite('<bookmarks-store>', function() {
test('correct paths generated for nodes', function() {
var TEST_PATHS = {
'0': 'rootNode',
'1': 'rootNode.children.0',
'2': 'rootNode.children.0.children.0',
'3': 'rootNode.children.0.children.1',
'4': 'rootNode.children.1',
'5': 'rootNode.children.2',
'1': 'rootNode.children.#0',
'2': 'rootNode.children.#0.children.#0',
'3': 'rootNode.children.#0.children.#1',
'4': 'rootNode.children.#1',
'5': 'rootNode.children.#2',
};
for (var id in store.idToNodeMap_)
......@@ -110,4 +111,64 @@ suite('<bookmarks-store>', function() {
assertTrue(store.idToNodeMap_['1'].isSelected);
assertFalse(store.idToNodeMap_['3'].isSelected);
});
test('deleting a node updates the tree', function() {
// Remove an empty folder/bookmark.
store.onBookmarkRemoved_('4', {parentId: '0', index: '1'});
// Check the tree is correct.
assertEquals('5', store.rootNode.children[1].id);
// idToNodeMap_ has been updated.
assertEquals(undefined, store.idToNodeMap_['4']);
assertEquals(store.rootNode.children[1], store.idToNodeMap_['5']);
// Paths have been updated.
var TEST_PATHS = {
'0': 'rootNode',
'1': 'rootNode.children.#0',
'2': 'rootNode.children.#0.children.#0',
'3': 'rootNode.children.#0.children.#1',
'5': 'rootNode.children.#1',
};
for (var id in store.idToNodeMap_)
assertEquals(TEST_PATHS[id], store.idToNodeMap_[id].path);
// Remove a folder with children.
store.onBookmarkRemoved_('1', {parentId: '0', index: '0'});
// Check the tree is correct.
assertEquals('5', store.rootNode.children[0].id);
// idToNodeMap_ has been updated.
assertEquals(undefined, store.idToNodeMap_['1']);
assertEquals(undefined, store.idToNodeMap_['2']);
assertEquals(undefined, store.idToNodeMap_['3']);
assertEquals(undefined, store.idToNodeMap_['4']);
assertEquals(store.rootNode.children[0], store.idToNodeMap_['5']);
// Paths have been updated.
TEST_PATHS = {
'0': 'rootNode',
'5': 'rootNode.children.#0',
};
for (var id in store.idToNodeMap_)
assertEquals(TEST_PATHS[id], store.idToNodeMap_[id].path);
});
test('selectedId updates after removing a selected folder', function() {
// Selected folder gets removed.
store.selectedId = '2';
store.onBookmarkRemoved_('2', {parentId:'1', index:'0'});
assertTrue(store.idToNodeMap_['1'].isSelected);
assertEquals('1', store.selectedId);
// A folder with selected folder in it gets removed.
store.selectedId = '3';
store.onBookmarkRemoved_('1', {parentId:'0', index:'0'});
assertTrue(store.idToNodeMap_['0'].isSelected);
assertEquals('0', store.selectedId);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment