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

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

Issue 2872163002: MD Bookmarks: Add 'Open' command, to open in either the BMM or in new tabs (Closed)
Patch Set: Open items with middle-click 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
« no previous file with comments | « no previous file | chrome/browser/resources/md_bookmarks/constants.js » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 cr.define('bookmarks', function() {
6 is: 'bookmarks-command-manager', 6
7 7 var CommandManager = Polymer({
8 behaviors: [ 8 is: 'bookmarks-command-manager',
9 bookmarks.StoreClient, 9
10 ], 10 behaviors: [
11 11 bookmarks.StoreClient,
12 properties: { 12 ],
13 /** @private {!Array<Command>} */ 13
14 menuCommands_: { 14 properties: {
15 type: Array, 15 /** @private {!Array<Command>} */
16 value: function() { 16 menuCommands_: {
17 return [ 17 type: Array,
18 Command.EDIT, 18 value: function() {
19 Command.COPY, 19 return [
20 Command.DELETE, 20 Command.EDIT,
21 // <hr> 21 Command.COPY,
22 Command.OPEN_NEW_TAB, 22 Command.DELETE,
23 Command.OPEN_NEW_WINDOW, 23 // <hr>
24 Command.OPEN_INCOGNITO, 24 Command.OPEN_NEW_TAB,
25 ]; 25 Command.OPEN_NEW_WINDOW,
26 Command.OPEN_INCOGNITO,
27 ];
28 },
26 }, 29 },
27 }, 30
28 31 /** @type {Set<string>} */
29 /** @type {Set<string>} */ 32 menuIds_: Object,
30 menuIds_: Object, 33 },
31 }, 34
32 35 attached: function() {
33 attached: function() { 36 assert(CommandManager.instance_ == null);
34 /** @private {function(!Event)} */ 37 CommandManager.instance_ = this;
35 this.boundOnOpenItemMenu_ = this.onOpenItemMenu_.bind(this); 38
36 document.addEventListener('open-item-menu', this.boundOnOpenItemMenu_); 39 /** @private {function(!Event)} */
37 40 this.boundOnOpenItemMenu_ = this.onOpenItemMenu_.bind(this);
38 /** @private {function(!Event)} */ 41 document.addEventListener('open-item-menu', this.boundOnOpenItemMenu_);
39 this.boundOnKeydown_ = this.onKeydown_.bind(this); 42
40 document.addEventListener('keydown', this.boundOnKeydown_); 43 /** @private {function(!Event)} */
41 44 this.boundOnKeydown_ = this.onKeydown_.bind(this);
42 /** @private {Object<Command, string>} */ 45 document.addEventListener('keydown', this.boundOnKeydown_);
43 this.shortcuts_ = {}; 46
44 this.shortcuts_[Command.EDIT] = cr.isMac ? 'enter' : 'f2'; 47 /** @private {Object<Command, string>} */
45 this.shortcuts_[Command.COPY] = cr.isMac ? 'meta+c' : 'ctrl+c'; 48 this.shortcuts_ = {};
46 this.shortcuts_[Command.DELETE] = cr.isMac ? 'delete backspace' : 'delete'; 49 this.shortcuts_[Command.EDIT] = cr.isMac ? 'enter' : 'f2';
47 this.shortcuts_[Command.OPEN_NEW_TAB] = 50 this.shortcuts_[Command.COPY] = cr.isMac ? 'meta+c' : 'ctrl+c';
48 cr.isMac ? 'meta+enter' : 'ctrl+enter'; 51 this.shortcuts_[Command.DELETE] =
49 this.shortcuts_[Command.OPEN_NEW_WINDOW] = 'shift+enter'; 52 cr.isMac ? 'delete backspace' : 'delete';
50 }, 53 this.shortcuts_[Command.OPEN_NEW_TAB] =
51 54 cr.isMac ? 'meta+enter' : 'ctrl+enter';
52 detached: function() { 55 this.shortcuts_[Command.OPEN_NEW_WINDOW] = 'shift+enter';
53 document.removeEventListener('open-item-menu', this.boundOnOpenItemMenu_); 56 this.shortcuts_[Command.OPEN] = cr.isMac ? 'meta+down' : 'enter';
54 document.removeEventListener('keydown', this.boundOnKeydown_); 57 },
55 }, 58
56 59 detached: function() {
57 /** 60 document.removeEventListener('open-item-menu', this.boundOnOpenItemMenu_);
58 * Display the command context menu at (|x|, |y|) in window co-ordinates. 61 document.removeEventListener('keydown', this.boundOnKeydown_);
59 * Commands will execute on the currently selected items. 62
60 * @param {number} x 63 CommandManager.instance_ = null;
61 * @param {number} y 64 },
62 */ 65
63 openCommandMenuAtPosition: function(x, y) { 66 /**
64 this.menuIds_ = this.getState().selection.items; 67 * Display the command context menu at (|x|, |y|) in window co-ordinates.
65 /** @type {!CrActionMenuElement} */ (this.$.dropdown) 68 * Commands will execute on the currently selected items.
66 .showAtPosition({top: y, left: x}); 69 * @param {number} x
67 }, 70 * @param {number} y
68 71 */
69 /** 72 openCommandMenuAtPosition: function(x, y) {
70 * Display the command context menu positioned to cover the |target| 73 this.menuIds_ = this.getState().selection.items;
71 * element. Commands will execute on the currently selected items. 74 /** @type {!CrActionMenuElement} */ (this.$.dropdown)
72 * @param {!Element} target 75 .showAtPosition({top: y, left: x});
73 */ 76 },
74 openCommandMenuAtElement: function(target) { 77
75 this.menuIds_ = this.getState().selection.items; 78 /**
76 /** @type {!CrActionMenuElement} */ (this.$.dropdown).showAt(target); 79 * Display the command context menu positioned to cover the |target|
77 }, 80 * element. Commands will execute on the currently selected items.
78 81 * @param {!Element} target
79 closeCommandMenu: function() { 82 */
80 /** @type {!CrActionMenuElement} */ (this.$.dropdown).close(); 83 openCommandMenuAtElement: function(target) {
81 }, 84 this.menuIds_ = this.getState().selection.items;
82 85 /** @type {!CrActionMenuElement} */ (this.$.dropdown).showAt(target);
83 //////////////////////////////////////////////////////////////////////////// 86 },
84 // Command handlers: 87
85 88 closeCommandMenu: function() {
86 /** 89 /** @type {!CrActionMenuElement} */ (this.$.dropdown).close();
87 * Determine if the |command| can be executed with the given |itemIds|. 90 },
88 * Commands which appear in the context menu should be implemented separately 91
89 * using `isCommandVisible_` and `isCommandEnabled_`. 92 ////////////////////////////////////////////////////////////////////////////
90 * @param {Command} command 93 // Command handlers:
91 * @param {!Set<string>} itemIds 94
92 * @return {boolean} 95 /**
93 */ 96 * Determine if the |command| can be executed with the given |itemIds|.
94 canExecute: function(command, itemIds) { 97 * Commands which appear in the context menu should be implemented
95 return this.isCommandVisible_(command, itemIds) && 98 * separately using `isCommandVisible_` and `isCommandEnabled_`.
96 this.isCommandEnabled_(command, itemIds); 99 * @param {Command} command
97 }, 100 * @param {!Set<string>} itemIds
98 101 * @return {boolean}
99 /** 102 */
100 * @param {Command} command 103 canExecute: function(command, itemIds) {
101 * @param {!Set<string>} itemIds 104 switch (command) {
102 * @return {boolean} True if the command should be visible in the context 105 case Command.OPEN:
103 * menu. 106 return itemIds.size > 0;
104 */ 107 default:
105 isCommandVisible_: function(command, itemIds) { 108 return this.isCommandVisible_(command, itemIds) &&
106 switch (command) { 109 this.isCommandEnabled_(command, itemIds);
107 case Command.EDIT: 110 }
108 return itemIds.size == 1; 111 },
109 case Command.COPY: 112
110 return itemIds.size == 1 && 113 /**
111 this.containsMatchingNode_(itemIds, function(node) { 114 * @param {Command} command
112 return !!node.url; 115 * @param {!Set<string>} itemIds
113 }); 116 * @return {boolean} True if the command should be visible in the context
114 case Command.DELETE: 117 * menu.
115 case Command.OPEN_NEW_TAB: 118 */
116 case Command.OPEN_NEW_WINDOW: 119 isCommandVisible_: function(command, itemIds) {
117 case Command.OPEN_INCOGNITO: 120 switch (command) {
118 return itemIds.size > 0; 121 case Command.EDIT:
119 default: 122 return itemIds.size == 1;
120 return false; 123 case Command.COPY:
121 } 124 return itemIds.size == 1 &&
122 }, 125 this.containsMatchingNode_(itemIds, function(node) {
123 126 return !!node.url;
124 /** 127 });
125 * @param {Command} command 128 case Command.DELETE:
126 * @param {!Set<string>} itemIds 129 case Command.OPEN_NEW_TAB:
127 * @return {boolean} True if the command should be clickable in the context 130 case Command.OPEN_NEW_WINDOW:
128 * menu. 131 case Command.OPEN_INCOGNITO:
129 */ 132 return itemIds.size > 0;
130 isCommandEnabled_: function(command, itemIds) { 133 default:
131 switch (command) { 134 return false;
132 case Command.OPEN_NEW_TAB: 135 }
133 case Command.OPEN_NEW_WINDOW: 136 },
134 case Command.OPEN_INCOGNITO: 137
135 return this.expandUrls_(itemIds).length > 0; 138 /**
136 default: 139 * @param {Command} command
137 return true; 140 * @param {!Set<string>} itemIds
138 } 141 * @return {boolean} True if the command should be clickable in the context
139 }, 142 * menu.
140 143 */
141 /** 144 isCommandEnabled_: function(command, itemIds) {
142 * @param {Command} command 145 switch (command) {
143 * @param {!Set<string>} itemIds 146 case Command.OPEN_NEW_TAB:
144 */ 147 case Command.OPEN_NEW_WINDOW:
145 handle: function(command, itemIds) { 148 case Command.OPEN_INCOGNITO:
146 switch (command) { 149 return this.expandUrls_(itemIds).length > 0;
147 case Command.EDIT: 150 default:
148 var id = Array.from(itemIds)[0]; 151 return true;
149 /** @type {!BookmarksEditDialogElement} */ (this.$.editDialog.get()) 152 }
150 .showEditDialog(this.getState().nodes[id]); 153 },
151 break; 154
152 case Command.COPY: 155 /**
153 var idList = Array.from(itemIds); 156 * @param {Command} command
154 chrome.bookmarkManagerPrivate.copy(idList, function() { 157 * @param {!Set<string>} itemIds
155 // TODO(jiaxi): Add toast later. 158 */
159 handle: function(command, itemIds) {
160 switch (command) {
161 case Command.EDIT:
162 var id = Array.from(itemIds)[0];
163 /** @type {!BookmarksEditDialogElement} */ (this.$.editDialog.get())
164 .showEditDialog(this.getState().nodes[id]);
165 break;
166 case Command.COPY:
167 var idList = Array.from(itemIds);
168 chrome.bookmarkManagerPrivate.copy(idList, function() {
169 // TODO(jiaxi): Add toast later.
170 });
171 break;
172 case Command.DELETE:
173 chrome.bookmarkManagerPrivate.removeTrees(
174 Array.from(this.minimizeDeletionSet_(itemIds)), function() {
175 // TODO(jiaxi): Add toast later.
176 });
177 break;
178 case Command.OPEN_NEW_TAB:
179 case Command.OPEN_NEW_WINDOW:
180 case Command.OPEN_INCOGNITO:
181 this.openUrls_(this.expandUrls_(itemIds), command);
182 break;
183 case Command.OPEN:
184 var isFolder = itemIds.size == 1 &&
185 this.containsMatchingNode_(itemIds, function(node) {
186 return !node.url;
187 });
188 if (isFolder) {
189 var folderId = Array.from(itemIds)[0];
190 this.dispatch(bookmarks.actions.selectFolder(
191 folderId, this.getState().nodes));
192 } else {
193 this.openUrls_(this.expandUrls_(itemIds), command);
194 }
195 break;
196 }
197 },
198
199 ////////////////////////////////////////////////////////////////////////////
200 // Private functions:
201
202 /**
203 * Minimize the set of |itemIds| by removing any node which has an ancestor
204 * node already in the set. This ensures that instead of trying to delete
205 * both a node and its descendant, we will only try to delete the topmost
206 * node, preventing an error in the bookmarkManagerPrivate.removeTrees API
207 * call.
208 * @param {!Set<string>} itemIds
209 * @return {!Set<string>}
210 */
211 minimizeDeletionSet_: function(itemIds) {
212 var minimizedSet = new Set();
213 var nodes = this.getState().nodes;
214 itemIds.forEach(function(itemId) {
215 var currentId = itemId;
216 while (currentId != ROOT_NODE_ID) {
217 currentId = assert(nodes[currentId].parentId);
218 if (itemIds.has(currentId))
219 return;
220 }
221 minimizedSet.add(itemId);
222 });
223 return minimizedSet;
224 },
225
226 /**
227 * @param {!Array<string>} urls
228 * @param {Command} command
229 * @private
230 */
231 openUrls_: function(urls, command) {
232 assert(
233 command == Command.OPEN || command == Command.OPEN_NEW_TAB ||
234 command == Command.OPEN_NEW_WINDOW ||
235 command == Command.OPEN_INCOGNITO);
236
237 if (urls.length == 0)
238 return;
239
240 var incognito = command == Command.OPEN_INCOGNITO;
241 if (command == Command.OPEN_NEW_WINDOW || incognito) {
242 chrome.windows.create({url: urls, incognito: incognito});
243 } else {
244 if (command == Command.OPEN)
245 chrome.tabs.create({url: urls.shift(), active: true});
246 urls.forEach(function(url) {
247 chrome.tabs.create({url: url, active: false});
156 }); 248 });
157 break; 249 }
158 case Command.DELETE: 250 },
159 chrome.bookmarkManagerPrivate.removeTrees( 251
160 Array.from(this.minimizeDeletionSet_(itemIds)), function() { 252 /**
161 // TODO(jiaxi): Add toast later. 253 * Returns all URLs in the given set of nodes and their immediate children.
162 }); 254 * Note that these will be ordered by insertion order into the |itemIds|
163 break; 255 * set.
164 case Command.OPEN_NEW_TAB: 256 * @param {!Set<string>} itemIds
165 case Command.OPEN_NEW_WINDOW: 257 * @return {!Array<string>}
166 case Command.OPEN_INCOGNITO: 258 * @private
167 this.openUrls_(this.expandUrls_(itemIds), command); 259 */
168 break; 260 expandUrls_: function(itemIds) {
169 } 261 var urls = [];
170 }, 262 var nodes = this.getState().nodes;
171 263
172 //////////////////////////////////////////////////////////////////////////// 264 itemIds.forEach(function(id) {
173 // Private functions: 265 var node = nodes[id];
174 266 if (node.url) {
175 /** 267 urls.push(node.url);
176 * Minimize the set of |itemIds| by removing any node which has an ancestor 268 } else {
177 * node already in the set. This ensures that instead of trying to delete both 269 node.children.forEach(function(childId) {
178 * a node and its descendant, we will only try to delete the topmost node, 270 var childNode = nodes[childId];
179 * preventing an error in the bookmarkManagerPrivate.removeTrees API call. 271 if (childNode.url)
180 * @param {!Set<string>} itemIds 272 urls.push(childNode.url);
181 * @return {!Set<string>} 273 });
182 */ 274 }
183 minimizeDeletionSet_: function(itemIds) { 275 });
184 var minimizedSet = new Set(); 276
185 var nodes = this.getState().nodes; 277 return urls;
186 itemIds.forEach(function(itemId) { 278 },
187 var currentId = itemId; 279
188 while (currentId != ROOT_NODE_ID) { 280 /**
189 currentId = assert(nodes[currentId].parentId); 281 * @param {!Set<string>} itemIds
190 if (itemIds.has(currentId)) 282 * @param {function(BookmarkNode):boolean} predicate
283 * @return {boolean} True if any node in |itemIds| returns true for
284 * |predicate|.
285 */
286 containsMatchingNode_: function(itemIds, predicate) {
287 var nodes = this.getState().nodes;
288
289 return Array.from(itemIds).some(function(id) {
290 return predicate(nodes[id]);
291 });
292 },
293
294 /**
295 * @param {Event} e
296 * @private
297 */
298 onOpenItemMenu_: function(e) {
299 if (e.detail.targetElement) {
300 this.openCommandMenuAtElement(e.detail.targetElement);
301 } else {
302 this.openCommandMenuAtPosition(e.detail.x, e.detail.y);
303 }
304 },
305
306 /**
307 * @param {Event} e
308 * @private
309 */
310 onCommandClick_: function(e) {
311 this.closeCommandMenu();
312 this.handle(e.target.getAttribute('command'), assert(this.menuIds_));
313 },
314
315 /**
316 * @param {!Event} e
317 * @private
318 */
319 onKeydown_: function(e) {
320 var selection = this.getState().selection.items;
321 // TODO(tsergeant): Prevent keyboard shortcuts when a dialog is open or
322 // text field is focused.
323 for (var commandName in this.shortcuts_) {
324 var shortcut = this.shortcuts_[commandName];
325 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(
326 e, shortcut) &&
327 this.canExecute(commandName, selection)) {
328 this.handle(commandName, selection);
329
330 e.stopPropagation();
331 e.preventDefault();
191 return; 332 return;
192 } 333 }
193 minimizedSet.add(itemId); 334 }
194 }); 335 },
195 return minimizedSet; 336
196 }, 337 /**
197 338 * Close the menu on mousedown so clicks can propagate to the underlying UI.
198 /** 339 * This allows the user to right click the list while a context menu is
199 * @param {!Array<string>} urls 340 * showing and get another context menu.
200 * @param {Command} command 341 * @param {Event} e
201 * @private 342 * @private
202 */ 343 */
203 openUrls_: function(urls, command) { 344 onMenuMousedown_: function(e) {
204 assert( 345 if (e.path[0] != this.$.dropdown)
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 * @param {!Set<string>} itemIds
225 * @return {!Array<string>}
226 * @private
227 */
228 expandUrls_: function(itemIds) {
229 var urls = [];
230 var nodes = this.getState().nodes;
231
232 itemIds.forEach(function(id) {
233 var node = nodes[id];
234 if (node.url) {
235 urls.push(node.url);
236 } else {
237 node.children.forEach(function(childId) {
238 var childNode = nodes[childId];
239 if (childNode.url)
240 urls.push(childNode.url);
241 });
242 }
243 });
244
245 return urls;
246 },
247
248 /**
249 * @param {!Set<string>} itemIds
250 * @param {function(BookmarkNode):boolean} predicate
251 * @return {boolean} True if any node in |itemIds| returns true for
252 * |predicate|.
253 */
254 containsMatchingNode_: function(itemIds, predicate) {
255 var nodes = this.getState().nodes;
256
257 return Array.from(itemIds).some(function(id) {
258 return predicate(nodes[id]);
259 });
260 },
261
262 /**
263 * @param {Event} e
264 * @private
265 */
266 onOpenItemMenu_: function(e) {
267 if (e.detail.targetElement) {
268 this.openCommandMenuAtElement(e.detail.targetElement);
269 } else {
270 this.openCommandMenuAtPosition(e.detail.x, e.detail.y);
271 }
272 },
273
274 /**
275 * @param {Event} e
276 * @private
277 */
278 onCommandClick_: function(e) {
279 this.closeCommandMenu();
280 this.handle(e.target.getAttribute('command'), assert(this.menuIds_));
281 },
282
283 /**
284 * @param {!Event} e
285 * @private
286 */
287 onKeydown_: function(e) {
288 var selection = this.getState().selection.items;
289 // TODO(tsergeant): Prevent keyboard shortcuts when a dialog is open or text
290 // field is focused.
291 for (var commandName in this.shortcuts_) {
292 var shortcut = this.shortcuts_[commandName];
293 if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(e, shortcut) &&
294 this.canExecute(commandName, selection)) {
295 this.handle(commandName, selection);
296
297 e.stopPropagation();
298 e.preventDefault();
299 return; 346 return;
300 } 347
301 } 348 this.$.dropdown.close();
302 }, 349 },
303 350
304 /** 351 /**
305 * Close the menu on mousedown so clicks can propagate to the underlying UI. 352 * @param {Command} command
306 * This allows the user to right click the list while a context menu is 353 * @return {string}
307 * showing and get another context menu. 354 * @private
308 * @param {Event} e 355 */
309 * @private 356 getCommandLabel_: function(command) {
310 */ 357 var multipleNodes = this.menuIds_.size > 1 ||
311 onMenuMousedown_: function(e) { 358 this.containsMatchingNode_(this.menuIds_, function(node) {
312 if (e.path[0] != this.$.dropdown) 359 return !node.url;
313 return; 360 });
314 361 var label;
315 this.$.dropdown.close(); 362 switch (command) {
316 }, 363 case Command.EDIT:
317 364 if (this.menuIds_.size > 1)
318 /** 365 return '';
319 * @param {Command} command 366
320 * @return {string} 367 var id = Array.from(this.menuIds_)[0];
321 * @private 368 var itemUrl = this.getState().nodes[id].url;
322 */ 369 label = itemUrl ? 'menuEdit' : 'menuRename';
323 getCommandLabel_: function(command) { 370 break;
324 var multipleNodes = this.menuIds_.size > 1 || 371 case Command.COPY:
325 this.containsMatchingNode_(this.menuIds_, function(node) { 372 label = 'menuCopyURL';
326 return !node.url; 373 break;
327 }); 374 case Command.DELETE:
328 var label; 375 label = 'menuDelete';
329 switch (command) { 376 break;
330 case Command.EDIT: 377 case Command.OPEN_NEW_TAB:
331 if (this.menuIds_.size > 1) 378 label = multipleNodes ? 'menuOpenAllNewTab' : 'menuOpenNewTab';
332 return ''; 379 break;
333 380 case Command.OPEN_NEW_WINDOW:
334 var id = Array.from(this.menuIds_)[0]; 381 label = multipleNodes ? 'menuOpenAllNewWindow' : 'menuOpenNewWindow';
335 var itemUrl = this.getState().nodes[id].url; 382 break;
336 label = itemUrl ? 'menuEdit' : 'menuRename'; 383 case Command.OPEN_INCOGNITO:
337 break; 384 label = multipleNodes ? 'menuOpenAllIncognito' : 'menuOpenIncognito';
338 case Command.COPY: 385 break;
339 label = 'menuCopyURL'; 386 }
340 break; 387
341 case Command.DELETE: 388 return loadTimeData.getString(assert(label));
342 label = 'menuDelete'; 389 },
343 break; 390
344 case Command.OPEN_NEW_TAB: 391 /**
345 label = multipleNodes ? 'menuOpenAllNewTab' : 'menuOpenNewTab'; 392 * @param {Command} command
346 break; 393 * @return {boolean}
347 case Command.OPEN_NEW_WINDOW: 394 * @private
348 label = multipleNodes ? 'menuOpenAllNewWindow' : 'menuOpenNewWindow'; 395 */
349 break; 396 showDividerAfter_: function(command) {
350 case Command.OPEN_INCOGNITO: 397 return command == Command.DELETE;
351 label = multipleNodes ? 'menuOpenAllIncognito' : 'menuOpenIncognito'; 398 },
352 break; 399 });
353 } 400
354 401 /** @private {bookmarks.CommandManager} */
355 return loadTimeData.getString(assert(label)); 402 CommandManager.instance_ = null;
356 }, 403
357 404 /** @return {!bookmarks.CommandManager} */
358 /** 405 CommandManager.getInstance = function() {
359 * @param {Command} command 406 return assert(CommandManager.instance_);
360 * @return {boolean} 407 };
361 * @private 408
362 */ 409 return {
363 showDividerAfter_: function(command) { 410 CommandManager: CommandManager,
364 return command == Command.DELETE; 411 };
365 },
366 }); 412 });
OLDNEW
« no previous file with comments | « no previous file | chrome/browser/resources/md_bookmarks/constants.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698