Index: chrome/browser/resources/md_bookmarks/command_manager.js |
diff --git a/chrome/browser/resources/md_bookmarks/command_manager.js b/chrome/browser/resources/md_bookmarks/command_manager.js |
index a21c9c471868ec0e2bdcb6484d27bb132b9670f8..6e9565b8ae30c7e6017619bdd0a23d14df25d646 100644 |
--- a/chrome/browser/resources/md_bookmarks/command_manager.js |
+++ b/chrome/browser/resources/md_bookmarks/command_manager.js |
@@ -10,6 +10,22 @@ Polymer({ |
], |
properties: { |
+ /** @private {!Array<Command>} */ |
+ menuCommands_: { |
+ type: Array, |
+ value: function() { |
+ return [ |
+ Command.EDIT, |
+ Command.COPY, |
+ Command.DELETE, |
+ // <hr> |
+ Command.OPEN_NEW_TAB, |
+ Command.OPEN_NEW_WINDOW, |
+ Command.OPEN_INCOGNITO, |
+ ]; |
+ }, |
+ }, |
+ |
/** @type {Set<string>} */ |
menuIds_: Object, |
}, |
@@ -28,6 +44,9 @@ Polymer({ |
this.shortcuts_[Command.EDIT] = cr.isMac ? 'enter' : 'f2'; |
this.shortcuts_[Command.COPY] = cr.isMac ? 'meta+c' : 'ctrl+c'; |
this.shortcuts_[Command.DELETE] = cr.isMac ? 'delete backspace' : 'delete'; |
+ this.shortcuts_[Command.OPEN_NEW_TAB] = |
+ cr.isMac ? 'meta+enter' : 'ctrl+enter'; |
+ this.shortcuts_[Command.OPEN_NEW_WINDOW] = 'shift+enter'; |
}, |
detached: function() { |
@@ -65,11 +84,25 @@ Polymer({ |
// Command handlers: |
/** |
+ * Determine if the |command| can be executed with the given |itemIds|. |
+ * Commands which appear in the context menu should be implemented separately |
+ * using `isCommandVisible_` and `isCommandEnabled_`. |
* @param {Command} command |
* @param {!Set<string>} itemIds |
* @return {boolean} |
*/ |
canExecute: function(command, itemIds) { |
+ return this.isCommandVisible_(command, itemIds) && |
+ this.isCommandEnabled_(command, itemIds); |
+ }, |
+ |
+ /** |
+ * @param {Command} command |
+ * @param {!Set<string>} itemIds |
+ * @return {boolean} True if the command should be visible in the context |
+ * menu. |
+ */ |
+ isCommandVisible_: function(command, itemIds) { |
switch (command) { |
case Command.EDIT: |
return itemIds.size == 1; |
@@ -79,12 +112,32 @@ Polymer({ |
return !!node.url; |
}); |
case Command.DELETE: |
+ case Command.OPEN_NEW_TAB: |
+ case Command.OPEN_NEW_WINDOW: |
+ case Command.OPEN_INCOGNITO: |
return itemIds.size > 0; |
default: |
return false; |
} |
}, |
+ /** |
+ * @param {Command} command |
+ * @param {!Set<string>} itemIds |
+ * @return {boolean} True if the command should be clickable in the context |
+ * menu. |
+ */ |
+ isCommandEnabled_: function(command, itemIds) { |
+ switch (command) { |
+ case Command.OPEN_NEW_TAB: |
+ case Command.OPEN_NEW_WINDOW: |
+ case Command.OPEN_INCOGNITO: |
+ return this.expandUrls_(itemIds).length > 0; |
+ default: |
+ return true; |
+ } |
+ }, |
+ |
/** |
* @param {Command} command |
* @param {!Set<string>} itemIds |
@@ -108,6 +161,11 @@ Polymer({ |
// TODO(jiaxi): Add toast later. |
}); |
break; |
+ case Command.OPEN_NEW_TAB: |
+ case Command.OPEN_NEW_WINDOW: |
+ case Command.OPEN_INCOGNITO: |
+ this.openUrls_(this.expandUrls_(itemIds), command); |
+ break; |
} |
}, |
@@ -137,6 +195,56 @@ Polymer({ |
return minimizedSet; |
}, |
+ /** |
+ * @param {!Array<string>} urls |
+ * @param {Command} command |
+ * @private |
+ */ |
+ openUrls_: function(urls, command) { |
+ assert( |
+ command == Command.OPEN_NEW_TAB || command == Command.OPEN_NEW_WINDOW || |
+ command == Command.OPEN_INCOGNITO); |
+ |
+ if (urls.length == 0) |
+ return; |
+ |
+ var incognito = command == Command.OPEN_INCOGNITO; |
+ if (command == Command.OPEN_NEW_WINDOW || incognito) { |
+ chrome.windows.create({url: urls, incognito: incognito}); |
+ } else { |
+ urls.forEach(function(url) { |
+ chrome.tabs.create({url: url, active: false}); |
+ }); |
+ } |
+ }, |
+ |
+ /** |
+ * Returns all URLs in the given set of nodes and their immediate children. |
+ * Note that these will be ordered by insertion order into the |itemIds| set. |
calamity
2017/05/12 03:22:52
Mention that this assumes itemIds are all at the s
tsergeant
2017/05/12 05:15:27
As discussed, it doesn't assume that, but I've exp
|
+ * @param {!Set<string>} itemIds |
+ * @return {!Array<string>} |
+ * @private |
+ */ |
+ expandUrls_: function(itemIds) { |
+ var urls = []; |
+ var nodes = this.getState().nodes; |
+ |
+ itemIds.forEach(function(id) { |
+ var node = nodes[id]; |
+ if (node.url) { |
+ urls.push(node.url); |
+ } else { |
+ node.children.forEach(function(childId) { |
+ var childNode = nodes[childId]; |
+ if (childNode.url) |
+ urls.push(childNode.url); |
+ }); |
+ } |
+ }); |
+ |
+ return urls; |
+ }, |
+ |
/** |
* @param {!Set<string>} itemIds |
* @param {function(BookmarkNode):boolean} predicate |
@@ -207,14 +315,52 @@ Polymer({ |
this.$.dropdown.close(); |
}, |
- /** @private */ |
- getEditActionLabel_: function() { |
- if (this.menuIds_.size > 1) |
- return; |
+ /** |
+ * @param {Command} command |
+ * @return {string} |
+ * @private |
+ */ |
+ getCommandLabel_: function(command) { |
+ var multipleNodes = this.menuIds_.size > 1 || |
+ this.containsMatchingNode_(this.menuIds_, function(node) { |
+ return !node.url; |
+ }); |
+ var label; |
+ switch (command) { |
+ case Command.EDIT: |
+ if (this.menuIds_.size > 1) |
+ return ''; |
+ |
+ var id = Array.from(this.menuIds_)[0]; |
+ var itemUrl = this.getState().nodes[id].url; |
+ label = itemUrl ? 'menuEdit' : 'menuRename'; |
+ break; |
+ case Command.COPY: |
+ label = 'menuCopyURL'; |
+ break; |
+ case Command.DELETE: |
+ label = 'menuDelete'; |
+ break; |
+ case Command.OPEN_NEW_TAB: |
+ label = multipleNodes ? 'menuOpenAllNewTab' : 'menuOpenNewTab'; |
+ break; |
+ case Command.OPEN_NEW_WINDOW: |
+ label = multipleNodes ? 'menuOpenAllNewWindow' : 'menuOpenNewWindow'; |
+ break; |
+ case Command.OPEN_INCOGNITO: |
+ label = multipleNodes ? 'menuOpenAllIncognito' : 'menuOpenIncognito'; |
+ break; |
+ } |
+ |
+ return loadTimeData.getString(assert(label)); |
+ }, |
- var id = Array.from(this.menuIds_)[0]; |
- var itemUrl = this.getState().nodes[id].url; |
- var label = itemUrl ? 'menuEdit' : 'menuRename'; |
- return loadTimeData.getString(label); |
+ /** |
+ * @param {Command} command |
+ * @return {boolean} |
+ * @private |
+ */ |
+ showDividerAfter_: function(command) { |
+ return command == Command.DELETE; |
}, |
}); |