| OLD | NEW |
| 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 /** | 5 /** |
| 6 * @fileoverview Element which shows context menus and handles keyboard | 6 * @fileoverview Element which shows context menus and handles keyboard |
| 7 * shortcuts. | 7 * shortcuts. |
| 8 */ | 8 */ |
| 9 cr.define('bookmarks', function() { | 9 cr.define('bookmarks', function() { |
| 10 | 10 |
| 11 var CommandManager = Polymer({ | 11 var CommandManager = Polymer({ |
| 12 is: 'bookmarks-command-manager', | 12 is: 'bookmarks-command-manager', |
| 13 | 13 |
| 14 behaviors: [ | 14 behaviors: [ |
| 15 bookmarks.StoreClient, | 15 bookmarks.StoreClient, |
| 16 ], | 16 ], |
| 17 | 17 |
| 18 properties: { | 18 properties: { |
| 19 /** @private {!Array<Command>} */ | 19 /** @private {!Array<Command>} */ |
| 20 menuCommands_: { | 20 menuCommands_: { |
| 21 type: Array, | 21 type: Array, |
| 22 value: function() { | 22 value: function() { |
| 23 return [ | 23 return [ |
| 24 Command.EDIT, | 24 Command.EDIT, |
| 25 Command.COPY_URL, | 25 Command.COPY_URL, |
| 26 Command.SHOW_IN_FOLDER, |
| 26 Command.DELETE, | 27 Command.DELETE, |
| 27 // <hr> | 28 // <hr> |
| 28 Command.OPEN_NEW_TAB, | 29 Command.OPEN_NEW_TAB, |
| 29 Command.OPEN_NEW_WINDOW, | 30 Command.OPEN_NEW_WINDOW, |
| 30 Command.OPEN_INCOGNITO, | 31 Command.OPEN_INCOGNITO, |
| 31 ]; | 32 ]; |
| 32 }, | 33 }, |
| 33 }, | 34 }, |
| 34 | 35 |
| 35 /** @private {Set<string>} */ | 36 /** @private {Set<string>} */ |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 67 /** @private {function()} */ | 68 /** @private {function()} */ |
| 68 this.boundOnCommandUndo_ = function() { | 69 this.boundOnCommandUndo_ = function() { |
| 69 this.handle(Command.UNDO, new Set()); | 70 this.handle(Command.UNDO, new Set()); |
| 70 }.bind(this); | 71 }.bind(this); |
| 71 document.addEventListener('command-undo', this.boundOnCommandUndo_); | 72 document.addEventListener('command-undo', this.boundOnCommandUndo_); |
| 72 | 73 |
| 73 /** @private {function(!Event)} */ | 74 /** @private {function(!Event)} */ |
| 74 this.boundOnKeydown_ = this.onKeydown_.bind(this); | 75 this.boundOnKeydown_ = this.onKeydown_.bind(this); |
| 75 document.addEventListener('keydown', this.boundOnKeydown_); | 76 document.addEventListener('keydown', this.boundOnKeydown_); |
| 76 | 77 |
| 78 /** |
| 79 * Indicates where the context menu was opened from. Will be NONE if |
| 80 * menu is not open, indicating that commands are from keyboard shortcuts |
| 81 * or elsewhere in the UI. |
| 82 * @private {MenuSource} |
| 83 */ |
| 84 this.menuSource_ = MenuSource.NONE; |
| 85 |
| 77 /** @private {Object<Command, cr.ui.KeyboardShortcutList>} */ | 86 /** @private {Object<Command, cr.ui.KeyboardShortcutList>} */ |
| 78 this.shortcuts_ = {}; | 87 this.shortcuts_ = {}; |
| 79 | 88 |
| 80 this.addShortcut_(Command.EDIT, 'F2', 'Enter'); | 89 this.addShortcut_(Command.EDIT, 'F2', 'Enter'); |
| 81 this.addShortcut_(Command.DELETE, 'Delete', 'Delete Backspace'); | 90 this.addShortcut_(Command.DELETE, 'Delete', 'Delete Backspace'); |
| 82 | 91 |
| 83 this.addShortcut_(Command.OPEN, 'Enter', 'Meta|ArrowDown Meta|o'); | 92 this.addShortcut_(Command.OPEN, 'Enter', 'Meta|ArrowDown Meta|o'); |
| 84 this.addShortcut_(Command.OPEN_NEW_TAB, 'Ctrl|Enter', 'Meta|Enter'); | 93 this.addShortcut_(Command.OPEN_NEW_TAB, 'Ctrl|Enter', 'Meta|Enter'); |
| 85 this.addShortcut_(Command.OPEN_NEW_WINDOW, 'Shift|Enter'); | 94 this.addShortcut_(Command.OPEN_NEW_WINDOW, 'Shift|Enter'); |
| 86 | 95 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 101 document.removeEventListener('command-undo', this.boundOnCommandUndo_); | 110 document.removeEventListener('command-undo', this.boundOnCommandUndo_); |
| 102 document.removeEventListener('keydown', this.boundOnKeydown_); | 111 document.removeEventListener('keydown', this.boundOnKeydown_); |
| 103 }, | 112 }, |
| 104 | 113 |
| 105 /** | 114 /** |
| 106 * Display the command context menu at (|x|, |y|) in window co-ordinates. | 115 * Display the command context menu at (|x|, |y|) in window co-ordinates. |
| 107 * Commands will execute on |items| if given, or on the currently selected | 116 * Commands will execute on |items| if given, or on the currently selected |
| 108 * items. | 117 * items. |
| 109 * @param {number} x | 118 * @param {number} x |
| 110 * @param {number} y | 119 * @param {number} y |
| 120 * @param {MenuSource} source |
| 111 * @param {Set<string>=} items | 121 * @param {Set<string>=} items |
| 112 */ | 122 */ |
| 113 openCommandMenuAtPosition: function(x, y, items) { | 123 openCommandMenuAtPosition: function(x, y, source, items) { |
| 124 this.menuSource_ = source; |
| 114 this.menuIds_ = items || this.getState().selection.items; | 125 this.menuIds_ = items || this.getState().selection.items; |
| 115 | 126 |
| 116 var dropdown = | 127 var dropdown = |
| 117 /** @type {!CrActionMenuElement} */ (this.$.dropdown.get()); | 128 /** @type {!CrActionMenuElement} */ (this.$.dropdown.get()); |
| 118 // Ensure that the menu is fully rendered before trying to position it. | 129 // Ensure that the menu is fully rendered before trying to position it. |
| 119 Polymer.dom.flush(); | 130 Polymer.dom.flush(); |
| 120 bookmarks.DialogFocusManager.getInstance().showDialog( | 131 bookmarks.DialogFocusManager.getInstance().showDialog( |
| 121 dropdown, function() { | 132 dropdown, function() { |
| 122 dropdown.showAtPosition({top: y, left: x}); | 133 dropdown.showAtPosition({top: y, left: x}); |
| 123 }); | 134 }); |
| 124 }, | 135 }, |
| 125 | 136 |
| 126 /** | 137 /** |
| 127 * Display the command context menu positioned to cover the |target| | 138 * Display the command context menu positioned to cover the |target| |
| 128 * element. Commands will execute on the currently selected items. | 139 * element. Commands will execute on the currently selected items. |
| 129 * @param {!Element} target | 140 * @param {!Element} target |
| 141 * @param {MenuSource} source |
| 130 */ | 142 */ |
| 131 openCommandMenuAtElement: function(target) { | 143 openCommandMenuAtElement: function(target, source) { |
| 144 this.menuSource_ = source; |
| 132 this.menuIds_ = this.getState().selection.items; | 145 this.menuIds_ = this.getState().selection.items; |
| 133 | 146 |
| 134 var dropdown = | 147 var dropdown = |
| 135 /** @type {!CrActionMenuElement} */ (this.$.dropdown.get()); | 148 /** @type {!CrActionMenuElement} */ (this.$.dropdown.get()); |
| 136 // Ensure that the menu is fully rendered before trying to position it. | 149 // Ensure that the menu is fully rendered before trying to position it. |
| 137 Polymer.dom.flush(); | 150 Polymer.dom.flush(); |
| 138 bookmarks.DialogFocusManager.getInstance().showDialog( | 151 bookmarks.DialogFocusManager.getInstance().showDialog( |
| 139 dropdown, function() { | 152 dropdown, function() { |
| 140 dropdown.showAt(target); | 153 dropdown.showAt(target); |
| 141 }); | 154 }); |
| 142 }, | 155 }, |
| 143 | 156 |
| 144 closeCommandMenu: function() { | 157 closeCommandMenu: function() { |
| 145 this.menuIds_ = new Set(); | 158 this.menuIds_ = new Set(); |
| 159 this.menuSource_ = MenuSource.NONE; |
| 146 /** @type {!CrActionMenuElement} */ (this.$.dropdown.get()).close(); | 160 /** @type {!CrActionMenuElement} */ (this.$.dropdown.get()).close(); |
| 147 }, | 161 }, |
| 148 | 162 |
| 149 //////////////////////////////////////////////////////////////////////////// | 163 //////////////////////////////////////////////////////////////////////////// |
| 150 // Command handlers: | 164 // Command handlers: |
| 151 | 165 |
| 152 /** | 166 /** |
| 153 * Determine if the |command| can be executed with the given |itemIds|. | 167 * Determine if the |command| can be executed with the given |itemIds|. |
| 154 * Commands which appear in the context menu should be implemented | 168 * Commands which appear in the context menu should be implemented |
| 155 * separately using `isCommandVisible_` and `isCommandEnabled_`. | 169 * separately using `isCommandVisible_` and `isCommandEnabled_`. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 * menu. | 205 * menu. |
| 192 */ | 206 */ |
| 193 isCommandVisible_: function(command, itemIds) { | 207 isCommandVisible_: function(command, itemIds) { |
| 194 switch (command) { | 208 switch (command) { |
| 195 case Command.EDIT: | 209 case Command.EDIT: |
| 196 return itemIds.size == 1 && this.globalCanEdit_; | 210 return itemIds.size == 1 && this.globalCanEdit_; |
| 197 case Command.COPY_URL: | 211 case Command.COPY_URL: |
| 198 return this.isSingleBookmark_(itemIds); | 212 return this.isSingleBookmark_(itemIds); |
| 199 case Command.DELETE: | 213 case Command.DELETE: |
| 200 return itemIds.size > 0 && this.globalCanEdit_; | 214 return itemIds.size > 0 && this.globalCanEdit_; |
| 215 case Command.SHOW_IN_FOLDER: |
| 216 return this.menuSource_ == MenuSource.LIST && itemIds.size == 1 && |
| 217 this.getState().search.term != '' && |
| 218 !this.containsMatchingNode_(itemIds, function(node) { |
| 219 return !node.parentId || node.parentId == ROOT_NODE_ID; |
| 220 }); |
| 201 case Command.OPEN_NEW_TAB: | 221 case Command.OPEN_NEW_TAB: |
| 202 case Command.OPEN_NEW_WINDOW: | 222 case Command.OPEN_NEW_WINDOW: |
| 203 case Command.OPEN_INCOGNITO: | 223 case Command.OPEN_INCOGNITO: |
| 204 return itemIds.size > 0; | 224 return itemIds.size > 0; |
| 205 default: | 225 default: |
| 206 return false; | 226 return false; |
| 207 } | 227 } |
| 208 }, | 228 }, |
| 209 | 229 |
| 210 /** | 230 /** |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 255 Promise.resolve(loadTimeData.getString('toastUrlCopied')); | 275 Promise.resolve(loadTimeData.getString('toastUrlCopied')); |
| 256 } else { | 276 } else { |
| 257 labelPromise = cr.sendWithPromise( | 277 labelPromise = cr.sendWithPromise( |
| 258 'getPluralString', 'toastItemsCopied', idList.length); | 278 'getPluralString', 'toastItemsCopied', idList.length); |
| 259 } | 279 } |
| 260 | 280 |
| 261 this.showTitleToast_( | 281 this.showTitleToast_( |
| 262 labelPromise, state.nodes[idList[0]].title, false); | 282 labelPromise, state.nodes[idList[0]].title, false); |
| 263 }.bind(this)); | 283 }.bind(this)); |
| 264 break; | 284 break; |
| 285 case Command.SHOW_IN_FOLDER: |
| 286 var id = Array.from(itemIds)[0]; |
| 287 this.dispatch(bookmarks.actions.selectFolder( |
| 288 assert(state.nodes[id].parentId), state.nodes)); |
| 289 break; |
| 265 case Command.DELETE: | 290 case Command.DELETE: |
| 266 var idList = Array.from(this.minimizeDeletionSet_(itemIds)); | 291 var idList = Array.from(this.minimizeDeletionSet_(itemIds)); |
| 267 var title = state.nodes[idList[0]].title; | 292 var title = state.nodes[idList[0]].title; |
| 268 var labelPromise = cr.sendWithPromise( | 293 var labelPromise = cr.sendWithPromise( |
| 269 'getPluralString', 'toastItemsDeleted', idList.length); | 294 'getPluralString', 'toastItemsDeleted', idList.length); |
| 270 chrome.bookmarkManagerPrivate.removeTrees(idList, function() { | 295 chrome.bookmarkManagerPrivate.removeTrees(idList, function() { |
| 271 this.showTitleToast_(labelPromise, title, true); | 296 this.showTitleToast_(labelPromise, title, true); |
| 272 }.bind(this)); | 297 }.bind(this)); |
| 273 break; | 298 break; |
| 274 case Command.UNDO: | 299 case Command.UNDO: |
| (...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 var id = Array.from(this.menuIds_)[0]; | 520 var id = Array.from(this.menuIds_)[0]; |
| 496 var itemUrl = this.getState().nodes[id].url; | 521 var itemUrl = this.getState().nodes[id].url; |
| 497 label = itemUrl ? 'menuEdit' : 'menuRename'; | 522 label = itemUrl ? 'menuEdit' : 'menuRename'; |
| 498 break; | 523 break; |
| 499 case Command.COPY_URL: | 524 case Command.COPY_URL: |
| 500 label = 'menuCopyURL'; | 525 label = 'menuCopyURL'; |
| 501 break; | 526 break; |
| 502 case Command.DELETE: | 527 case Command.DELETE: |
| 503 label = 'menuDelete'; | 528 label = 'menuDelete'; |
| 504 break; | 529 break; |
| 530 case Command.SHOW_IN_FOLDER: |
| 531 label = 'menuShowInFolder'; |
| 532 break; |
| 505 case Command.OPEN_NEW_TAB: | 533 case Command.OPEN_NEW_TAB: |
| 506 label = multipleNodes ? 'menuOpenAllNewTab' : 'menuOpenNewTab'; | 534 label = multipleNodes ? 'menuOpenAllNewTab' : 'menuOpenNewTab'; |
| 507 break; | 535 break; |
| 508 case Command.OPEN_NEW_WINDOW: | 536 case Command.OPEN_NEW_WINDOW: |
| 509 label = multipleNodes ? 'menuOpenAllNewWindow' : 'menuOpenNewWindow'; | 537 label = multipleNodes ? 'menuOpenAllNewWindow' : 'menuOpenNewWindow'; |
| 510 break; | 538 break; |
| 511 case Command.OPEN_INCOGNITO: | 539 case Command.OPEN_INCOGNITO: |
| 512 label = multipleNodes ? 'menuOpenAllIncognito' : 'menuOpenIncognito'; | 540 label = multipleNodes ? 'menuOpenAllIncognito' : 'menuOpenIncognito'; |
| 513 break; | 541 break; |
| 514 } | 542 } |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 580 | 608 |
| 581 //////////////////////////////////////////////////////////////////////////// | 609 //////////////////////////////////////////////////////////////////////////// |
| 582 // Event handlers: | 610 // Event handlers: |
| 583 | 611 |
| 584 /** | 612 /** |
| 585 * @param {Event} e | 613 * @param {Event} e |
| 586 * @private | 614 * @private |
| 587 */ | 615 */ |
| 588 onOpenItemMenu_: function(e) { | 616 onOpenItemMenu_: function(e) { |
| 589 if (e.detail.targetElement) { | 617 if (e.detail.targetElement) { |
| 590 this.openCommandMenuAtElement(e.detail.targetElement); | 618 this.openCommandMenuAtElement(e.detail.targetElement, e.detail.source); |
| 591 } else { | 619 } else { |
| 592 this.openCommandMenuAtPosition(e.detail.x, e.detail.y); | 620 this.openCommandMenuAtPosition(e.detail.x, e.detail.y, e.detail.source); |
| 593 } | 621 } |
| 594 }, | 622 }, |
| 595 | 623 |
| 596 /** | 624 /** |
| 597 * @param {Event} e | 625 * @param {Event} e |
| 598 * @private | 626 * @private |
| 599 */ | 627 */ |
| 600 onCommandClick_: function(e) { | 628 onCommandClick_: function(e) { |
| 601 this.handle( | 629 this.handle( |
| 602 e.currentTarget.getAttribute('command'), assert(this.menuIds_)); | 630 e.currentTarget.getAttribute('command'), assert(this.menuIds_)); |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 644 | 672 |
| 645 /** @return {!bookmarks.CommandManager} */ | 673 /** @return {!bookmarks.CommandManager} */ |
| 646 CommandManager.getInstance = function() { | 674 CommandManager.getInstance = function() { |
| 647 return assert(CommandManager.instance_); | 675 return assert(CommandManager.instance_); |
| 648 }; | 676 }; |
| 649 | 677 |
| 650 return { | 678 return { |
| 651 CommandManager: CommandManager, | 679 CommandManager: CommandManager, |
| 652 }; | 680 }; |
| 653 }); | 681 }); |
| OLD | NEW |