Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 (function() { | 5 (function() { |
| 6 /** @const */ var BookmarkList = bmm.BookmarkList; | 6 /** @const */ var BookmarkList = bmm.BookmarkList; |
| 7 /** @const */ var BookmarkTree = bmm.BookmarkTree; | 7 /** @const */ var BookmarkTree = bmm.BookmarkTree; |
| 8 /** @const */ var Command = cr.ui.Command; | 8 /** @const */ var Command = cr.ui.Command; |
| 9 /** @const */ var CommandBinding = cr.ui.CommandBinding; | |
| 10 /** @const */ var LinkKind = cr.LinkKind; | 9 /** @const */ var LinkKind = cr.LinkKind; |
| 11 /** @const */ var ListItem = cr.ui.ListItem; | 10 /** @const */ var ListItem = cr.ui.ListItem; |
| 12 /** @const */ var Menu = cr.ui.Menu; | 11 /** @const */ var Menu = cr.ui.Menu; |
| 13 /** @const */ var MenuButton = cr.ui.MenuButton; | 12 /** @const */ var MenuButton = cr.ui.MenuButton; |
| 14 /** @const */ var Splitter = cr.ui.Splitter; | 13 /** @const */ var Splitter = cr.ui.Splitter; |
| 15 /** @const */ var TreeItem = cr.ui.TreeItem; | 14 /** @const */ var TreeItem = cr.ui.TreeItem; |
| 16 | 15 |
| 17 /** | 16 /** |
| 18 * An array containing the BookmarkTreeNodes that were deleted in the last | 17 * An array containing the BookmarkTreeNodes that were deleted in the last |
| 19 * deletion action. This is used for implementing undo. | 18 * deletion action. This is used for implementing undo. |
| 20 * @type {Array.<BookmarkTreeNode>} | 19 * @type {Array.<Array.<BookmarkTreeNode>>} |
| 21 */ | 20 */ |
| 22 var lastDeletedNodes; | 21 var lastDeletedNodes; |
| 23 | 22 |
| 24 /** | 23 /** |
| 25 * | 24 * |
| 26 * Holds the last DOMTimeStamp when mouse pointer hovers on folder in tree | 25 * Holds the last DOMTimeStamp when mouse pointer hovers on folder in tree |
| 27 * view. Zero means pointer doesn't hover on folder. | 26 * view. Zero means pointer doesn't hover on folder. |
| 28 * @type {number} | 27 * @type {number} |
| 29 */ | 28 */ |
| 30 var lastHoverOnFolderTimeStamp = 0; | 29 var lastHoverOnFolderTimeStamp = 0; |
| 31 | 30 |
| 32 /** | 31 /** |
| 33 * Holds a function that will undo that last action, if global undo is enabled. | 32 * Holds a function that will undo that last action, if global undo is enabled. |
| 34 * @type {Function} | 33 * @type {Function} |
| 35 */ | 34 */ |
| 36 var performGlobalUndo; | 35 var performGlobalUndo; |
| 37 | 36 |
| 38 /** | 37 /** |
| 39 * Holds a link controller singleton. Use getLinkController() rarther than | 38 * Holds a link controller singleton. Use getLinkController() rarther than |
| 40 * accessing this variabie. | 39 * accessing this variabie. |
| 41 * @type {LinkController} | 40 * @type {cr.LinkController} |
| 42 */ | 41 */ |
| 43 var linkController; | 42 var linkController; |
| 44 | 43 |
| 45 /** | 44 /** |
| 46 * New Windows are not allowed in Windows 8 metro mode. | 45 * New Windows are not allowed in Windows 8 metro mode. |
| 47 */ | 46 */ |
| 48 var canOpenNewWindows = true; | 47 var canOpenNewWindows = true; |
| 49 | 48 |
| 50 /** | 49 /** |
| 51 * Incognito mode availability can take the following values: , | 50 * Incognito mode availability can take the following values: , |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 135 | 134 |
| 136 searchTreeItem.label = loadTimeData.getString('search'); | 135 searchTreeItem.label = loadTimeData.getString('search'); |
| 137 searchTreeItem.icon = isRTL() ? 'images/bookmark_manager_search_rtl.png' : | 136 searchTreeItem.icon = isRTL() ? 'images/bookmark_manager_search_rtl.png' : |
| 138 'images/bookmark_manager_search.png'; | 137 'images/bookmark_manager_search.png'; |
| 139 } | 138 } |
| 140 | 139 |
| 141 /** | 140 /** |
| 142 * Updates the location hash to reflect the current state of the application. | 141 * Updates the location hash to reflect the current state of the application. |
| 143 */ | 142 */ |
| 144 function updateHash() { | 143 function updateHash() { |
| 145 window.location.hash = tree.selectedItem.bookmarkId; | 144 window.location.hash = $('tree').selectedItem.bookmarkId; |
| 146 updateAllCommands(); | 145 updateAllCommands(); |
| 147 } | 146 } |
| 148 | 147 |
| 149 /** | 148 /** |
| 150 * Navigates to a bookmark ID. | 149 * Navigates to a bookmark ID. |
| 151 * @param {string} id The ID to navigate to. | 150 * @param {string} id The ID to navigate to. |
| 152 * @param {function()=} opt_callback Function called when list view loaded or | 151 * @param {function()=} opt_callback Function called when list view loaded or |
| 153 * displayed specified folder. | 152 * displayed specified folder. |
| 154 */ | 153 */ |
| 155 function navigateTo(id, opt_callback) { | 154 function navigateTo(id, opt_callback) { |
| 156 window.location.hash = id; | 155 window.location.hash = id; |
| 157 updateAllCommands(); | 156 updateAllCommands(); |
| 158 | 157 |
| 159 var metricsId = folderMetricsNameMap[id.replace(/^q=.*/, 'q=')] || | 158 var metricsId = folderMetricsNameMap[id.replace(/^q=.*/, 'q=')] || |
| 160 folderMetricsNameMap['subfolder']; | 159 folderMetricsNameMap['subfolder']; |
| 161 chrome.metricsPrivate.recordUserAction( | 160 chrome.metricsPrivate.recordUserAction( |
| 162 'BookmarkManager_NavigateTo_' + metricsId); | 161 'BookmarkManager_NavigateTo_' + metricsId); |
| 163 | 162 |
| 164 if (opt_callback) { | 163 if (opt_callback) { |
| 165 if (list.parentId == id) | 164 if ($('list').parentId == id) |
|
Dan Beam
2014/09/23 02:46:56
cast to !Element here as you're already doing mayb
Vitaly Pavlenko
2014/09/23 22:20:55
Done.
| |
| 166 opt_callback(); | 165 opt_callback(); |
| 167 else | 166 else |
| 168 addOneShotEventListener(list, 'load', opt_callback); | 167 addOneShotEventListener(/** @type {!Element} */($('list')), 'load', |
| 168 opt_callback); | |
|
Dan Beam
2014/09/23 02:46:56
if () needs curlies
Vitaly Pavlenko
2014/09/23 22:20:55
Done.
| |
| 169 } | 169 } |
| 170 } | 170 } |
| 171 | 171 |
| 172 /** | 172 /** |
| 173 * Updates the parent ID of the bookmark list and selects the correct tree item. | 173 * Updates the parent ID of the bookmark list and selects the correct tree item. |
| 174 * @param {string} id The id. | 174 * @param {string} id The id. |
| 175 */ | 175 */ |
| 176 function updateParentId(id) { | 176 function updateParentId(id) { |
| 177 // Setting list.parentId fires 'load' event. | 177 // Setting list.parentId fires 'load' event. |
| 178 list.parentId = id; | 178 $('list').parentId = id; |
| 179 | 179 |
| 180 // When tree.selectedItem changed, tree view calls navigatTo() then it | 180 // When tree.selectedItem changed, tree view calls navigatTo() then it |
| 181 // calls updateHash() when list view displayed specified folder. | 181 // calls updateHash() when list view displayed specified folder. |
| 182 tree.selectedItem = bmm.treeLookup[id] || tree.selectedItem; | 182 $('tree').selectedItem = bmm.treeLookup[id] || $('tree').selectedItem; |
| 183 } | 183 } |
| 184 | 184 |
| 185 // Process the location hash. This is called by onhashchange and when the page | 185 // Process the location hash. This is called by onhashchange and when the page |
| 186 // is first loaded. | 186 // is first loaded. |
| 187 function processHash() { | 187 function processHash() { |
| 188 var id = window.location.hash.slice(1); | 188 var id = window.location.hash.slice(1); |
| 189 if (!id) { | 189 if (!id) { |
| 190 // If we do not have a hash, select first item in the tree. | 190 // If we do not have a hash, select first item in the tree. |
| 191 id = tree.items[0].bookmarkId; | 191 id = $('tree').items[0].bookmarkId; |
| 192 } | 192 } |
| 193 | 193 |
| 194 var valid = false; | 194 var valid = false; |
| 195 if (/^e=/.test(id)) { | 195 if (/^e=/.test(id)) { |
| 196 id = id.slice(2); | 196 id = id.slice(2); |
| 197 | 197 |
| 198 // If hash contains e=, edit the item specified. | 198 // If hash contains e=, edit the item specified. |
| 199 chrome.bookmarks.get(id, function(bookmarkNodes) { | 199 chrome.bookmarks.get(id, function(bookmarkNodes) { |
| 200 // Verify the node to edit is a valid node. | 200 // Verify the node to edit is a valid node. |
| 201 if (!bookmarkNodes || bookmarkNodes.length != 1) | 201 if (!bookmarkNodes || bookmarkNodes.length != 1) |
| 202 return; | 202 return; |
| 203 var bookmarkNode = bookmarkNodes[0]; | 203 var bookmarkNode = bookmarkNodes[0]; |
| 204 | 204 |
| 205 // After the list reloads, edit the desired bookmark. | 205 // After the list reloads, edit the desired bookmark. |
| 206 var editBookmark = function(e) { | 206 var editBookmark = function() { |
| 207 var index = list.dataModel.findIndexById(bookmarkNode.id); | 207 var index = $('list').dataModel.findIndexById(bookmarkNode.id); |
| 208 if (index != -1) { | 208 if (index != -1) { |
| 209 var sm = list.selectionModel; | 209 var sm = $('list').selectionModel; |
| 210 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; | 210 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; |
| 211 scrollIntoViewAndMakeEditable(index); | 211 scrollIntoViewAndMakeEditable(index); |
| 212 } | 212 } |
| 213 }; | 213 }; |
| 214 | 214 |
| 215 navigateTo(bookmarkNode.parentId, editBookmark); | 215 navigateTo(bookmarkNode.parentId, editBookmark); |
| 216 }); | 216 }); |
| 217 | 217 |
| 218 // We handle the two cases of navigating to the bookmark to be edited | 218 // We handle the two cases of navigating to the bookmark to be edited |
| 219 // above. Don't run the standard navigation code below. | 219 // above. Don't run the standard navigation code below. |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 266 var id = searchTreeItem.bookmarkId = 'q=' + searchText; | 266 var id = searchTreeItem.bookmarkId = 'q=' + searchText; |
| 267 bmm.treeLookup[searchTreeItem.bookmarkId] = searchTreeItem; | 267 bmm.treeLookup[searchTreeItem.bookmarkId] = searchTreeItem; |
| 268 } | 268 } |
| 269 | 269 |
| 270 var input = $('term'); | 270 var input = $('term'); |
| 271 // Do not update the input if the user is actively using the text input. | 271 // Do not update the input if the user is actively using the text input. |
| 272 if (document.activeElement != input) | 272 if (document.activeElement != input) |
| 273 input.value = searchText; | 273 input.value = searchText; |
| 274 | 274 |
| 275 if (searchText) { | 275 if (searchText) { |
| 276 tree.add(searchTreeItem); | 276 $('tree').add(searchTreeItem); |
| 277 tree.selectedItem = searchTreeItem; | 277 $('tree').selectedItem = searchTreeItem; |
| 278 } else { | 278 } else { |
| 279 // Go "home". | 279 // Go "home". |
| 280 tree.selectedItem = tree.items[0]; | 280 $('tree').selectedItem = $('tree').items[0]; |
| 281 id = tree.selectedItem.bookmarkId; | 281 id = $('tree').selectedItem.bookmarkId; |
| 282 } | 282 } |
| 283 | 283 |
| 284 navigateTo(id); | 284 navigateTo(id); |
| 285 } | 285 } |
| 286 | 286 |
| 287 /** | 287 /** |
| 288 * This returns the user visible path to the folder where the bookmark is | 288 * This returns the user visible path to the folder where the bookmark is |
| 289 * located. | 289 * located. |
| 290 * @param {number} parentId The ID of the parent folder. | 290 * @param {number} parentId The ID of the parent folder. |
| 291 * @return {string} The path to the the bookmark, | 291 * @return {string} The path to the the bookmark, |
| 292 */ | 292 */ |
| 293 function getFolder(parentId) { | 293 function getFolder(parentId) { |
| 294 var parentNode = tree.getBookmarkNodeById(parentId); | 294 var parentNode = $('tree').getBookmarkNodeById(parentId); |
| 295 if (parentNode) { | 295 if (parentNode) { |
| 296 var s = parentNode.title; | 296 var s = parentNode.title; |
| 297 if (parentNode.parentId != bmm.ROOT_ID) { | 297 if (parentNode.parentId != bmm.ROOT_ID) { |
| 298 return getFolder(parentNode.parentId) + '/' + s; | 298 return getFolder(parentNode.parentId) + '/' + s; |
| 299 } | 299 } |
| 300 return s; | 300 return s; |
| 301 } | 301 } |
| 302 } | 302 } |
| 303 | 303 |
| 304 function handleLoadForTree(e) { | 304 function handleLoadForTree(e) { |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 324 if (!bmm.isFolder(child)) | 324 if (!bmm.isFolder(child)) |
| 325 urls.push(child.url); | 325 urls.push(child.url); |
| 326 }); | 326 }); |
| 327 } else { | 327 } else { |
| 328 urls.push(node.url); | 328 urls.push(node.url); |
| 329 } | 329 } |
| 330 } | 330 } |
| 331 | 331 |
| 332 // Get a future promise for the nodes. | 332 // Get a future promise for the nodes. |
| 333 var promises = nodes.map(function(node) { | 333 var promises = nodes.map(function(node) { |
| 334 if (bmm.isFolder(node)) | 334 if (bmm.isFolder(assert(node))) |
| 335 return bmm.loadSubtree(node.id); | 335 return bmm.loadSubtree(node.id); |
| 336 // Not a folder so we already have all the data we need. | 336 // Not a folder so we already have all the data we need. |
| 337 return Promise.resolve(node); | 337 return Promise.resolve(node); |
| 338 }); | 338 }); |
| 339 | 339 |
| 340 return Promise.all(promises).then(function(nodes) { | 340 return Promise.all(promises).then(function(nodes) { |
| 341 nodes.forEach(addNodes); | 341 nodes.forEach(addNodes); |
| 342 return urls; | 342 return urls; |
| 343 }); | 343 }); |
| 344 } | 344 } |
| 345 | 345 |
| 346 /** | 346 /** |
| 347 * Returns the nodes (non recursive) to use for the open commands. | 347 * Returns the nodes (non recursive) to use for the open commands. |
| 348 * @param {HTMLElement} target . | 348 * @param {HTMLElement} target |
| 349 * @return {Array.<BookmarkTreeNode>} . | 349 * @return {!Array.<BookmarkTreeNode>} |
| 350 */ | 350 */ |
| 351 function getNodesForOpen(target) { | 351 function getNodesForOpen(target) { |
| 352 if (target == tree) { | 352 if (target == $('tree')) { |
| 353 if (tree.selectedItem != searchTreeItem) | 353 if ($('tree').selectedItem != searchTreeItem) |
| 354 return tree.selectedFolders; | 354 return $('tree').selectedFolders; |
| 355 // Fall through to use all nodes in the list. | 355 // Fall through to use all nodes in the list. |
| 356 } else { | 356 } else { |
| 357 var items = list.selectedItems; | 357 var items = $('list').selectedItems; |
| 358 if (items.length) | 358 if (items.length) |
| 359 return items; | 359 return items; |
| 360 } | 360 } |
| 361 | 361 |
| 362 // The list starts off with a null dataModel. We can get here during startup. | 362 // The list starts off with a null dataModel. We can get here during startup. |
| 363 if (!list.dataModel) | 363 if (!$('list').dataModel) |
| 364 return []; | 364 return []; |
| 365 | 365 |
| 366 // Return an array based on the dataModel. | 366 // Return an array based on the dataModel. |
| 367 return list.dataModel.slice(); | 367 return $('list').dataModel.slice(); |
| 368 } | 368 } |
| 369 | 369 |
| 370 /** | 370 /** |
| 371 * Returns a promise that will contain all URLs of all the selected bookmarks | 371 * Returns a promise that will contain all URLs of all the selected bookmarks |
| 372 * and the nested bookmarks for use with the open commands. | 372 * and the nested bookmarks for use with the open commands. |
| 373 * @param {HTMLElement} target The target list or tree. | 373 * @param {HTMLElement} target The target list or tree. |
| 374 * @return {Promise.<Array.<string>>} . | 374 * @return {Promise.<Array.<string>>} . |
| 375 */ | 375 */ |
| 376 function getUrlsForOpenCommands(target) { | 376 function getUrlsForOpenCommands(target) { |
| 377 return getAllUrls(getNodesForOpen(target)); | 377 return getAllUrls(getNodesForOpen(target)); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 390 * @param {string} pluralId The string id of menu label if the singular form is | 390 * @param {string} pluralId The string id of menu label if the singular form is |
| 391 not used. | 391 not used. |
| 392 * @param {boolean} commandDisabled Whether the menu item should be disabled | 392 * @param {boolean} commandDisabled Whether the menu item should be disabled |
| 393 no matter what bookmarks are selected. | 393 no matter what bookmarks are selected. |
| 394 */ | 394 */ |
| 395 function updateOpenCommand(e, command, singularId, pluralId, commandDisabled) { | 395 function updateOpenCommand(e, command, singularId, pluralId, commandDisabled) { |
| 396 if (singularId) { | 396 if (singularId) { |
| 397 // The command label reflects the selection which might not reflect | 397 // The command label reflects the selection which might not reflect |
| 398 // how many bookmarks will be opened. For example if you right click an | 398 // how many bookmarks will be opened. For example if you right click an |
| 399 // empty area in a folder with 1 bookmark the text should still say "all". | 399 // empty area in a folder with 1 bookmark the text should still say "all". |
| 400 assert(!e.target || e.target instanceof BookmarkList || | |
| 401 e.target instanceof BookmarkTree); | |
| 400 var selectedNodes = getSelectedBookmarkNodes(e.target).filter(notNewNode); | 402 var selectedNodes = getSelectedBookmarkNodes(e.target).filter(notNewNode); |
| 401 var singular = selectedNodes.length == 1 && !bmm.isFolder(selectedNodes[0]); | 403 var singular = selectedNodes.length == 1 && !bmm.isFolder(selectedNodes[0]); |
| 402 command.label = loadTimeData.getString(singular ? singularId : pluralId); | 404 command.label = loadTimeData.getString(singular ? singularId : pluralId); |
| 403 } | 405 } |
| 404 | 406 |
| 405 if (commandDisabled) { | 407 if (commandDisabled) { |
| 406 command.disabled = true; | 408 command.disabled = true; |
| 407 e.canExecute = false; | 409 e.canExecute = false; |
| 408 return; | 410 return; |
| 409 } | 411 } |
| 410 | 412 |
| 411 getUrlsForOpenCommands(e.target).then(function(urls) { | 413 getUrlsForOpenCommands(assertInstanceof(e.target, HTMLElement)).then( |
| 414 function(urls) { | |
| 412 var disabled = !urls.length; | 415 var disabled = !urls.length; |
| 413 command.disabled = disabled; | 416 command.disabled = disabled; |
| 414 e.canExecute = !disabled; | 417 e.canExecute = !disabled; |
| 415 }); | 418 }); |
| 416 } | 419 } |
| 417 | 420 |
| 418 /** | 421 /** |
| 419 * Calls the backend to figure out if we can paste the clipboard into the active | 422 * Calls the backend to figure out if we can paste the clipboard into the active |
| 420 * folder. | 423 * folder. |
| 421 * @param {Function=} opt_f Function to call after the state has been updated. | 424 * @param {Function=} opt_f Function to call after the state has been updated. |
| 422 */ | 425 */ |
| 423 function updatePasteCommand(opt_f) { | 426 function updatePasteCommand(opt_f) { |
| 424 function update(canPaste) { | 427 function update(canPaste) { |
| 425 var organizeMenuCommand = $('paste-from-organize-menu-command'); | 428 var organizeMenuCommand = $('paste-from-organize-menu-command'); |
| 426 var contextMenuCommand = $('paste-from-context-menu-command'); | 429 var contextMenuCommand = $('paste-from-context-menu-command'); |
| 427 organizeMenuCommand.disabled = !canPaste; | 430 organizeMenuCommand.disabled = !canPaste; |
| 428 contextMenuCommand.disabled = !canPaste; | 431 contextMenuCommand.disabled = !canPaste; |
| 429 if (opt_f) | 432 if (opt_f) |
| 430 opt_f(); | 433 opt_f(); |
| 431 } | 434 } |
| 432 // We cannot paste into search view. | 435 // We cannot paste into search view. |
| 433 if (list.isSearch()) | 436 if ($('list').isSearch()) |
| 434 update(false); | 437 update(false); |
| 435 else | 438 else |
| 436 chrome.bookmarkManagerPrivate.canPaste(list.parentId, update); | 439 chrome.bookmarkManagerPrivate.canPaste($('list').parentId, update); |
| 437 } | 440 } |
| 438 | 441 |
| 439 function handleCanExecuteForDocument(e) { | 442 function handleCanExecuteForDocument(e) { |
| 440 var command = e.command; | 443 var command = e.command; |
| 441 switch (command.id) { | 444 switch (command.id) { |
| 442 case 'import-menu-command': | 445 case 'import-menu-command': |
| 443 e.canExecute = canEdit; | 446 e.canExecute = canEdit; |
| 444 break; | 447 break; |
| 445 case 'export-menu-command': | 448 case 'export-menu-command': |
| 446 // We can always execute the export-menu command. | 449 // We can always execute the export-menu command. |
| 447 e.canExecute = true; | 450 e.canExecute = true; |
| 448 break; | 451 break; |
| 449 case 'sort-command': | 452 case 'sort-command': |
| 450 e.canExecute = !list.isSearch() && | 453 e.canExecute = !$('list').isSearch() && |
| 451 list.dataModel && list.dataModel.length > 1 && | 454 $('list').dataModel && $('list').dataModel.length > 1 && |
| 452 !isUnmodifiable(tree.getBookmarkNodeById(list.parentId)); | 455 !isUnmodifiable($('tree').getBookmarkNodeById($('list').parentId)); |
| 453 break; | 456 break; |
| 454 case 'undo-command': | 457 case 'undo-command': |
| 455 // If the search box is active, pass the undo command through | 458 // If the search box is active, pass the undo command through |
| 456 // (fixes http://crbug.com/278112). Otherwise, because | 459 // (fixes http://crbug.com/278112). Otherwise, because |
| 457 // the global undo command has no visible UI, always enable it, and | 460 // the global undo command has no visible UI, always enable it, and |
| 458 // just make it a no-op if undo is not possible. | 461 // just make it a no-op if undo is not possible. |
| 459 e.canExecute = e.currentTarget.activeElement !== $('term'); | 462 e.canExecute = e.currentTarget.activeElement !== $('term'); |
| 460 break; | 463 break; |
| 461 default: | 464 default: |
| 462 canExecuteForList(e); | 465 canExecuteForList(e); |
| 463 break; | 466 break; |
| 464 } | 467 } |
| 465 } | 468 } |
| 466 | 469 |
| 467 /** | 470 /** |
| 468 * Helper function for handling canExecute for the list and the tree. | 471 * Helper function for handling canExecute for the list and the tree. |
| 469 * @param {!Event} e Can execute event object. | 472 * @param {!cr.ui.CanExecuteEvent} e Can execute event object. |
| 470 * @param {boolean} isSearch Whether the user is trying to do a command on | 473 * @param {boolean} isSearch Whether the user is trying to do a command on |
| 471 * search. | 474 * search. |
| 472 */ | 475 */ |
| 473 function canExecuteShared(e, isSearch) { | 476 function canExecuteShared(e, isSearch) { |
| 474 var command = e.command; | 477 var command = e.command; |
| 475 var commandId = command.id; | 478 var commandId = command.id; |
| 476 switch (commandId) { | 479 switch (commandId) { |
| 477 case 'paste-from-organize-menu-command': | 480 case 'paste-from-organize-menu-command': |
| 478 case 'paste-from-context-menu-command': | 481 case 'paste-from-context-menu-command': |
| 479 updatePasteCommand(); | 482 updatePasteCommand(); |
| 480 break; | 483 break; |
| 481 | 484 |
| 482 case 'add-new-bookmark-command': | 485 case 'add-new-bookmark-command': |
| 483 case 'new-folder-command': | 486 case 'new-folder-command': |
| 484 var parentId = computeParentFolderForNewItem(); | 487 var parentId = computeParentFolderForNewItem(); |
| 485 var unmodifiable = isUnmodifiable(tree.getBookmarkNodeById(parentId)); | 488 var unmodifiable = isUnmodifiable( |
| 489 $('tree').getBookmarkNodeById(parentId)); | |
| 486 e.canExecute = !isSearch && canEdit && !unmodifiable; | 490 e.canExecute = !isSearch && canEdit && !unmodifiable; |
| 487 break; | 491 break; |
| 488 | 492 |
| 489 case 'open-in-new-tab-command': | 493 case 'open-in-new-tab-command': |
| 490 updateOpenCommand(e, command, 'open_in_new_tab', 'open_all', false); | 494 updateOpenCommand(e, command, 'open_in_new_tab', 'open_all', false); |
| 491 break; | 495 break; |
| 492 case 'open-in-background-tab-command': | 496 case 'open-in-background-tab-command': |
| 493 updateOpenCommand(e, command, '', '', false); | 497 updateOpenCommand(e, command, '', '', false); |
| 494 break; | 498 break; |
| 495 case 'open-in-new-window-command': | 499 case 'open-in-new-window-command': |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 506 break; | 510 break; |
| 507 | 511 |
| 508 case 'undo-delete-command': | 512 case 'undo-delete-command': |
| 509 e.canExecute = !!lastDeletedNodes; | 513 e.canExecute = !!lastDeletedNodes; |
| 510 break; | 514 break; |
| 511 } | 515 } |
| 512 } | 516 } |
| 513 | 517 |
| 514 /** | 518 /** |
| 515 * Helper function for handling canExecute for the list and document. | 519 * Helper function for handling canExecute for the list and document. |
| 516 * @param {!Event} e Can execute event object. | 520 * @param {!cr.ui.CanExecuteEvent} e Can execute event object. |
| 517 */ | 521 */ |
| 518 function canExecuteForList(e) { | 522 function canExecuteForList(e) { |
| 519 var command = e.command; | 523 var command = e.command; |
| 520 var commandId = command.id; | 524 var commandId = command.id; |
| 521 | 525 |
| 522 function hasSelected() { | 526 function hasSelected() { |
| 523 return !!list.selectedItem; | 527 return !!$('list').selectedItem; |
| 524 } | 528 } |
| 525 | 529 |
| 526 function hasSingleSelected() { | 530 function hasSingleSelected() { |
| 527 return list.selectedItems.length == 1; | 531 return $('list').selectedItems.length == 1; |
| 528 } | 532 } |
| 529 | 533 |
| 530 function canCopyItem(item) { | 534 function canCopyItem(item) { |
| 531 return item.id != 'new'; | 535 return item.id != 'new'; |
| 532 } | 536 } |
| 533 | 537 |
| 534 function canCopyItems() { | 538 function canCopyItems() { |
| 535 var selectedItems = list.selectedItems; | 539 var selectedItems = $('list').selectedItems; |
| 536 return selectedItems && selectedItems.some(canCopyItem); | 540 return selectedItems && selectedItems.some(canCopyItem); |
| 537 } | 541 } |
| 538 | 542 |
| 539 function isSearch() { | 543 function isSearch() { |
| 540 return list.isSearch(); | 544 return $('list').isSearch(); |
| 541 } | 545 } |
| 542 | 546 |
| 543 switch (commandId) { | 547 switch (commandId) { |
| 544 case 'rename-folder-command': | 548 case 'rename-folder-command': |
| 545 // Show rename if a single folder is selected. | 549 // Show rename if a single folder is selected. |
| 546 var items = list.selectedItems; | 550 var items = $('list').selectedItems; |
| 547 if (items.length != 1) { | 551 if (items.length != 1) { |
| 548 e.canExecute = false; | 552 e.canExecute = false; |
| 549 command.hidden = true; | 553 command.hidden = true; |
| 550 } else { | 554 } else { |
| 551 var isFolder = bmm.isFolder(items[0]); | 555 var isFolder = bmm.isFolder(items[0]); |
| 552 e.canExecute = isFolder && canEdit && !hasUnmodifiable(items); | 556 e.canExecute = isFolder && canEdit && !hasUnmodifiable(items); |
| 553 command.hidden = !isFolder; | 557 command.hidden = !isFolder; |
| 554 } | 558 } |
| 555 break; | 559 break; |
| 556 | 560 |
| 557 case 'edit-command': | 561 case 'edit-command': |
| 558 // Show the edit command if not a folder. | 562 // Show the edit command if not a folder. |
| 559 var items = list.selectedItems; | 563 var items = $('list').selectedItems; |
| 560 if (items.length != 1) { | 564 if (items.length != 1) { |
| 561 e.canExecute = false; | 565 e.canExecute = false; |
| 562 command.hidden = false; | 566 command.hidden = false; |
| 563 } else { | 567 } else { |
| 564 var isFolder = bmm.isFolder(items[0]); | 568 var isFolder = bmm.isFolder(items[0]); |
| 565 e.canExecute = !isFolder && canEdit && !hasUnmodifiable(items); | 569 e.canExecute = !isFolder && canEdit && !hasUnmodifiable(items); |
| 566 command.hidden = isFolder; | 570 command.hidden = isFolder; |
| 567 } | 571 } |
| 568 break; | 572 break; |
| 569 | 573 |
| 570 case 'show-in-folder-command': | 574 case 'show-in-folder-command': |
| 571 e.canExecute = isSearch() && hasSingleSelected(); | 575 e.canExecute = isSearch() && hasSingleSelected(); |
| 572 break; | 576 break; |
| 573 | 577 |
| 574 case 'delete-command': | 578 case 'delete-command': |
| 575 case 'cut-command': | 579 case 'cut-command': |
| 576 e.canExecute = canCopyItems() && canEdit && | 580 e.canExecute = canCopyItems() && canEdit && |
| 577 !hasUnmodifiable(list.selectedItems); | 581 !hasUnmodifiable($('list').selectedItems); |
| 578 break; | 582 break; |
| 579 | 583 |
| 580 case 'copy-command': | 584 case 'copy-command': |
| 581 e.canExecute = canCopyItems(); | 585 e.canExecute = canCopyItems(); |
| 582 break; | 586 break; |
| 583 | 587 |
| 584 case 'open-in-same-window-command': | 588 case 'open-in-same-window-command': |
| 585 e.canExecute = hasSelected(); | 589 e.canExecute = hasSelected(); |
| 586 break; | 590 break; |
| 587 | 591 |
| 588 default: | 592 default: |
| 589 canExecuteShared(e, isSearch()); | 593 canExecuteShared(e, isSearch()); |
| 590 } | 594 } |
| 591 } | 595 } |
| 592 | 596 |
| 593 // Update canExecute for the commands when the list is the active element. | 597 // Update canExecute for the commands when the list is the active element. |
| 594 function handleCanExecuteForList(e) { | 598 function handleCanExecuteForList(e) { |
| 595 if (e.target != list) return; | 599 if (e.target != $('list')) return; |
| 596 canExecuteForList(e); | 600 canExecuteForList(e); |
| 597 } | 601 } |
| 598 | 602 |
| 599 // Update canExecute for the commands when the tree is the active element. | 603 // Update canExecute for the commands when the tree is the active element. |
| 600 function handleCanExecuteForTree(e) { | 604 function handleCanExecuteForTree(e) { |
| 601 if (e.target != tree) return; | 605 if (e.target != $('tree')) return; |
| 602 | 606 |
| 603 var command = e.command; | 607 var command = e.command; |
| 604 var commandId = command.id; | 608 var commandId = command.id; |
| 605 | 609 |
| 606 function hasSelected() { | 610 function hasSelected() { |
| 607 return !!e.target.selectedItem; | 611 return !!e.target.selectedItem; |
| 608 } | 612 } |
| 609 | 613 |
| 610 function isSearch() { | 614 function isSearch() { |
| 611 var item = e.target.selectedItem; | 615 var item = e.target.selectedItem; |
| 612 return item == searchTreeItem; | 616 return item == searchTreeItem; |
| 613 } | 617 } |
| 614 | 618 |
| 615 function isTopLevelItem() { | 619 function isTopLevelItem() { |
| 616 return e.target.selectedItem.parentNode == tree; | 620 return e.target.selectedItem.parentNode == $('tree'); |
| 617 } | 621 } |
| 618 | 622 |
| 619 switch (commandId) { | 623 switch (commandId) { |
| 620 case 'rename-folder-command': | 624 case 'rename-folder-command': |
| 621 command.hidden = false; | 625 command.hidden = false; |
| 622 e.canExecute = hasSelected() && !isTopLevelItem() && canEdit && | 626 e.canExecute = hasSelected() && !isTopLevelItem() && canEdit && |
| 623 !hasUnmodifiable(tree.selectedFolders); | 627 !hasUnmodifiable($('tree').selectedFolders); |
| 624 break; | 628 break; |
| 625 | 629 |
| 626 case 'edit-command': | 630 case 'edit-command': |
| 627 command.hidden = true; | 631 command.hidden = true; |
| 628 e.canExecute = false; | 632 e.canExecute = false; |
| 629 break; | 633 break; |
| 630 | 634 |
| 631 case 'delete-command': | 635 case 'delete-command': |
| 632 case 'cut-command': | 636 case 'cut-command': |
| 633 e.canExecute = hasSelected() && !isTopLevelItem() && canEdit && | 637 e.canExecute = hasSelected() && !isTopLevelItem() && canEdit && |
| 634 !hasUnmodifiable(tree.selectedFolders); | 638 !hasUnmodifiable($('tree').selectedFolders); |
| 635 break; | 639 break; |
| 636 | 640 |
| 637 case 'copy-command': | 641 case 'copy-command': |
| 638 e.canExecute = hasSelected() && !isTopLevelItem(); | 642 e.canExecute = hasSelected() && !isTopLevelItem(); |
| 639 break; | 643 break; |
| 640 | 644 |
| 641 default: | 645 default: |
| 642 canExecuteShared(e, isSearch()); | 646 canExecuteShared(e, isSearch()); |
| 643 } | 647 } |
| 644 } | 648 } |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 662 if (result != canEdit) { | 666 if (result != canEdit) { |
| 663 canEdit = result; | 667 canEdit = result; |
| 664 editingCommands.forEach(function(baseId) { | 668 editingCommands.forEach(function(baseId) { |
| 665 $(baseId + '-command').canExecuteChange(); | 669 $(baseId + '-command').canExecuteChange(); |
| 666 }); | 670 }); |
| 667 } | 671 } |
| 668 }); | 672 }); |
| 669 } | 673 } |
| 670 | 674 |
| 671 function handleChangeForTree(e) { | 675 function handleChangeForTree(e) { |
| 672 navigateTo(tree.selectedItem.bookmarkId); | 676 navigateTo($('tree').selectedItem.bookmarkId); |
| 673 } | 677 } |
| 674 | 678 |
| 675 function handleOrganizeButtonClick(e) { | 679 function handleOrganizeButtonClick(e) { |
| 676 updateEditingCommands(); | 680 updateEditingCommands(); |
| 677 $('add-new-bookmark-command').canExecuteChange(); | 681 $('add-new-bookmark-command').canExecuteChange(); |
| 678 $('new-folder-command').canExecuteChange(); | 682 $('new-folder-command').canExecuteChange(); |
| 679 $('sort-command').canExecuteChange(); | 683 $('sort-command').canExecuteChange(); |
| 680 } | 684 } |
| 681 | 685 |
| 682 function handleRename(e) { | 686 function handleRename(e) { |
| 683 var item = e.target; | 687 var item = e.target; |
| 684 var bookmarkNode = item.bookmarkNode; | 688 var bookmarkNode = item.bookmarkNode; |
| 685 chrome.bookmarks.update(bookmarkNode.id, {title: item.label}); | 689 chrome.bookmarks.update(bookmarkNode.id, {title: item.label}); |
| 686 performGlobalUndo = null; // This can't be undone, so disable global undo. | 690 performGlobalUndo = null; // This can't be undone, so disable global undo. |
| 687 } | 691 } |
| 688 | 692 |
| 689 function handleEdit(e) { | 693 function handleEdit(e) { |
| 690 var item = e.target; | 694 var item = e.target; |
| 691 var bookmarkNode = item.bookmarkNode; | 695 var bookmarkNode = item.bookmarkNode; |
| 692 var context = { | 696 var context = { |
| 693 title: bookmarkNode.title | 697 title: bookmarkNode.title |
| 694 }; | 698 }; |
| 695 if (!bmm.isFolder(bookmarkNode)) | 699 if (!bmm.isFolder(bookmarkNode)) |
| 696 context.url = bookmarkNode.url; | 700 context.url = bookmarkNode.url; |
| 697 | 701 |
| 698 if (bookmarkNode.id == 'new') { | 702 if (bookmarkNode.id == 'new') { |
| 699 selectItemsAfterUserAction(list); | 703 selectItemsAfterUserAction(/** @type {BookmarkList} */($('list'))); |
| 700 | 704 |
| 701 // New page | 705 // New page |
| 702 context.parentId = bookmarkNode.parentId; | 706 context.parentId = bookmarkNode.parentId; |
| 703 chrome.bookmarks.create(context, function(node) { | 707 chrome.bookmarks.create(context, function(node) { |
| 704 // A new node was created and will get added to the list due to the | 708 // A new node was created and will get added to the list due to the |
| 705 // handler. | 709 // handler. |
| 706 var dataModel = list.dataModel; | 710 var dataModel = $('list').dataModel; |
| 707 var index = dataModel.indexOf(bookmarkNode); | 711 var index = dataModel.indexOf(bookmarkNode); |
| 708 dataModel.splice(index, 1); | 712 dataModel.splice(index, 1); |
| 709 | 713 |
| 710 // Select new item. | 714 // Select new item. |
| 711 var newIndex = dataModel.findIndexById(node.id); | 715 var newIndex = dataModel.findIndexById(node.id); |
| 712 if (newIndex != -1) { | 716 if (newIndex != -1) { |
| 713 var sm = list.selectionModel; | 717 var sm = $('list').selectionModel; |
| 714 list.scrollIndexIntoView(newIndex); | 718 $('list').scrollIndexIntoView(newIndex); |
| 715 sm.leadIndex = sm.anchorIndex = sm.selectedIndex = newIndex; | 719 sm.leadIndex = sm.anchorIndex = sm.selectedIndex = newIndex; |
| 716 } | 720 } |
| 717 }); | 721 }); |
| 718 } else { | 722 } else { |
| 719 // Edit | 723 // Edit |
| 720 chrome.bookmarks.update(bookmarkNode.id, context); | 724 chrome.bookmarks.update(bookmarkNode.id, context); |
| 721 } | 725 } |
| 722 performGlobalUndo = null; // This can't be undone, so disable global undo. | 726 performGlobalUndo = null; // This can't be undone, so disable global undo. |
| 723 } | 727 } |
| 724 | 728 |
| 725 function handleCancelEdit(e) { | 729 function handleCancelEdit(e) { |
| 726 var item = e.target; | 730 var item = e.target; |
| 727 var bookmarkNode = item.bookmarkNode; | 731 var bookmarkNode = item.bookmarkNode; |
| 728 if (bookmarkNode.id == 'new') { | 732 if (bookmarkNode.id == 'new') { |
| 729 var dataModel = list.dataModel; | 733 var dataModel = $('list').dataModel; |
| 730 var index = dataModel.findIndexById('new'); | 734 var index = dataModel.findIndexById('new'); |
| 731 dataModel.splice(index, 1); | 735 dataModel.splice(index, 1); |
| 732 } | 736 } |
| 733 } | 737 } |
| 734 | 738 |
| 735 /** | 739 /** |
| 736 * Navigates to the folder that the selected item is in and selects it. This is | 740 * Navigates to the folder that the selected item is in and selects it. This is |
| 737 * used for the show-in-folder command. | 741 * used for the show-in-folder command. |
| 738 */ | 742 */ |
| 739 function showInFolder() { | 743 function showInFolder() { |
| 740 var bookmarkNode = list.selectedItem; | 744 var bookmarkNode = $('list').selectedItem; |
| 741 if (!bookmarkNode) | 745 if (!bookmarkNode) |
| 742 return; | 746 return; |
| 743 var parentId = bookmarkNode.parentId; | 747 var parentId = bookmarkNode.parentId; |
| 744 | 748 |
| 745 // After the list is loaded we should select the revealed item. | 749 // After the list is loaded we should select the revealed item. |
| 746 function selectItem() { | 750 function selectItem() { |
| 747 var index = list.dataModel.findIndexById(bookmarkNode.id); | 751 var index = $('list').dataModel.findIndexById(bookmarkNode.id); |
| 748 if (index == -1) | 752 if (index == -1) |
| 749 return; | 753 return; |
| 750 var sm = list.selectionModel; | 754 var sm = $('list').selectionModel; |
| 751 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; | 755 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; |
| 752 list.scrollIndexIntoView(index); | 756 $('list').scrollIndexIntoView(index); |
| 753 } | 757 } |
| 754 | 758 |
| 755 var treeItem = bmm.treeLookup[parentId]; | 759 var treeItem = bmm.treeLookup[parentId]; |
| 756 treeItem.reveal(); | 760 treeItem.reveal(); |
| 757 | 761 |
| 758 navigateTo(parentId, selectItem); | 762 navigateTo(parentId, selectItem); |
| 759 } | 763 } |
| 760 | 764 |
| 761 /** | 765 /** |
| 762 * @return {!cr.LinkController} The link controller used to open links based on | 766 * @return {!cr.LinkController} The link controller used to open links based on |
| 763 * user clicks and keyboard actions. | 767 * user clicks and keyboard actions. |
| 764 */ | 768 */ |
| 765 function getLinkController() { | 769 function getLinkController() { |
| 766 return linkController || | 770 return linkController || |
| 767 (linkController = new cr.LinkController(loadTimeData)); | 771 (linkController = new cr.LinkController(loadTimeData)); |
| 768 } | 772 } |
| 769 | 773 |
| 770 /** | 774 /** |
| 771 * Returns the selected bookmark nodes of the provided tree or list. | 775 * Returns the selected bookmark nodes of the provided tree or list. |
| 772 * If |opt_target| is not provided or null the active element is used. | 776 * If |opt_target| is not provided or null the active element is used. |
| 773 * Only call this if the list or the tree is focused. | 777 * Only call this if the list or the tree is focused. |
| 774 * @param {BookmarkList|BookmarkTree} opt_target The target list or tree. | 778 * @param {(BookmarkList|BookmarkTree)=} opt_target The target list or tree. |
| 775 * @return {!Array} Array of bookmark nodes. | 779 * @return {!Array} Array of bookmark nodes. |
| 776 */ | 780 */ |
| 777 function getSelectedBookmarkNodes(opt_target) { | 781 function getSelectedBookmarkNodes(opt_target) { |
| 778 return (opt_target || document.activeElement) == tree ? | 782 return (opt_target || document.activeElement) == $('tree') ? |
| 779 tree.selectedFolders : list.selectedItems; | 783 $('tree').selectedFolders : $('list').selectedItems; |
| 780 } | 784 } |
| 781 | 785 |
| 782 /** | 786 /** |
| 783 * @return {!Array.<string>} An array of the selected bookmark IDs. | 787 * @return {!Array.<string>} An array of the selected bookmark IDs. |
| 784 */ | 788 */ |
| 785 function getSelectedBookmarkIds() { | 789 function getSelectedBookmarkIds() { |
| 786 var selectedNodes = getSelectedBookmarkNodes(); | 790 var selectedNodes = getSelectedBookmarkNodes(); |
| 787 selectedNodes.sort(function(a, b) { return a.index - b.index }); | 791 selectedNodes.sort(function(a, b) { return a.index - b.index }); |
| 788 return selectedNodes.map(function(node) { | 792 return selectedNodes.map(function(node) { |
| 789 return node.id; | 793 return node.id; |
| 790 }); | 794 }); |
| 791 } | 795 } |
| 792 | 796 |
| 793 /** | 797 /** |
| 794 * @param {BookmarkTreeNode} node The node to test. | 798 * @param {BookmarkTreeNode} node The node to test. |
| 795 * @return {boolean} Whether the given node is unmodifiable. | 799 * @return {boolean} Whether the given node is unmodifiable. |
| 796 */ | 800 */ |
| 797 function isUnmodifiable(node) { | 801 function isUnmodifiable(node) { |
| 798 return node && node.unmodifiable; | 802 return node && node.unmodifiable; |
| 799 } | 803 } |
| 800 | 804 |
| 801 /** | 805 /** |
| 802 * @param {BookmarkList} A list of BookmarkNodes. | 806 * @param {Array.<BookmarkTreeNode>} nodes A list of BookmarkTreeNodes. |
| 803 * @return {boolean} Whether any of the nodes is managed. | 807 * @return {boolean} Whether any of the nodes is managed. |
| 804 */ | 808 */ |
| 805 function hasUnmodifiable(nodes) { | 809 function hasUnmodifiable(nodes) { |
| 806 return nodes.some(isUnmodifiable); | 810 return nodes.some(isUnmodifiable); |
| 807 } | 811 } |
| 808 | 812 |
| 809 /** | 813 /** |
| 810 * Opens the selected bookmarks. | 814 * Opens the selected bookmarks. |
| 811 * @param {LinkKind} kind The kind of link we want to open. | 815 * @param {cr.LinkKind} kind The kind of link we want to open. |
| 812 * @param {HTMLElement} opt_eventTarget The target of the user initiated event. | 816 * @param {HTMLElement=} opt_eventTarget The target of the user initiated event. |
| 813 */ | 817 */ |
| 814 function openBookmarks(kind, opt_eventTarget) { | 818 function openBookmarks(kind, opt_eventTarget) { |
| 815 // If we have selected any folders, we need to find all the bookmarks one | 819 // If we have selected any folders, we need to find all the bookmarks one |
| 816 // level down. We use multiple async calls to getSubtree instead of getting | 820 // level down. We use multiple async calls to getSubtree instead of getting |
| 817 // the whole tree since we would like to minimize the amount of data sent. | 821 // the whole tree since we would like to minimize the amount of data sent. |
| 818 | 822 |
| 819 var urlsP = getUrlsForOpenCommands(opt_eventTarget); | 823 var urlsP = getUrlsForOpenCommands(opt_eventTarget ? opt_eventTarget : null); |
| 820 urlsP.then(function(urls) { | 824 urlsP.then(function(urls) { |
| 821 getLinkController().openUrls(urls, kind); | 825 getLinkController().openUrls(assert(urls), kind); |
| 822 chrome.bookmarkManagerPrivate.recordLaunch(); | 826 chrome.bookmarkManagerPrivate.recordLaunch(); |
| 823 }); | 827 }); |
| 824 } | 828 } |
| 825 | 829 |
| 826 /** | 830 /** |
| 827 * Opens an item in the list. | 831 * Opens an item in the list. |
| 828 */ | 832 */ |
| 829 function openItem() { | 833 function openItem() { |
| 830 var bookmarkNodes = getSelectedBookmarkNodes(); | 834 var bookmarkNodes = getSelectedBookmarkNodes(); |
| 831 // If we double clicked or pressed enter on a single folder, navigate to it. | 835 // If we double clicked or pressed enter on a single folder, navigate to it. |
| 832 if (bookmarkNodes.length == 1 && bmm.isFolder(bookmarkNodes[0])) | 836 if (bookmarkNodes.length == 1 && bmm.isFolder(bookmarkNodes[0])) |
| 833 navigateTo(bookmarkNodes[0].id); | 837 navigateTo(bookmarkNodes[0].id); |
| 834 else | 838 else |
| 835 openBookmarks(LinkKind.FOREGROUND_TAB); | 839 openBookmarks(LinkKind.FOREGROUND_TAB); |
| 836 } | 840 } |
| 837 | 841 |
| 838 /** | 842 /** |
| 839 * Refreshes search results after delete or undo-delete. | 843 * Refreshes search results after delete or undo-delete. |
| 840 * This ensures children of deleted folders do not remain in results | 844 * This ensures children of deleted folders do not remain in results |
| 841 */ | 845 */ |
| 842 function updateSearchResults() { | 846 function updateSearchResults() { |
| 843 if (list.isSearch()) { | 847 if ($('list').isSearch()) { |
| 844 list.reload(); | 848 $('list').reload(); |
| 845 } | 849 } |
| 846 } | 850 } |
| 847 | 851 |
| 848 /** | 852 /** |
| 849 * Deletes the selected bookmarks. The bookmarks are saved in memory in case | 853 * Deletes the selected bookmarks. The bookmarks are saved in memory in case |
| 850 * the user needs to undo the deletion. | 854 * the user needs to undo the deletion. |
| 851 */ | 855 */ |
| 852 function deleteBookmarks() { | 856 function deleteBookmarks() { |
| 853 var selectedIds = getSelectedBookmarkIds(); | 857 var selectedIds = getSelectedBookmarkIds(); |
| 854 var filteredIds = getFilteredSelectedBookmarkIds(); | 858 var filteredIds = getFilteredSelectedBookmarkIds(); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 872 performDelete(); | 876 performDelete(); |
| 873 updateSearchResults(); | 877 updateSearchResults(); |
| 874 } | 878 } |
| 875 }); | 879 }); |
| 876 }); | 880 }); |
| 877 } | 881 } |
| 878 | 882 |
| 879 /** | 883 /** |
| 880 * Restores a tree of bookmarks under a specified folder. | 884 * Restores a tree of bookmarks under a specified folder. |
| 881 * @param {BookmarkTreeNode} node The node to restore. | 885 * @param {BookmarkTreeNode} node The node to restore. |
| 882 * @param {=string} parentId The ID of the folder to restore under. If not | 886 * @param {(string|number)=} opt_parentId If a string is passed, it's the ID of |
| 883 * specified, the original parentId of the node will be used. | 887 * the folder to restore under. If not specified or a number is passed (when |
| 888 * called by forEach), the original parentId of the node will be used. | |
| 884 */ | 889 */ |
| 885 function restoreTree(node, parentId) { | 890 function restoreTree(node, opt_parentId) { |
| 886 var bookmarkInfo = { | 891 var bookmarkInfo = { |
| 887 parentId: parentId || node.parentId, | 892 parentId: typeof opt_parentId == 'string' ? opt_parentId : node.parentId, |
| 888 title: node.title, | 893 title: node.title, |
| 889 index: node.index, | 894 index: node.index, |
| 890 url: node.url | 895 url: node.url |
| 891 }; | 896 }; |
| 892 | 897 |
| 893 chrome.bookmarks.create(bookmarkInfo, function(result) { | 898 chrome.bookmarks.create(bookmarkInfo, function(result) { |
| 894 if (!result) { | 899 if (!result) { |
| 895 console.error('Failed to restore bookmark.'); | 900 console.error('Failed to restore bookmark.'); |
| 896 return; | 901 return; |
| 897 } | 902 } |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 919 | 924 |
| 920 // Only a single level of undo is supported, so disable global undo now. | 925 // Only a single level of undo is supported, so disable global undo now. |
| 921 performGlobalUndo = null; | 926 performGlobalUndo = null; |
| 922 } | 927 } |
| 923 | 928 |
| 924 /** | 929 /** |
| 925 * Computes folder for "Add Page" and "Add Folder". | 930 * Computes folder for "Add Page" and "Add Folder". |
| 926 * @return {string} The id of folder node where we'll create new page/folder. | 931 * @return {string} The id of folder node where we'll create new page/folder. |
| 927 */ | 932 */ |
| 928 function computeParentFolderForNewItem() { | 933 function computeParentFolderForNewItem() { |
| 929 if (document.activeElement == tree) | 934 if (document.activeElement == $('tree')) |
| 930 return list.parentId; | 935 return $('list').parentId; |
| 931 var selectedItem = list.selectedItem; | 936 var selectedItem = $('list').selectedItem; |
| 932 return selectedItem && bmm.isFolder(selectedItem) ? | 937 return selectedItem && bmm.isFolder(selectedItem) ? |
| 933 selectedItem.id : list.parentId; | 938 selectedItem.id : $('list').parentId; |
| 934 } | 939 } |
| 935 | 940 |
| 936 /** | 941 /** |
| 937 * Callback for rename folder and edit command. This starts editing for | 942 * Callback for rename folder and edit command. This starts editing for |
| 938 * selected item. | 943 * selected item. |
| 939 */ | 944 */ |
| 940 function editSelectedItem() { | 945 function editSelectedItem() { |
| 941 if (document.activeElement == tree) { | 946 if (document.activeElement == $('tree')) { |
| 942 tree.selectedItem.editing = true; | 947 $('tree').selectedItem.editing = true; |
| 943 } else { | 948 } else { |
| 944 var li = list.getListItem(list.selectedItem); | 949 var li = $('list').getListItem($('list').selectedItem); |
| 945 if (li) | 950 if (li) |
| 946 li.editing = true; | 951 li.editing = true; |
| 947 } | 952 } |
| 948 } | 953 } |
| 949 | 954 |
| 950 /** | 955 /** |
| 951 * Callback for the new folder command. This creates a new folder and starts | 956 * Callback for the new folder command. This creates a new folder and starts |
| 952 * a rename of it. | 957 * a rename of it. |
| 953 */ | 958 */ |
| 954 function newFolder() { | 959 function newFolder() { |
| 955 performGlobalUndo = null; // This can't be undone, so disable global undo. | 960 performGlobalUndo = null; // This can't be undone, so disable global undo. |
| 956 | 961 |
| 957 var parentId = computeParentFolderForNewItem(); | 962 var parentId = computeParentFolderForNewItem(); |
| 958 | 963 |
| 959 // Callback is called after tree and list data model updated. | 964 // Callback is called after tree and list data model updated. |
| 960 function createFolder(callback) { | 965 function createFolder(callback) { |
| 961 chrome.bookmarks.create({ | 966 chrome.bookmarks.create({ |
| 962 title: loadTimeData.getString('new_folder_name'), | 967 title: loadTimeData.getString('new_folder_name'), |
| 963 parentId: parentId | 968 parentId: parentId |
| 964 }, callback); | 969 }, callback); |
| 965 } | 970 } |
| 966 | 971 |
| 967 if (document.activeElement == tree) { | 972 if (document.activeElement == $('tree')) { |
| 968 createFolder(function(newNode) { | 973 createFolder(function(newNode) { |
| 969 navigateTo(newNode.id, function() { | 974 navigateTo(newNode.id, function() { |
| 970 bmm.treeLookup[newNode.id].editing = true; | 975 bmm.treeLookup[newNode.id].editing = true; |
| 971 }); | 976 }); |
| 972 }); | 977 }); |
| 973 return; | 978 return; |
| 974 } | 979 } |
| 975 | 980 |
| 976 function editNewFolderInList() { | 981 function editNewFolderInList() { |
| 977 createFolder(function() { | 982 createFolder(function() { |
| 978 var index = list.dataModel.length - 1; | 983 var index = $('list').dataModel.length - 1; |
| 979 var sm = list.selectionModel; | 984 var sm = $('list').selectionModel; |
| 980 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; | 985 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; |
| 981 scrollIntoViewAndMakeEditable(index); | 986 scrollIntoViewAndMakeEditable(index); |
| 982 }); | 987 }); |
| 983 } | 988 } |
| 984 | 989 |
| 985 navigateTo(parentId, editNewFolderInList); | 990 navigateTo(parentId, editNewFolderInList); |
| 986 } | 991 } |
| 987 | 992 |
| 988 /** | 993 /** |
| 989 * Scrolls the list item into view and makes it editable. | 994 * Scrolls the list item into view and makes it editable. |
| 990 * @param {number} index The index of the item to make editable. | 995 * @param {number} index The index of the item to make editable. |
| 991 */ | 996 */ |
| 992 function scrollIntoViewAndMakeEditable(index) { | 997 function scrollIntoViewAndMakeEditable(index) { |
| 993 list.scrollIndexIntoView(index); | 998 $('list').scrollIndexIntoView(index); |
| 994 // onscroll is now dispatched asynchronously so we have to postpone | 999 // onscroll is now dispatched asynchronously so we have to postpone |
| 995 // the rest. | 1000 // the rest. |
| 996 setTimeout(function() { | 1001 setTimeout(function() { |
| 997 var item = list.getListItemByIndex(index); | 1002 var item = $('list').getListItemByIndex(index); |
| 998 if (item) | 1003 if (item) |
| 999 item.editing = true; | 1004 item.editing = true; |
| 1000 }); | 1005 }, 0); |
| 1001 } | 1006 } |
| 1002 | 1007 |
| 1003 /** | 1008 /** |
| 1004 * Adds a page to the current folder. This is called by the | 1009 * Adds a page to the current folder. This is called by the |
| 1005 * add-new-bookmark-command handler. | 1010 * add-new-bookmark-command handler. |
| 1006 */ | 1011 */ |
| 1007 function addPage() { | 1012 function addPage() { |
| 1008 var parentId = computeParentFolderForNewItem(); | 1013 var parentId = computeParentFolderForNewItem(); |
| 1009 | 1014 |
| 1010 function editNewBookmark() { | 1015 function editNewBookmark() { |
| 1011 var fakeNode = { | 1016 var fakeNode = { |
| 1012 title: '', | 1017 title: '', |
| 1013 url: '', | 1018 url: '', |
| 1014 parentId: parentId, | 1019 parentId: parentId, |
| 1015 id: 'new' | 1020 id: 'new' |
| 1016 }; | 1021 }; |
| 1017 var dataModel = list.dataModel; | 1022 var dataModel = $('list').dataModel; |
| 1018 var length = dataModel.length; | 1023 var length = dataModel.length; |
| 1019 dataModel.splice(length, 0, fakeNode); | 1024 dataModel.splice(length, 0, fakeNode); |
| 1020 var sm = list.selectionModel; | 1025 var sm = $('list').selectionModel; |
| 1021 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = length; | 1026 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = length; |
| 1022 scrollIntoViewAndMakeEditable(length); | 1027 scrollIntoViewAndMakeEditable(length); |
| 1023 }; | 1028 }; |
| 1024 | 1029 |
| 1025 navigateTo(parentId, editNewBookmark); | 1030 navigateTo(parentId, editNewBookmark); |
| 1026 } | 1031 } |
| 1027 | 1032 |
| 1028 /** | 1033 /** |
| 1029 * This function is used to select items after a user action such as paste, drop | 1034 * This function is used to select items after a user action such as paste, drop |
| 1030 * add page etc. | 1035 * add page etc. |
| 1031 * @param {BookmarkList|BookmarkTree} target The target of the user action. | 1036 * @param {BookmarkList|BookmarkTree} target The target of the user action. |
| 1032 * @param {=string} opt_selectedTreeId If provided, then select that tree id. | 1037 * @param {string=} opt_selectedTreeId If provided, then select that tree id. |
| 1033 */ | 1038 */ |
| 1034 function selectItemsAfterUserAction(target, opt_selectedTreeId) { | 1039 function selectItemsAfterUserAction(target, opt_selectedTreeId) { |
| 1035 // We get one onCreated event per item so we delay the handling until we get | 1040 // We get one onCreated event per item so we delay the handling until we get |
| 1036 // no more events coming. | 1041 // no more events coming. |
| 1037 | 1042 |
| 1038 var ids = []; | 1043 var ids = []; |
| 1039 var timer; | 1044 var timer; |
| 1040 | 1045 |
| 1041 function handle(id, bookmarkNode) { | 1046 function handle(id, bookmarkNode) { |
| 1042 clearTimeout(timer); | 1047 clearTimeout(timer); |
| 1043 if (opt_selectedTreeId || list.parentId == bookmarkNode.parentId) | 1048 if (opt_selectedTreeId || $('list').parentId == bookmarkNode.parentId) |
| 1044 ids.push(id); | 1049 ids.push(id); |
| 1045 timer = setTimeout(handleTimeout, 50); | 1050 timer = setTimeout(handleTimeout, 50); |
| 1046 } | 1051 } |
| 1047 | 1052 |
| 1048 function handleTimeout() { | 1053 function handleTimeout() { |
| 1049 chrome.bookmarks.onCreated.removeListener(handle); | 1054 chrome.bookmarks.onCreated.removeListener(handle); |
| 1050 chrome.bookmarks.onMoved.removeListener(handle); | 1055 chrome.bookmarks.onMoved.removeListener(handle); |
| 1051 | 1056 |
| 1052 if (opt_selectedTreeId && ids.indexOf(opt_selectedTreeId) != -1) { | 1057 if (opt_selectedTreeId && ids.indexOf(opt_selectedTreeId) != -1) { |
| 1053 var index = ids.indexOf(opt_selectedTreeId); | 1058 var index = ids.indexOf(opt_selectedTreeId); |
| 1054 if (index != -1 && opt_selectedTreeId in bmm.treeLookup) { | 1059 if (index != -1 && opt_selectedTreeId in bmm.treeLookup) { |
| 1055 tree.selectedItem = bmm.treeLookup[opt_selectedTreeId]; | 1060 $('tree').selectedItem = bmm.treeLookup[opt_selectedTreeId]; |
| 1056 } | 1061 } |
| 1057 } else if (target == list) { | 1062 } else if (target == $('list')) { |
| 1058 var dataModel = list.dataModel; | 1063 var dataModel = $('list').dataModel; |
| 1059 var firstIndex = dataModel.findIndexById(ids[0]); | 1064 var firstIndex = dataModel.findIndexById(ids[0]); |
| 1060 var lastIndex = dataModel.findIndexById(ids[ids.length - 1]); | 1065 var lastIndex = dataModel.findIndexById(ids[ids.length - 1]); |
| 1061 if (firstIndex != -1 && lastIndex != -1) { | 1066 if (firstIndex != -1 && lastIndex != -1) { |
| 1062 var selectionModel = list.selectionModel; | 1067 var selectionModel = $('list').selectionModel; |
| 1063 selectionModel.selectedIndex = -1; | 1068 selectionModel.selectedIndex = -1; |
| 1064 selectionModel.selectRange(firstIndex, lastIndex); | 1069 selectionModel.selectRange(firstIndex, lastIndex); |
| 1065 selectionModel.anchorIndex = selectionModel.leadIndex = lastIndex; | 1070 selectionModel.anchorIndex = selectionModel.leadIndex = lastIndex; |
| 1066 list.focus(); | 1071 $('list').focus(); |
| 1067 } | 1072 } |
| 1068 } | 1073 } |
| 1069 | 1074 |
| 1070 list.endBatchUpdates(); | 1075 $('list').endBatchUpdates(); |
| 1071 } | 1076 } |
| 1072 | 1077 |
| 1073 list.startBatchUpdates(); | 1078 $('list').startBatchUpdates(); |
| 1074 | 1079 |
| 1075 chrome.bookmarks.onCreated.addListener(handle); | 1080 chrome.bookmarks.onCreated.addListener(handle); |
| 1076 chrome.bookmarks.onMoved.addListener(handle); | 1081 chrome.bookmarks.onMoved.addListener(handle); |
| 1077 timer = setTimeout(handleTimeout, 300); | 1082 timer = setTimeout(handleTimeout, 300); |
| 1078 } | 1083 } |
| 1079 | 1084 |
| 1080 /** | 1085 /** |
| 1081 * Record user action. | 1086 * Record user action. |
| 1082 * @param {string} name An user action name. | 1087 * @param {string} name An user action name. |
| 1083 */ | 1088 */ |
| 1084 function recordUserAction(name) { | 1089 function recordUserAction(name) { |
| 1085 chrome.metricsPrivate.recordUserAction('BookmarkManager_Command_' + name); | 1090 chrome.metricsPrivate.recordUserAction('BookmarkManager_Command_' + name); |
| 1086 } | 1091 } |
| 1087 | 1092 |
| 1088 /** | 1093 /** |
| 1089 * The currently selected bookmark, based on where the user is clicking. | 1094 * The currently selected bookmark, based on where the user is clicking. |
| 1090 * @return {string} The ID of the currently selected bookmark (could be from | 1095 * @return {string} The ID of the currently selected bookmark (could be from |
| 1091 * tree view or list view). | 1096 * tree view or list view). |
| 1092 */ | 1097 */ |
| 1093 function getSelectedId() { | 1098 function getSelectedId() { |
| 1094 if (document.activeElement == tree) | 1099 if (document.activeElement == $('tree')) |
| 1095 return tree.selectedItem.bookmarkId; | 1100 return $('tree').selectedItem.bookmarkId; |
| 1096 var selectedItem = list.selectedItem; | 1101 var selectedItem = $('list').selectedItem; |
| 1097 return selectedItem && bmm.isFolder(selectedItem) ? | 1102 return selectedItem && bmm.isFolder(selectedItem) ? |
| 1098 selectedItem.id : tree.selectedItem.bookmarkId; | 1103 selectedItem.id : $('tree').selectedItem.bookmarkId; |
| 1099 } | 1104 } |
| 1100 | 1105 |
| 1101 /** | 1106 /** |
| 1102 * Pastes the copied/cutted bookmark into the right location depending whether | 1107 * Pastes the copied/cutted bookmark into the right location depending whether |
| 1103 * if it was called from Organize Menu or from Context Menu. | 1108 * if it was called from Organize Menu or from Context Menu. |
| 1104 * @param {string} id The id of the element being pasted from. | 1109 * @param {string} id The id of the element being pasted from. |
| 1105 */ | 1110 */ |
| 1106 function pasteBookmark(id) { | 1111 function pasteBookmark(id) { |
| 1107 recordUserAction('Paste'); | 1112 recordUserAction('Paste'); |
| 1108 selectItemsAfterUserAction(list); | 1113 selectItemsAfterUserAction(/** @type {BookmarkList} */($('list'))); |
| 1109 chrome.bookmarkManagerPrivate.paste(id, getSelectedBookmarkIds()); | 1114 chrome.bookmarkManagerPrivate.paste(id, getSelectedBookmarkIds()); |
| 1110 } | 1115 } |
| 1111 | 1116 |
| 1112 /** | 1117 /** |
| 1113 * Returns true if child is contained in another selected folder. | 1118 * Returns true if child is contained in another selected folder. |
| 1114 * Traces parent nodes up the tree until a selected ancestor or root is found. | 1119 * Traces parent nodes up the tree until a selected ancestor or root is found. |
| 1115 */ | 1120 */ |
| 1116 function hasSelectedAncestor(parentNode) { | 1121 function hasSelectedAncestor(parentNode) { |
| 1117 function contains(arr, item) { | 1122 function contains(arr, item) { |
| 1118 for (var i = 0; i < arr.length; i++) | 1123 for (var i = 0; i < arr.length; i++) |
| 1119 if (arr[i] === item) | 1124 if (arr[i] === item) |
| 1120 return true; | 1125 return true; |
| 1121 return false; | 1126 return false; |
| 1122 } | 1127 } |
| 1123 | 1128 |
| 1124 // Don't search top level, cannot select permanent nodes in search. | 1129 // Don't search top level, cannot select permanent nodes in search. |
| 1125 if (parentNode == null || parentNode.id <= 2) | 1130 if (parentNode == null || parentNode.id <= 2) |
| 1126 return false; | 1131 return false; |
| 1127 | 1132 |
| 1128 // Found selected ancestor. | 1133 // Found selected ancestor. |
| 1129 if (contains(getSelectedBookmarkNodes(), parentNode)) | 1134 if (contains(getSelectedBookmarkNodes(), parentNode)) |
| 1130 return true; | 1135 return true; |
| 1131 | 1136 |
| 1132 // Keep digging. | 1137 // Keep digging. |
| 1133 return hasSelectedAncestor(tree.getBookmarkNodeById(parentNode.parentId)); | 1138 return hasSelectedAncestor( |
| 1139 $('tree').getBookmarkNodeById(parentNode.parentId)); | |
| 1134 } | 1140 } |
| 1135 | 1141 |
| 1136 function getFilteredSelectedBookmarkIds() { | 1142 function getFilteredSelectedBookmarkIds() { |
| 1137 // Remove duplicates from filteredIds and return. | 1143 // Remove duplicates from filteredIds and return. |
| 1138 var filteredIds = new Array(); | 1144 var filteredIds = new Array(); |
| 1139 // Selected nodes to iterate through for matches. | 1145 // Selected nodes to iterate through for matches. |
| 1140 var nodes = getSelectedBookmarkNodes(); | 1146 var nodes = getSelectedBookmarkNodes(); |
| 1141 | 1147 |
| 1142 for (var i = 0; i < nodes.length; i++) | 1148 for (var i = 0; i < nodes.length; i++) |
| 1143 if (!hasSelectedAncestor(tree.getBookmarkNodeById(nodes[i].parentId))) | 1149 if (!hasSelectedAncestor($('tree').getBookmarkNodeById(nodes[i].parentId))) |
| 1144 filteredIds.splice(0, 0, nodes[i].id); | 1150 filteredIds.splice(0, 0, nodes[i].id); |
| 1145 | 1151 |
| 1146 return filteredIds; | 1152 return filteredIds; |
| 1147 } | 1153 } |
| 1148 | 1154 |
| 1149 /** | 1155 /** |
| 1150 * Handler for the command event. This is used for context menu of list/tree | 1156 * Handler for the command event. This is used for context menu of list/tree |
| 1151 * and organized menu. | 1157 * and organized menu. |
| 1152 * @param {!Event} e The event object. | 1158 * @param {!Event} e The event object. |
| 1153 */ | 1159 */ |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 1171 recordUserAction('UndoNone'); | 1177 recordUserAction('UndoNone'); |
| 1172 } | 1178 } |
| 1173 break; | 1179 break; |
| 1174 case 'show-in-folder-command': | 1180 case 'show-in-folder-command': |
| 1175 recordUserAction('ShowInFolder'); | 1181 recordUserAction('ShowInFolder'); |
| 1176 showInFolder(); | 1182 showInFolder(); |
| 1177 break; | 1183 break; |
| 1178 case 'open-in-new-tab-command': | 1184 case 'open-in-new-tab-command': |
| 1179 case 'open-in-background-tab-command': | 1185 case 'open-in-background-tab-command': |
| 1180 recordUserAction('OpenInNewTab'); | 1186 recordUserAction('OpenInNewTab'); |
| 1181 openBookmarks(LinkKind.BACKGROUND_TAB, e.target); | 1187 openBookmarks(LinkKind.BACKGROUND_TAB, |
| 1188 assertInstanceof(e.target, HTMLElement)); | |
| 1182 break; | 1189 break; |
| 1183 case 'open-in-new-window-command': | 1190 case 'open-in-new-window-command': |
| 1184 recordUserAction('OpenInNewWindow'); | 1191 recordUserAction('OpenInNewWindow'); |
| 1185 openBookmarks(LinkKind.WINDOW, e.target); | 1192 openBookmarks(LinkKind.WINDOW, |
| 1193 assertInstanceof(e.target, HTMLElement)); | |
| 1186 break; | 1194 break; |
| 1187 case 'open-incognito-window-command': | 1195 case 'open-incognito-window-command': |
| 1188 recordUserAction('OpenIncognito'); | 1196 recordUserAction('OpenIncognito'); |
| 1189 openBookmarks(LinkKind.INCOGNITO, e.target); | 1197 openBookmarks(LinkKind.INCOGNITO, |
| 1198 assertInstanceof(e.target, HTMLElement)); | |
| 1190 break; | 1199 break; |
| 1191 case 'delete-command': | 1200 case 'delete-command': |
| 1192 recordUserAction('Delete'); | 1201 recordUserAction('Delete'); |
| 1193 deleteBookmarks(); | 1202 deleteBookmarks(); |
| 1194 break; | 1203 break; |
| 1195 case 'copy-command': | 1204 case 'copy-command': |
| 1196 recordUserAction('Copy'); | 1205 recordUserAction('Copy'); |
| 1197 chrome.bookmarkManagerPrivate.copy(getSelectedBookmarkIds(), | 1206 chrome.bookmarkManagerPrivate.copy(getSelectedBookmarkIds(), |
| 1198 updatePasteCommand); | 1207 updatePasteCommand); |
| 1199 break; | 1208 break; |
| 1200 case 'cut-command': | 1209 case 'cut-command': |
| 1201 recordUserAction('Cut'); | 1210 recordUserAction('Cut'); |
| 1202 chrome.bookmarkManagerPrivate.cut(getSelectedBookmarkIds(), | 1211 chrome.bookmarkManagerPrivate.cut(getSelectedBookmarkIds(), |
| 1203 function() { | 1212 function() { |
| 1204 updatePasteCommand(); | 1213 updatePasteCommand(); |
| 1205 updateSearchResults(); | 1214 updateSearchResults(); |
| 1206 }); | 1215 }); |
| 1207 break; | 1216 break; |
| 1208 case 'paste-from-organize-menu-command': | 1217 case 'paste-from-organize-menu-command': |
| 1209 pasteBookmark(list.parentId); | 1218 pasteBookmark($('list').parentId); |
| 1210 break; | 1219 break; |
| 1211 case 'paste-from-context-menu-command': | 1220 case 'paste-from-context-menu-command': |
| 1212 pasteBookmark(getSelectedId()); | 1221 pasteBookmark(getSelectedId()); |
| 1213 break; | 1222 break; |
| 1214 case 'sort-command': | 1223 case 'sort-command': |
| 1215 recordUserAction('Sort'); | 1224 recordUserAction('Sort'); |
| 1216 chrome.bookmarkManagerPrivate.sortChildren(list.parentId); | 1225 chrome.bookmarkManagerPrivate.sortChildren($('list').parentId); |
| 1217 break; | 1226 break; |
| 1218 case 'rename-folder-command': | 1227 case 'rename-folder-command': |
| 1219 editSelectedItem(); | 1228 editSelectedItem(); |
| 1220 break; | 1229 break; |
| 1221 case 'edit-command': | 1230 case 'edit-command': |
| 1222 recordUserAction('Edit'); | 1231 recordUserAction('Edit'); |
| 1223 editSelectedItem(); | 1232 editSelectedItem(); |
| 1224 break; | 1233 break; |
| 1225 case 'new-folder-command': | 1234 case 'new-folder-command': |
| 1226 recordUserAction('NewFolder'); | 1235 recordUserAction('NewFolder'); |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1239 undoDelete(); | 1248 undoDelete(); |
| 1240 break; | 1249 break; |
| 1241 } | 1250 } |
| 1242 } | 1251 } |
| 1243 | 1252 |
| 1244 // Execute the copy, cut and paste commands when those events are dispatched by | 1253 // Execute the copy, cut and paste commands when those events are dispatched by |
| 1245 // the browser. This allows us to rely on the browser to handle the keyboard | 1254 // the browser. This allows us to rely on the browser to handle the keyboard |
| 1246 // shortcuts for these commands. | 1255 // shortcuts for these commands. |
| 1247 function installEventHandlerForCommand(eventName, commandId) { | 1256 function installEventHandlerForCommand(eventName, commandId) { |
| 1248 function handle(e) { | 1257 function handle(e) { |
| 1249 if (document.activeElement != list && document.activeElement != tree) | 1258 if (document.activeElement != $('list') && |
| 1259 document.activeElement != $('tree')) | |
| 1250 return; | 1260 return; |
| 1251 var command = $(commandId); | 1261 var command = $(commandId); |
| 1252 if (!command.disabled) { | 1262 if (!command.disabled) { |
| 1253 command.execute(); | 1263 command.execute(); |
| 1254 if (e) | 1264 if (e) |
| 1255 e.preventDefault(); // Prevent the system beep. | 1265 e.preventDefault(); // Prevent the system beep. |
| 1256 } | 1266 } |
| 1257 } | 1267 } |
| 1258 if (eventName == 'paste') { | 1268 if (eventName == 'paste') { |
| 1259 // Paste is a bit special since we need to do an async call to see if we | 1269 // Paste is a bit special since we need to do an async call to see if we |
| 1260 // can paste because the paste command might not be up to date. | 1270 // can paste because the paste command might not be up to date. |
| 1261 document.addEventListener(eventName, function(e) { | 1271 document.addEventListener(eventName, function(e) { |
| 1262 updatePasteCommand(handle); | 1272 updatePasteCommand(handle); |
| 1263 }); | 1273 }); |
| 1264 } else { | 1274 } else { |
| 1265 document.addEventListener(eventName, handle); | 1275 document.addEventListener(eventName, handle); |
| 1266 } | 1276 } |
| 1267 } | 1277 } |
| 1268 | 1278 |
| 1269 function initializeSplitter() { | 1279 function initializeSplitter() { |
| 1270 var splitter = document.querySelector('.main > .splitter'); | 1280 var splitter = document.querySelector('.main > .splitter'); |
| 1271 Splitter.decorate(splitter); | 1281 Splitter.decorate(splitter); |
| 1272 | 1282 |
| 1273 // The splitter persists the size of the left component in the local store. | 1283 // The splitter persists the size of the left component in the local store. |
| 1274 if ('treeWidth' in localStorage) | 1284 if ('treeWidth' in window.localStorage) |
| 1275 splitter.previousElementSibling.style.width = localStorage['treeWidth']; | 1285 splitter.previousElementSibling.style.width = |
| 1286 window.localStorage['treeWidth']; | |
| 1276 | 1287 |
| 1277 splitter.addEventListener('resize', function(e) { | 1288 splitter.addEventListener('resize', function(e) { |
| 1278 localStorage['treeWidth'] = splitter.previousElementSibling.style.width; | 1289 window.localStorage['treeWidth'] = |
| 1290 splitter.previousElementSibling.style.width; | |
| 1279 }); | 1291 }); |
| 1280 } | 1292 } |
| 1281 | 1293 |
| 1282 function initializeBookmarkManager() { | 1294 function initializeBookmarkManager() { |
| 1283 // Sometimes the extension API is not initialized. | 1295 // Sometimes the extension API is not initialized. |
| 1284 if (!chrome.bookmarks) | 1296 if (!chrome.bookmarks) |
| 1285 console.error('Bookmarks extension API is not available'); | 1297 console.error('Bookmarks extension API is not available'); |
| 1286 | 1298 |
| 1287 chrome.bookmarkManagerPrivate.getStrings(continueInitializeBookmarkManager); | 1299 chrome.bookmarkManagerPrivate.getStrings(continueInitializeBookmarkManager); |
| 1288 } | 1300 } |
| 1289 | 1301 |
| 1290 function continueInitializeBookmarkManager(localizedStrings) { | 1302 function continueInitializeBookmarkManager(localizedStrings) { |
| 1291 loadLocalizedStrings(localizedStrings); | 1303 loadLocalizedStrings(localizedStrings); |
| 1292 | 1304 |
| 1293 bmm.treeLookup[searchTreeItem.bookmarkId] = searchTreeItem; | 1305 bmm.treeLookup[searchTreeItem.bookmarkId] = searchTreeItem; |
| 1294 | 1306 |
| 1295 cr.ui.decorate('menu', Menu); | 1307 cr.ui.decorate('menu', Menu); |
| 1296 cr.ui.decorate('button[menu]', MenuButton); | 1308 cr.ui.decorate('button[menu]', MenuButton); |
| 1297 cr.ui.decorate('command', Command); | 1309 cr.ui.decorate('command', Command); |
| 1298 BookmarkList.decorate(list); | 1310 BookmarkList.decorate($('list')); |
| 1299 BookmarkTree.decorate(tree); | 1311 BookmarkTree.decorate($('tree')); |
| 1300 | 1312 |
| 1301 list.addEventListener('canceledit', handleCancelEdit); | 1313 $('list').addEventListener('canceledit', handleCancelEdit); |
| 1302 list.addEventListener('canExecute', handleCanExecuteForList); | 1314 $('list').addEventListener('canExecute', handleCanExecuteForList); |
| 1303 list.addEventListener('change', updateAllCommands); | 1315 $('list').addEventListener('change', updateAllCommands); |
| 1304 list.addEventListener('contextmenu', updateEditingCommands); | 1316 $('list').addEventListener('contextmenu', updateEditingCommands); |
| 1305 list.addEventListener('dblclick', handleDoubleClickForList); | 1317 $('list').addEventListener('dblclick', handleDoubleClickForList); |
| 1306 list.addEventListener('edit', handleEdit); | 1318 $('list').addEventListener('edit', handleEdit); |
| 1307 list.addEventListener('rename', handleRename); | 1319 $('list').addEventListener('rename', handleRename); |
| 1308 list.addEventListener('urlClicked', handleUrlClickedForList); | 1320 $('list').addEventListener('urlClicked', handleUrlClickedForList); |
| 1309 | 1321 |
| 1310 tree.addEventListener('canExecute', handleCanExecuteForTree); | 1322 $('tree').addEventListener('canExecute', handleCanExecuteForTree); |
| 1311 tree.addEventListener('change', handleChangeForTree); | 1323 $('tree').addEventListener('change', handleChangeForTree); |
| 1312 tree.addEventListener('contextmenu', updateEditingCommands); | 1324 $('tree').addEventListener('contextmenu', updateEditingCommands); |
| 1313 tree.addEventListener('rename', handleRename); | 1325 $('tree').addEventListener('rename', handleRename); |
| 1314 tree.addEventListener('load', handleLoadForTree); | 1326 $('tree').addEventListener('load', handleLoadForTree); |
| 1315 | 1327 |
| 1316 cr.ui.contextMenuHandler.addContextMenuProperty(tree); | 1328 cr.ui.contextMenuHandler.addContextMenuProperty( |
| 1317 list.contextMenu = $('context-menu'); | 1329 /** @type {!Element} */($('tree'))); |
| 1318 tree.contextMenu = $('context-menu'); | 1330 $('list').contextMenu = $('context-menu'); |
| 1331 $('tree').contextMenu = $('context-menu'); | |
| 1319 | 1332 |
| 1320 // We listen to hashchange so that we can update the currently shown folder | 1333 // We listen to hashchange so that we can update the currently shown folder |
| 1321 // when // the user goes back and forward in the history. | 1334 // when // the user goes back and forward in the history. |
| 1322 window.addEventListener('hashchange', processHash); | 1335 window.addEventListener('hashchange', processHash); |
| 1323 | 1336 |
| 1324 document.querySelector('header form').onsubmit = function(e) { | 1337 document.querySelector('header form').onsubmit = |
| 1338 /** @type {function(Event=)} */(function(e) { | |
| 1325 setSearch($('term').value); | 1339 setSearch($('term').value); |
| 1326 e.preventDefault(); | 1340 e.preventDefault(); |
| 1327 }; | 1341 }); |
| 1328 | 1342 |
| 1329 $('term').addEventListener('search', handleSearch); | 1343 $('term').addEventListener('search', handleSearch); |
| 1330 | 1344 |
| 1331 document.querySelector('.summary button').addEventListener( | 1345 document.querySelector('.summary button').addEventListener( |
| 1332 'click', handleOrganizeButtonClick); | 1346 'click', handleOrganizeButtonClick); |
| 1333 | 1347 |
| 1334 document.addEventListener('canExecute', handleCanExecuteForDocument); | 1348 document.addEventListener('canExecute', handleCanExecuteForDocument); |
| 1335 document.addEventListener('command', handleCommand); | 1349 document.addEventListener('command', handleCommand); |
| 1336 | 1350 |
| 1337 // Listen to copy, cut and paste events and execute the associated commands. | 1351 // Listen to copy, cut and paste events and execute the associated commands. |
| (...skipping 26 matching lines...) Expand all Loading... | |
| 1364 }); | 1378 }); |
| 1365 | 1379 |
| 1366 chrome.bookmarkManagerPrivate.canOpenNewWindows(function(result) { | 1380 chrome.bookmarkManagerPrivate.canOpenNewWindows(function(result) { |
| 1367 canOpenNewWindows = result; | 1381 canOpenNewWindows = result; |
| 1368 }); | 1382 }); |
| 1369 | 1383 |
| 1370 cr.ui.FocusOutlineManager.forDocument(document); | 1384 cr.ui.FocusOutlineManager.forDocument(document); |
| 1371 initializeSplitter(); | 1385 initializeSplitter(); |
| 1372 bmm.addBookmarkModelListeners(); | 1386 bmm.addBookmarkModelListeners(); |
| 1373 dnd.init(selectItemsAfterUserAction); | 1387 dnd.init(selectItemsAfterUserAction); |
| 1374 tree.reload(); | 1388 $('tree').reload(); |
| 1375 } | 1389 } |
| 1376 | 1390 |
| 1377 initializeBookmarkManager(); | 1391 initializeBookmarkManager(); |
| 1378 })(); | 1392 })(); |
| OLD | NEW |