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

Side by Side Diff: chrome/browser/resources/md_bookmarks/command_manager.js

Issue 2864993002: MD Bookmarks: Add commands for 'Open in <x>' menu items (Closed)
Patch Set: Review comments Created 3 years, 7 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 unified diff | Download patch
OLDNEW
1 // Copyright 2017 The Chromium Authors. All rights reserved. 1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 Polymer({ 5 Polymer({
6 is: 'bookmarks-command-manager', 6 is: 'bookmarks-command-manager',
7 7
8 behaviors: [ 8 behaviors: [
9 bookmarks.StoreClient, 9 bookmarks.StoreClient,
10 ], 10 ],
11 11
12 properties: { 12 properties: {
13 /** @private {!Array<Command>} */
14 menuCommands_: {
15 type: Array,
16 value: function() {
17 return [
18 Command.EDIT,
19 Command.COPY,
20 Command.DELETE,
21 // <hr>
22 Command.OPEN_NEW_TAB,
23 Command.OPEN_NEW_WINDOW,
24 Command.OPEN_INCOGNITO,
25 ];
26 },
27 },
28
13 /** @type {Set<string>} */ 29 /** @type {Set<string>} */
14 menuIds_: Object, 30 menuIds_: Object,
15 }, 31 },
16 32
17 attached: function() { 33 attached: function() {
18 /** @private {function(!Event)} */ 34 /** @private {function(!Event)} */
19 this.boundOnOpenItemMenu_ = this.onOpenItemMenu_.bind(this); 35 this.boundOnOpenItemMenu_ = this.onOpenItemMenu_.bind(this);
20 document.addEventListener('open-item-menu', this.boundOnOpenItemMenu_); 36 document.addEventListener('open-item-menu', this.boundOnOpenItemMenu_);
21 37
22 /** @private {function(!Event)} */ 38 /** @private {function(!Event)} */
23 this.boundOnKeydown_ = this.onKeydown_.bind(this); 39 this.boundOnKeydown_ = this.onKeydown_.bind(this);
24 document.addEventListener('keydown', this.boundOnKeydown_); 40 document.addEventListener('keydown', this.boundOnKeydown_);
25 41
26 /** @private {Object<Command, string>} */ 42 /** @private {Object<Command, string>} */
27 this.shortcuts_ = {}; 43 this.shortcuts_ = {};
28 this.shortcuts_[Command.EDIT] = cr.isMac ? 'enter' : 'f2'; 44 this.shortcuts_[Command.EDIT] = cr.isMac ? 'enter' : 'f2';
29 this.shortcuts_[Command.COPY] = cr.isMac ? 'meta+c' : 'ctrl+c'; 45 this.shortcuts_[Command.COPY] = cr.isMac ? 'meta+c' : 'ctrl+c';
30 this.shortcuts_[Command.DELETE] = cr.isMac ? 'delete backspace' : 'delete'; 46 this.shortcuts_[Command.DELETE] = cr.isMac ? 'delete backspace' : 'delete';
47 this.shortcuts_[Command.OPEN_NEW_TAB] =
48 cr.isMac ? 'meta+enter' : 'ctrl+enter';
49 this.shortcuts_[Command.OPEN_NEW_WINDOW] = 'shift+enter';
31 }, 50 },
32 51
33 detached: function() { 52 detached: function() {
34 document.removeEventListener('open-item-menu', this.boundOnOpenItemMenu_); 53 document.removeEventListener('open-item-menu', this.boundOnOpenItemMenu_);
35 document.removeEventListener('keydown', this.boundOnKeydown_); 54 document.removeEventListener('keydown', this.boundOnKeydown_);
36 }, 55 },
37 56
38 /** 57 /**
39 * Display the command context menu at (|x|, |y|) in window co-ordinates. 58 * Display the command context menu at (|x|, |y|) in window co-ordinates.
40 * Commands will execute on the currently selected items. 59 * Commands will execute on the currently selected items.
(...skipping 17 matching lines...) Expand all
58 }, 77 },
59 78
60 closeCommandMenu: function() { 79 closeCommandMenu: function() {
61 /** @type {!CrActionMenuElement} */ (this.$.dropdown).close(); 80 /** @type {!CrActionMenuElement} */ (this.$.dropdown).close();
62 }, 81 },
63 82
64 //////////////////////////////////////////////////////////////////////////// 83 ////////////////////////////////////////////////////////////////////////////
65 // Command handlers: 84 // Command handlers:
66 85
67 /** 86 /**
87 * Determine if the |command| can be executed with the given |itemIds|.
88 * Commands which appear in the context menu should be implemented separately
89 * using `isCommandVisible_` and `isCommandEnabled_`.
68 * @param {Command} command 90 * @param {Command} command
69 * @param {!Set<string>} itemIds 91 * @param {!Set<string>} itemIds
70 * @return {boolean} 92 * @return {boolean}
71 */ 93 */
72 canExecute: function(command, itemIds) { 94 canExecute: function(command, itemIds) {
95 return this.isCommandVisible_(command, itemIds) &&
96 this.isCommandEnabled_(command, itemIds);
97 },
98
99 /**
100 * @param {Command} command
101 * @param {!Set<string>} itemIds
102 * @return {boolean} True if the command should be visible in the context
103 * menu.
104 */
105 isCommandVisible_: function(command, itemIds) {
73 switch (command) { 106 switch (command) {
74 case Command.EDIT: 107 case Command.EDIT:
75 return itemIds.size == 1; 108 return itemIds.size == 1;
76 case Command.COPY: 109 case Command.COPY:
77 return itemIds.size == 1 && 110 return itemIds.size == 1 &&
78 this.containsMatchingNode_(itemIds, function(node) { 111 this.containsMatchingNode_(itemIds, function(node) {
79 return !!node.url; 112 return !!node.url;
80 }); 113 });
81 case Command.DELETE: 114 case Command.DELETE:
115 case Command.OPEN_NEW_TAB:
116 case Command.OPEN_NEW_WINDOW:
117 case Command.OPEN_INCOGNITO:
82 return itemIds.size > 0; 118 return itemIds.size > 0;
83 default: 119 default:
84 return false; 120 return false;
85 } 121 }
86 }, 122 },
87 123
88 /** 124 /**
89 * @param {Command} command 125 * @param {Command} command
90 * @param {!Set<string>} itemIds 126 * @param {!Set<string>} itemIds
127 * @return {boolean} True if the command should be clickable in the context
128 * menu.
129 */
130 isCommandEnabled_: function(command, itemIds) {
131 switch (command) {
132 case Command.OPEN_NEW_TAB:
133 case Command.OPEN_NEW_WINDOW:
134 case Command.OPEN_INCOGNITO:
135 return this.expandUrls_(itemIds).length > 0;
136 default:
137 return true;
138 }
139 },
140
141 /**
142 * @param {Command} command
143 * @param {!Set<string>} itemIds
91 */ 144 */
92 handle: function(command, itemIds) { 145 handle: function(command, itemIds) {
93 switch (command) { 146 switch (command) {
94 case Command.EDIT: 147 case Command.EDIT:
95 var id = Array.from(itemIds)[0]; 148 var id = Array.from(itemIds)[0];
96 /** @type {!BookmarksEditDialogElement} */ (this.$.editDialog.get()) 149 /** @type {!BookmarksEditDialogElement} */ (this.$.editDialog.get())
97 .showEditDialog(this.getState().nodes[id]); 150 .showEditDialog(this.getState().nodes[id]);
98 break; 151 break;
99 case Command.COPY: 152 case Command.COPY:
100 var idList = Array.from(itemIds); 153 var idList = Array.from(itemIds);
101 chrome.bookmarkManagerPrivate.copy(idList, function() { 154 chrome.bookmarkManagerPrivate.copy(idList, function() {
102 // TODO(jiaxi): Add toast later. 155 // TODO(jiaxi): Add toast later.
103 }); 156 });
104 break; 157 break;
105 case Command.DELETE: 158 case Command.DELETE:
106 chrome.bookmarkManagerPrivate.removeTrees( 159 chrome.bookmarkManagerPrivate.removeTrees(
107 Array.from(this.minimizeDeletionSet_(itemIds)), function() { 160 Array.from(this.minimizeDeletionSet_(itemIds)), function() {
108 // TODO(jiaxi): Add toast later. 161 // TODO(jiaxi): Add toast later.
109 }); 162 });
110 break; 163 break;
164 case Command.OPEN_NEW_TAB:
165 case Command.OPEN_NEW_WINDOW:
166 case Command.OPEN_INCOGNITO:
167 this.openUrls_(this.expandUrls_(itemIds), command);
168 break;
111 } 169 }
112 }, 170 },
113 171
114 //////////////////////////////////////////////////////////////////////////// 172 ////////////////////////////////////////////////////////////////////////////
115 // Private functions: 173 // Private functions:
116 174
117 /** 175 /**
118 * Minimize the set of |itemIds| by removing any node which has an ancestor 176 * Minimize the set of |itemIds| by removing any node which has an ancestor
119 * node already in the set. This ensures that instead of trying to delete both 177 * node already in the set. This ensures that instead of trying to delete both
120 * a node and its descendant, we will only try to delete the topmost node, 178 * a node and its descendant, we will only try to delete the topmost node,
(...skipping 10 matching lines...) Expand all
131 currentId = assert(nodes[currentId].parentId); 189 currentId = assert(nodes[currentId].parentId);
132 if (itemIds.has(currentId)) 190 if (itemIds.has(currentId))
133 return; 191 return;
134 } 192 }
135 minimizedSet.add(itemId); 193 minimizedSet.add(itemId);
136 }); 194 });
137 return minimizedSet; 195 return minimizedSet;
138 }, 196 },
139 197
140 /** 198 /**
199 * @param {!Array<string>} urls
200 * @param {Command} command
201 * @private
202 */
203 openUrls_: function(urls, command) {
204 assert(
205 command == Command.OPEN_NEW_TAB || command == Command.OPEN_NEW_WINDOW ||
206 command == Command.OPEN_INCOGNITO);
207
208 if (urls.length == 0)
209 return;
210
211 var incognito = command == Command.OPEN_INCOGNITO;
212 if (command == Command.OPEN_NEW_WINDOW || incognito) {
213 chrome.windows.create({url: urls, incognito: incognito});
214 } else {
215 urls.forEach(function(url) {
216 chrome.tabs.create({url: url, active: false});
217 });
218 }
219 },
220
221 /**
222 * Returns all URLs in the given set of nodes and their immediate children.
223 * Note that these will be ordered by insertion order into the |itemIds| set,
224 * and that it is possible to duplicate a URL by passing in both the parent ID
225 * and child ID.
226 * @param {!Set<string>} itemIds
227 * @return {!Array<string>}
228 * @private
229 */
230 expandUrls_: function(itemIds) {
231 var urls = [];
232 var nodes = this.getState().nodes;
233
234 itemIds.forEach(function(id) {
235 var node = nodes[id];
236 if (node.url) {
237 urls.push(node.url);
238 } else {
239 node.children.forEach(function(childId) {
240 var childNode = nodes[childId];
241 if (childNode.url)
242 urls.push(childNode.url);
243 });
244 }
245 });
246
247 return urls;
248 },
249
250 /**
141 * @param {!Set<string>} itemIds 251 * @param {!Set<string>} itemIds
142 * @param {function(BookmarkNode):boolean} predicate 252 * @param {function(BookmarkNode):boolean} predicate
143 * @return {boolean} True if any node in |itemIds| returns true for 253 * @return {boolean} True if any node in |itemIds| returns true for
144 * |predicate|. 254 * |predicate|.
145 */ 255 */
146 containsMatchingNode_: function(itemIds, predicate) { 256 containsMatchingNode_: function(itemIds, predicate) {
147 var nodes = this.getState().nodes; 257 var nodes = this.getState().nodes;
148 258
149 return Array.from(itemIds).some(function(id) { 259 return Array.from(itemIds).some(function(id) {
150 return predicate(nodes[id]); 260 return predicate(nodes[id]);
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 * @param {Event} e 310 * @param {Event} e
201 * @private 311 * @private
202 */ 312 */
203 onMenuMousedown_: function(e) { 313 onMenuMousedown_: function(e) {
204 if (e.path[0] != this.$.dropdown) 314 if (e.path[0] != this.$.dropdown)
205 return; 315 return;
206 316
207 this.$.dropdown.close(); 317 this.$.dropdown.close();
208 }, 318 },
209 319
210 /** @private */ 320 /**
211 getEditActionLabel_: function() { 321 * @param {Command} command
212 if (this.menuIds_.size > 1) 322 * @return {string}
213 return; 323 * @private
324 */
325 getCommandLabel_: function(command) {
326 var multipleNodes = this.menuIds_.size > 1 ||
327 this.containsMatchingNode_(this.menuIds_, function(node) {
328 return !node.url;
329 });
330 var label;
331 switch (command) {
332 case Command.EDIT:
333 if (this.menuIds_.size > 1)
334 return '';
214 335
215 var id = Array.from(this.menuIds_)[0]; 336 var id = Array.from(this.menuIds_)[0];
216 var itemUrl = this.getState().nodes[id].url; 337 var itemUrl = this.getState().nodes[id].url;
217 var label = itemUrl ? 'menuEdit' : 'menuRename'; 338 label = itemUrl ? 'menuEdit' : 'menuRename';
218 return loadTimeData.getString(label); 339 break;
340 case Command.COPY:
341 label = 'menuCopyURL';
342 break;
343 case Command.DELETE:
344 label = 'menuDelete';
345 break;
346 case Command.OPEN_NEW_TAB:
347 label = multipleNodes ? 'menuOpenAllNewTab' : 'menuOpenNewTab';
348 break;
349 case Command.OPEN_NEW_WINDOW:
350 label = multipleNodes ? 'menuOpenAllNewWindow' : 'menuOpenNewWindow';
351 break;
352 case Command.OPEN_INCOGNITO:
353 label = multipleNodes ? 'menuOpenAllIncognito' : 'menuOpenIncognito';
354 break;
355 }
356
357 return loadTimeData.getString(assert(label));
358 },
359
360 /**
361 * @param {Command} command
362 * @return {boolean}
363 * @private
364 */
365 showDividerAfter_: function(command) {
366 return command == Command.DELETE;
219 }, 367 },
220 }); 368 });
OLDNEW
« no previous file with comments | « chrome/browser/resources/md_bookmarks/command_manager.html ('k') | chrome/browser/resources/md_bookmarks/constants.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698