| 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 /** @const */ var BookmarkList = bmm.BookmarkList; | 5 /** @const */ var BookmarkList = bmm.BookmarkList; |
| 6 /** @const */ var BookmarkTree = bmm.BookmarkTree; | 6 /** @const */ var BookmarkTree = bmm.BookmarkTree; |
| 7 /** @const */ var Command = cr.ui.Command; | 7 /** @const */ var Command = cr.ui.Command; |
| 8 /** @const */ var CommandBinding = cr.ui.CommandBinding; | 8 /** @const */ var CommandBinding = cr.ui.CommandBinding; |
| 9 /** @const */ var LinkKind = cr.LinkKind; | 9 /** @const */ var LinkKind = cr.LinkKind; |
| 10 /** @const */ var ListItem = cr.ui.ListItem; | 10 /** @const */ var ListItem = cr.ui.ListItem; |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 93 | 93 |
| 94 var recentTreeItem = new TreeItem({ | 94 var recentTreeItem = new TreeItem({ |
| 95 icon: 'images/bookmark_manager_recent.png', | 95 icon: 'images/bookmark_manager_recent.png', |
| 96 bookmarkId: 'recent' | 96 bookmarkId: 'recent' |
| 97 }); | 97 }); |
| 98 bmm.treeLookup[recentTreeItem.bookmarkId] = recentTreeItem; | 98 bmm.treeLookup[recentTreeItem.bookmarkId] = recentTreeItem; |
| 99 | 99 |
| 100 BookmarkTree.decorate(tree); | 100 BookmarkTree.decorate(tree); |
| 101 | 101 |
| 102 tree.addEventListener('change', function() { | 102 tree.addEventListener('change', function() { |
| 103 navigateTo(tree.selectedItem.bookmarkId); | 103 navigateTo(tree.selectedItem.bookmarkId, updateHash); |
| 104 }); | 104 }); |
| 105 | 105 |
| 106 /** | 106 /** |
| 107 * Adds an event listener to a node that will remove itself after firing once. | 107 * Adds an event listener to a node that will remove itself after firing once. |
| 108 * @param {!Element} node The DOM node to add the listener to. | 108 * @param {!Element} node The DOM node to add the listener to. |
| 109 * @param {string} name The name of the event listener to add to. | 109 * @param {string} name The name of the event listener to add to. |
| 110 * @param {function(Event)} handler Function called when the event fires. | 110 * @param {function(Event)} handler Function called when the event fires. |
| 111 */ | 111 */ |
| 112 function addOneShotEventListener(node, name, handler) { | 112 function addOneShotEventListener(node, name, handler) { |
| 113 var f = function(e) { | 113 var f = function(e) { |
| 114 handler(e); | 114 handler(e); |
| 115 node.removeEventListener(name, f); | 115 node.removeEventListener(name, f); |
| 116 }; | 116 }; |
| 117 node.addEventListener(name, f); | 117 node.addEventListener(name, f); |
| 118 } | 118 } |
| 119 | 119 |
| 120 /** | 120 /** |
| 121 * Updates the location hash to reflect the current state of the application. | 121 * Updates the location hash to reflect the current state of the application. |
| 122 */ | 122 */ |
| 123 function updateHash() { | 123 function updateHash() { |
| 124 window.location.hash = tree.selectedItem.bookmarkId; | 124 window.location.hash = tree.selectedItem.bookmarkId; |
| 125 } | 125 } |
| 126 | 126 |
| 127 /** | 127 /** |
| 128 * Navigates to a bookmark ID. | 128 * Navigates to a bookmark ID. |
| 129 * @param {string} id The ID to navigate to. | 129 * @param {string} id The ID to navigate to. |
| 130 * @param {boolean=} opt_updateHashNow Whether to immediately update the | 130 * @param {function()} callback Function called when list view loaded or |
| 131 * location.hash. If false, then it is updated in a timeout. | 131 * displayed specified folder. |
| 132 */ | 132 */ |
| 133 function navigateTo(id, opt_updateHashNow) { | 133 function navigateTo(id, callback) { |
| 134 // console.info('navigateTo', 'from', window.location.hash, 'to', id); | 134 if (list.parentId == id) { |
| 135 // Update the location hash using a timer to prevent reentrancy. This is how | 135 callback(); |
| 136 // often we add history entries and the time here is a bit arbitrary but was | 136 return; |
| 137 // picked as the smallest time a human perceives as instant. | 137 } |
| 138 | 138 |
| 139 clearTimeout(navigateTo.timer_); | 139 addOneShotEventListener(list, 'load', callback); |
| 140 if (opt_updateHashNow) | |
| 141 updateHash(); | |
| 142 else | |
| 143 navigateTo.timer_ = setTimeout(updateHash, 250); | |
| 144 | |
| 145 updateParentId(id); | 140 updateParentId(id); |
| 146 } | 141 } |
| 147 | 142 |
| 148 /** | 143 /** |
| 149 * Updates the parent ID of the bookmark list and selects the correct tree item. | 144 * Updates the parent ID of the bookmark list and selects the correct tree item. |
| 150 * @param {string} id The id. | 145 * @param {string} id The id. |
| 151 */ | 146 */ |
| 152 function updateParentId(id) { | 147 function updateParentId(id) { |
| 148 // Setting list.parentId fires 'load' event. |
| 153 list.parentId = id; | 149 list.parentId = id; |
| 154 if (id in bmm.treeLookup) | 150 |
| 155 tree.selectedItem = bmm.treeLookup[id]; | 151 // When tree.selectedItem changed, tree view calls navigatTo() then it |
| 152 // calls updateHash() when list view displayed specified folder. |
| 153 tree.selectedItem = bmm.treeLookup[id] || tree.selectedItem; |
| 156 } | 154 } |
| 157 | 155 |
| 158 // Process the location hash. This is called by onhashchange and when the page | 156 // Process the location hash. This is called by onhashchange and when the page |
| 159 // is first loaded. | 157 // is first loaded. |
| 160 function processHash() { | 158 function processHash() { |
| 161 var id = window.location.hash.slice(1); | 159 var id = window.location.hash.slice(1); |
| 162 if (!id) { | 160 if (!id) { |
| 163 // If we do not have a hash, select first item in the tree. | 161 // If we do not have a hash, select first item in the tree. |
| 164 id = tree.items[0].bookmarkId; | 162 id = tree.items[0].bookmarkId; |
| 165 } | 163 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 178 // After the list reloads, edit the desired bookmark. | 176 // After the list reloads, edit the desired bookmark. |
| 179 var editBookmark = function(e) { | 177 var editBookmark = function(e) { |
| 180 var index = list.dataModel.findIndexById(bookmarkNode.id); | 178 var index = list.dataModel.findIndexById(bookmarkNode.id); |
| 181 if (index != -1) { | 179 if (index != -1) { |
| 182 var sm = list.selectionModel; | 180 var sm = list.selectionModel; |
| 183 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; | 181 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; |
| 184 scrollIntoViewAndMakeEditable(index); | 182 scrollIntoViewAndMakeEditable(index); |
| 185 } | 183 } |
| 186 }; | 184 }; |
| 187 | 185 |
| 188 if (list.parentId == bookmarkNode.parentId) { | 186 navigateTo(bookmarkNode.parentId, editBookmark); |
| 189 // Clear the e= from the hash so that future attemps to edit the same | |
| 190 // entry will show up as a hash change. | |
| 191 updateHash(); | |
| 192 editBookmark(); | |
| 193 } else { | |
| 194 // Navigate to the parent folder (which will update the hash). Once | |
| 195 // it's loaded, edit the bookmark. | |
| 196 addOneShotEventListener(list, 'load', editBookmark); | |
| 197 updateParentId(bookmarkNode.parentId); | |
| 198 } | |
| 199 }); | 187 }); |
| 200 | 188 |
| 201 // We handle the two cases of navigating to the bookmark to be edited | 189 // We handle the two cases of navigating to the bookmark to be edited |
| 202 // above. Don't run the standard navigation code below. | 190 // above. Don't run the standard navigation code below. |
| 203 return; | 191 return; |
| 204 } else if (/^q=/.test(id)) { | 192 } else if (/^q=/.test(id)) { |
| 205 // In case we got a search hash, update the text input and the | 193 // In case we got a search hash, update the text input and the |
| 206 // bmm.treeLookup to use the new id. | 194 // bmm.treeLookup to use the new id. |
| 207 setSearch(id.slice(2)); | 195 setSearch(id.slice(2)); |
| 208 valid = true; | 196 valid = true; |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 264 if (searchText) { | 252 if (searchText) { |
| 265 tree.add(searchTreeItem); | 253 tree.add(searchTreeItem); |
| 266 tree.selectedItem = searchTreeItem; | 254 tree.selectedItem = searchTreeItem; |
| 267 } else { | 255 } else { |
| 268 // Go "home". | 256 // Go "home". |
| 269 tree.selectedItem = tree.items[0]; | 257 tree.selectedItem = tree.items[0]; |
| 270 id = tree.selectedItem.bookmarkId; | 258 id = tree.selectedItem.bookmarkId; |
| 271 } | 259 } |
| 272 | 260 |
| 273 // Navigate now and update hash immediately. | 261 // Navigate now and update hash immediately. |
| 274 navigateTo(id, true); | 262 navigateTo(id, updateHash); |
| 275 } | 263 } |
| 276 | 264 |
| 277 // Handle the logo button UI. | 265 // Handle the logo button UI. |
| 278 // When the user clicks the button we should navigate "home" and focus the list. | 266 // When the user clicks the button we should navigate "home" and focus the list. |
| 279 document.querySelector('button.logo').onclick = function(e) { | 267 document.querySelector('button.logo').onclick = function(e) { |
| 280 setSearch(''); | 268 setSearch(''); |
| 281 $('list').focus(); | 269 $('list').focus(); |
| 282 }; | 270 }; |
| 283 | 271 |
| 284 /** | 272 /** |
| (...skipping 1009 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1294 dataModel.splice(index, 1); | 1282 dataModel.splice(index, 1); |
| 1295 } | 1283 } |
| 1296 }); | 1284 }); |
| 1297 | 1285 |
| 1298 /** | 1286 /** |
| 1299 * Navigates to the folder that the selected item is in and selects it. This is | 1287 * Navigates to the folder that the selected item is in and selects it. This is |
| 1300 * used for the show-in-folder command. | 1288 * used for the show-in-folder command. |
| 1301 */ | 1289 */ |
| 1302 function showInFolder() { | 1290 function showInFolder() { |
| 1303 var bookmarkNode = list.selectedItem; | 1291 var bookmarkNode = list.selectedItem; |
| 1292 if (!bookmarkNode) |
| 1293 return; |
| 1304 var parentId = bookmarkNode.parentId; | 1294 var parentId = bookmarkNode.parentId; |
| 1305 | 1295 |
| 1306 // After the list is loaded we should select the revealed item. | 1296 // After the list is loaded we should select the revealed item. |
| 1307 function f(e) { | 1297 function selectItem() { |
| 1308 var index; | 1298 var index = list.dataModel.findIndexById(bookmarkNode.id); |
| 1309 if (bookmarkNode && | 1299 if (index == -1) |
| 1310 (index = list.dataModel.findIndexById(bookmarkNode.id)) != -1) { | 1300 return; |
| 1311 var sm = list.selectionModel; | 1301 var sm = list.selectionModel; |
| 1312 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; | 1302 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; |
| 1313 list.scrollIndexIntoView(index); | 1303 list.scrollIndexIntoView(index); |
| 1314 } | |
| 1315 list.removeEventListener('load', f); | |
| 1316 } | 1304 } |
| 1317 list.addEventListener('load', f); | 1305 |
| 1318 var treeItem = bmm.treeLookup[parentId]; | 1306 var treeItem = bmm.treeLookup[parentId]; |
| 1319 treeItem.reveal(); | 1307 treeItem.reveal(); |
| 1320 | 1308 |
| 1321 navigateTo(parentId); | 1309 navigateTo(parentId, selectItem); |
| 1322 } | 1310 } |
| 1323 | 1311 |
| 1324 var linkController; | 1312 var linkController; |
| 1325 | 1313 |
| 1326 /** | 1314 /** |
| 1327 * @return {!cr.LinkController} The link controller used to open links based on | 1315 * @return {!cr.LinkController} The link controller used to open links based on |
| 1328 * user clicks and keyboard actions. | 1316 * user clicks and keyboard actions. |
| 1329 */ | 1317 */ |
| 1330 function getLinkController() { | 1318 function getLinkController() { |
| 1331 return linkController || | 1319 return linkController || |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1402 }); | 1390 }); |
| 1403 } | 1391 } |
| 1404 | 1392 |
| 1405 /** | 1393 /** |
| 1406 * Opens an item in the list. | 1394 * Opens an item in the list. |
| 1407 */ | 1395 */ |
| 1408 function openItem() { | 1396 function openItem() { |
| 1409 var bookmarkNodes = getSelectedBookmarkNodes(); | 1397 var bookmarkNodes = getSelectedBookmarkNodes(); |
| 1410 // If we double clicked or pressed enter on a single folder, navigate to it. | 1398 // If we double clicked or pressed enter on a single folder, navigate to it. |
| 1411 if (bookmarkNodes.length == 1 && bmm.isFolder(bookmarkNodes[0])) { | 1399 if (bookmarkNodes.length == 1 && bmm.isFolder(bookmarkNodes[0])) { |
| 1412 navigateTo(bookmarkNodes[0].id); | 1400 navigateTo(bookmarkNodes[0].id, updateHash); |
| 1413 } else { | 1401 } else { |
| 1414 openBookmarks(LinkKind.FOREGROUND_TAB); | 1402 openBookmarks(LinkKind.FOREGROUND_TAB); |
| 1415 } | 1403 } |
| 1416 } | 1404 } |
| 1417 | 1405 |
| 1418 /** | 1406 /** |
| 1419 * Deletes the selected bookmarks. The bookmarks are saved in memory in case | 1407 * Deletes the selected bookmarks. The bookmarks are saved in memory in case |
| 1420 * the user needs to undo the deletion. | 1408 * the user needs to undo the deletion. |
| 1421 */ | 1409 */ |
| 1422 function deleteBookmarks() { | 1410 function deleteBookmarks() { |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1510 // Callback is called after tree and list data model updated. | 1498 // Callback is called after tree and list data model updated. |
| 1511 function createFolder(callback) { | 1499 function createFolder(callback) { |
| 1512 chrome.bookmarks.create({ | 1500 chrome.bookmarks.create({ |
| 1513 title: loadTimeData.getString('new_folder_name'), | 1501 title: loadTimeData.getString('new_folder_name'), |
| 1514 parentId: parentId | 1502 parentId: parentId |
| 1515 }, callback); | 1503 }, callback); |
| 1516 } | 1504 } |
| 1517 | 1505 |
| 1518 if (document.activeElement == tree) { | 1506 if (document.activeElement == tree) { |
| 1519 createFolder(function(newNode) { | 1507 createFolder(function(newNode) { |
| 1520 newItem = bmm.treeLookup[newNode.id]; | 1508 navigateTo(newNode.id, function() { |
| 1521 tree.selectedItem = newItem; | 1509 bmm.treeLookup[newNode.id].editing = true; |
| 1522 newItem.editing = true; | 1510 }); |
| 1523 }); | 1511 }); |
| 1524 return; | 1512 return; |
| 1525 } | 1513 } |
| 1526 | 1514 |
| 1527 function editNewFolderInList() { | 1515 function editNewFolderInList() { |
| 1528 createFolder(function() { | 1516 createFolder(function() { |
| 1529 var index = list.dataModel.length - 1; | 1517 var index = list.dataModel.length - 1; |
| 1530 var sm = list.selectionModel; | 1518 var sm = list.selectionModel; |
| 1531 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; | 1519 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = index; |
| 1532 scrollIntoViewAndMakeEditable(index); | 1520 scrollIntoViewAndMakeEditable(index); |
| 1533 }); | 1521 }); |
| 1534 } | 1522 } |
| 1535 | 1523 |
| 1536 if (parentId == list.parentId) { | 1524 navigateTo(parentId, editNewFolderInList); |
| 1537 editNewFolderInList(); | |
| 1538 return; | |
| 1539 } | |
| 1540 | |
| 1541 addOneShotEventListener(list, 'load', editNewFolderInList); | |
| 1542 navigateTo(parentId, true); | |
| 1543 } | 1525 } |
| 1544 | 1526 |
| 1545 /** | 1527 /** |
| 1546 * Scrolls the list item into view and makes it editable. | 1528 * Scrolls the list item into view and makes it editable. |
| 1547 * @param {number} index The index of the item to make editable. | 1529 * @param {number} index The index of the item to make editable. |
| 1548 */ | 1530 */ |
| 1549 function scrollIntoViewAndMakeEditable(index) { | 1531 function scrollIntoViewAndMakeEditable(index) { |
| 1550 list.scrollIndexIntoView(index); | 1532 list.scrollIndexIntoView(index); |
| 1551 // onscroll is now dispatched asynchronously so we have to postpone | 1533 // onscroll is now dispatched asynchronously so we have to postpone |
| 1552 // the rest. | 1534 // the rest. |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1572 id: 'new' | 1554 id: 'new' |
| 1573 }; | 1555 }; |
| 1574 var dataModel = list.dataModel; | 1556 var dataModel = list.dataModel; |
| 1575 var length = dataModel.length; | 1557 var length = dataModel.length; |
| 1576 dataModel.splice(length, 0, fakeNode); | 1558 dataModel.splice(length, 0, fakeNode); |
| 1577 var sm = list.selectionModel; | 1559 var sm = list.selectionModel; |
| 1578 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = length; | 1560 sm.anchorIndex = sm.leadIndex = sm.selectedIndex = length; |
| 1579 scrollIntoViewAndMakeEditable(length); | 1561 scrollIntoViewAndMakeEditable(length); |
| 1580 }; | 1562 }; |
| 1581 | 1563 |
| 1582 if (parentId == list.parentId) { | 1564 navigateTo(parentId, editNewBookmark); |
| 1583 editNewBookmark(); | |
| 1584 return; | |
| 1585 } | |
| 1586 | |
| 1587 addOneShotEventListener(list, 'load', editNewBookmark); | |
| 1588 navigateTo(parentId, true); | |
| 1589 } | 1565 } |
| 1590 | 1566 |
| 1591 /** | 1567 /** |
| 1592 * This function is used to select items after a user action such as paste, drop | 1568 * This function is used to select items after a user action such as paste, drop |
| 1593 * add page etc. | 1569 * add page etc. |
| 1594 * @param {BookmarkList|BookmarkTree} target The target of the user action. | 1570 * @param {BookmarkList|BookmarkTree} target The target of the user action. |
| 1595 * @param {=string} opt_selectedTreeId If provided, then select that tree id. | 1571 * @param {=string} opt_selectedTreeId If provided, then select that tree id. |
| 1596 */ | 1572 */ |
| 1597 function selectItemsAfterUserAction(target, opt_selectedTreeId) { | 1573 function selectItemsAfterUserAction(target, opt_selectedTreeId) { |
| 1598 // We get one onCreated event per item so we delay the handling until we get | 1574 // We get one onCreated event per item so we delay the handling until we get |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1745 document.addEventListener('copy', handle('copy-command')); | 1721 document.addEventListener('copy', handle('copy-command')); |
| 1746 document.addEventListener('cut', handle('cut-command')); | 1722 document.addEventListener('cut', handle('cut-command')); |
| 1747 | 1723 |
| 1748 var pasteHandler = handle('paste-command'); | 1724 var pasteHandler = handle('paste-command'); |
| 1749 document.addEventListener('paste', function(e) { | 1725 document.addEventListener('paste', function(e) { |
| 1750 // Paste is a bit special since we need to do an async call to see if we can | 1726 // Paste is a bit special since we need to do an async call to see if we can |
| 1751 // paste because the paste command might not be up to date. | 1727 // paste because the paste command might not be up to date. |
| 1752 updatePasteCommand(pasteHandler); | 1728 updatePasteCommand(pasteHandler); |
| 1753 }); | 1729 }); |
| 1754 })(); | 1730 })(); |
| OLD | NEW |