| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 cr.define('dnd', function() { | 5 cr.define('dnd', function() { |
| 6 'use strict'; | 6 'use strict'; |
| 7 | 7 |
| 8 /** @const */ var BookmarkList = bmm.BookmarkList; | 8 /** @const */ var BookmarkList = bmm.BookmarkList; |
| 9 /** @const */ var ListItem = cr.ui.ListItem; | 9 /** @const */ var ListItem = cr.ui.ListItem; |
| 10 /** @const */ var TreeItem = cr.ui.TreeItem; | 10 /** @const */ var TreeItem = cr.ui.TreeItem; |
| 11 | 11 |
| 12 /** | 12 /** |
| 13 * Enumeration of valid drop locations relative to an element. These are | 13 * Enumeration of valid drop locations relative to an element. These are |
| 14 * bit masks to allow combining multiple locations in a single value. | 14 * bit masks to allow combining multiple locations in a single value. |
| 15 * @enum {number} | 15 * @enum {number} |
| 16 * @const | 16 * @const |
| 17 */ | 17 */ |
| 18 var DropPosition = { | 18 var DropPosition = {NONE: 0, ABOVE: 1, ON: 2, BELOW: 4}; |
| 19 NONE: 0, | |
| 20 ABOVE: 1, | |
| 21 ON: 2, | |
| 22 BELOW: 4 | |
| 23 }; | |
| 24 | 19 |
| 25 /** | 20 /** |
| 26 * @type {Object} Drop information calculated in |handleDragOver|. | 21 * @type {Object} Drop information calculated in |handleDragOver|. |
| 27 */ | 22 */ |
| 28 var dropDestination = null; | 23 var dropDestination = null; |
| 29 | 24 |
| 30 /** | 25 /** |
| 31 * @type {number} Timer id used to help minimize flicker. | 26 * @type {number} Timer id used to help minimize flicker. |
| 32 */ | 27 */ |
| 33 var removeDropIndicatorTimer; | 28 var removeDropIndicatorTimer; |
| 34 | 29 |
| 35 /** | 30 /** |
| 36 * The element currently targeted by a touch. | 31 * The element currently targeted by a touch. |
| 37 * @type {Element} | 32 * @type {Element} |
| 38 */ | 33 */ |
| 39 var currentTouchTarget; | 34 var currentTouchTarget; |
| 40 | 35 |
| 41 /** | 36 /** |
| 42 * The element that had a style applied it to indicate the drop location. | 37 * The element that had a style applied it to indicate the drop location. |
| 43 * This is used to easily remove the style when necessary. | 38 * This is used to easily remove the style when necessary. |
| 44 * @type {Element} | 39 * @type {Element} |
| 45 */ | 40 */ |
| 46 var lastIndicatorElement; | 41 var lastIndicatorElement; |
| 47 | 42 |
| 48 /** | 43 /** |
| 49 * The style that was applied to indicate the drop location. | 44 * The style that was applied to indicate the drop location. |
| 50 * @type {?string} | 45 * @type {?string} |
| 51 */ | 46 */ |
| 52 var lastIndicatorClassName; | 47 var lastIndicatorClassName; |
| 53 | 48 |
| 54 var dropIndicator = { | 49 var dropIndicator = { |
| 55 /** | 50 /** |
| 56 * Applies the drop indicator style on the target element and stores that | 51 * Applies the drop indicator style on the target element and stores that |
| 57 * information to easily remove the style in the future. | 52 * information to easily remove the style in the future. |
| 58 */ | 53 */ |
| 59 addDropIndicatorStyle: function(indicatorElement, position) { | 54 addDropIndicatorStyle: function(indicatorElement, position) { |
| 60 var indicatorStyleName = position == DropPosition.ABOVE ? 'drag-above' : | 55 var indicatorStyleName = position == DropPosition.ABOVE ? |
| 61 position == DropPosition.BELOW ? 'drag-below' : | 56 'drag-above' : |
| 62 'drag-on'; | 57 position == DropPosition.BELOW ? 'drag-below' : 'drag-on'; |
| 63 | 58 |
| 64 lastIndicatorElement = indicatorElement; | 59 lastIndicatorElement = indicatorElement; |
| 65 lastIndicatorClassName = indicatorStyleName; | 60 lastIndicatorClassName = indicatorStyleName; |
| 66 | 61 |
| 67 indicatorElement.classList.add(indicatorStyleName); | 62 indicatorElement.classList.add(indicatorStyleName); |
| 68 }, | 63 }, |
| 69 | 64 |
| 70 /** | 65 /** |
| 71 * Clears the drop indicator style from the last element was the drop target | 66 * Clears the drop indicator style from the last element was the drop target |
| 72 * so the drop indicator is no longer for that element. | 67 * so the drop indicator is no longer for that element. |
| 73 */ | 68 */ |
| 74 removeDropIndicatorStyle: function() { | 69 removeDropIndicatorStyle: function() { |
| 75 if (!lastIndicatorElement || !lastIndicatorClassName) | 70 if (!lastIndicatorElement || !lastIndicatorClassName) |
| 76 return; | 71 return; |
| 77 lastIndicatorElement.classList.remove(lastIndicatorClassName); | 72 lastIndicatorElement.classList.remove(lastIndicatorClassName); |
| 78 lastIndicatorElement = null; | 73 lastIndicatorElement = null; |
| 79 lastIndicatorClassName = null; | 74 lastIndicatorClassName = null; |
| 80 }, | 75 }, |
| 81 | 76 |
| 82 /** | 77 /** |
| 83 * Displays the drop indicator on the current drop target to give the | 78 * Displays the drop indicator on the current drop target to give the |
| 84 * user feedback on where the drop will occur. | 79 * user feedback on where the drop will occur. |
| 85 */ | 80 */ |
| 86 update: function(dropDest) { | 81 update: function(dropDest) { |
| 87 window.clearTimeout(removeDropIndicatorTimer); | 82 window.clearTimeout(removeDropIndicatorTimer); |
| 88 | 83 |
| 89 var indicatorElement = dropDest.element; | 84 var indicatorElement = dropDest.element; |
| 90 var position = dropDest.position; | 85 var position = dropDest.position; |
| 91 if (dropDest.element instanceof BookmarkList) { | 86 if (dropDest.element instanceof BookmarkList) { |
| 92 // For an empty bookmark list use 'drop-above' style. | 87 // For an empty bookmark list use 'drop-above' style. |
| 93 position = DropPosition.ABOVE; | 88 position = DropPosition.ABOVE; |
| 94 } else if (dropDest.element instanceof TreeItem) { | 89 } else if (dropDest.element instanceof TreeItem) { |
| 95 indicatorElement = indicatorElement.querySelector('.tree-row'); | 90 indicatorElement = indicatorElement.querySelector('.tree-row'); |
| 96 } | 91 } |
| 97 dropIndicator.removeDropIndicatorStyle(); | 92 dropIndicator.removeDropIndicatorStyle(); |
| 98 dropIndicator.addDropIndicatorStyle(indicatorElement, position); | 93 dropIndicator.addDropIndicatorStyle(indicatorElement, position); |
| 99 }, | 94 }, |
| 100 | 95 |
| 101 /** | 96 /** |
| 102 * Stop displaying the drop indicator. | 97 * Stop displaying the drop indicator. |
| 103 */ | 98 */ |
| 104 finish: function() { | 99 finish: function() { |
| 105 // The use of a timeout is in order to reduce flickering as we move | 100 // The use of a timeout is in order to reduce flickering as we move |
| 106 // between valid drop targets. | 101 // between valid drop targets. |
| 107 window.clearTimeout(removeDropIndicatorTimer); | 102 window.clearTimeout(removeDropIndicatorTimer); |
| 108 removeDropIndicatorTimer = window.setTimeout(function() { | 103 removeDropIndicatorTimer = window.setTimeout(function() { |
| 109 dropIndicator.removeDropIndicatorStyle(); | 104 dropIndicator.removeDropIndicatorStyle(); |
| 110 }, 100); | 105 }, 100); |
| 111 } | 106 } |
| 112 }; | 107 }; |
| 113 | 108 |
| 114 /** | 109 /** |
| 115 * Delay for expanding folder when pointer hovers on folder in tree view in | 110 * Delay for expanding folder when pointer hovers on folder in tree view in |
| 116 * milliseconds. | 111 * milliseconds. |
| 117 * @type {number} | 112 * @type {number} |
| 118 * @const | 113 * @const |
| 119 */ | 114 */ |
| 120 // TODO(yosin): EXPAND_FOLDER_DELAY should follow system settings. 400ms is | 115 // TODO(yosin): EXPAND_FOLDER_DELAY should follow system settings. 400ms is |
| 121 // taken from Windows default settings. | 116 // taken from Windows default settings. |
| 122 var EXPAND_FOLDER_DELAY = 400; | 117 var EXPAND_FOLDER_DELAY = 400; |
| 123 | 118 |
| 124 /** | 119 /** |
| 125 * The timestamp when the mouse was over a folder during a drag operation. | 120 * The timestamp when the mouse was over a folder during a drag operation. |
| 126 * Used to open the hovered folder after a certain time. | 121 * Used to open the hovered folder after a certain time. |
| 127 * @type {number} | 122 * @type {number} |
| 128 */ | 123 */ |
| 129 var lastHoverOnFolderTimeStamp = 0; | 124 var lastHoverOnFolderTimeStamp = 0; |
| 130 | 125 |
| 131 /** | 126 /** |
| 132 * Expand a folder if the user has hovered for longer than the specified | 127 * Expand a folder if the user has hovered for longer than the specified |
| 133 * time during a drag action. | 128 * time during a drag action. |
| 134 */ | 129 */ |
| 135 function updateAutoExpander(eventTimeStamp, overElement) { | 130 function updateAutoExpander(eventTimeStamp, overElement) { |
| 136 // Expands a folder in tree view when pointer hovers on it longer than | 131 // Expands a folder in tree view when pointer hovers on it longer than |
| 137 // EXPAND_FOLDER_DELAY. | 132 // EXPAND_FOLDER_DELAY. |
| 138 var hoverOnFolderTimeStamp = lastHoverOnFolderTimeStamp; | 133 var hoverOnFolderTimeStamp = lastHoverOnFolderTimeStamp; |
| 139 lastHoverOnFolderTimeStamp = 0; | 134 lastHoverOnFolderTimeStamp = 0; |
| 140 if (hoverOnFolderTimeStamp) { | 135 if (hoverOnFolderTimeStamp) { |
| 141 if (eventTimeStamp - hoverOnFolderTimeStamp >= EXPAND_FOLDER_DELAY) | 136 if (eventTimeStamp - hoverOnFolderTimeStamp >= EXPAND_FOLDER_DELAY) |
| 142 overElement.expanded = true; | 137 overElement.expanded = true; |
| 143 else | 138 else |
| 144 lastHoverOnFolderTimeStamp = hoverOnFolderTimeStamp; | 139 lastHoverOnFolderTimeStamp = hoverOnFolderTimeStamp; |
| 145 } else if (overElement instanceof TreeItem && | 140 } else if ( |
| 146 bmm.isFolder(overElement.bookmarkNode) && | 141 overElement instanceof TreeItem && |
| 147 overElement.hasChildren && | 142 bmm.isFolder(overElement.bookmarkNode) && overElement.hasChildren && |
| 148 !overElement.expanded) { | 143 !overElement.expanded) { |
| 149 lastHoverOnFolderTimeStamp = eventTimeStamp; | 144 lastHoverOnFolderTimeStamp = eventTimeStamp; |
| 150 } | 145 } |
| 151 } | 146 } |
| 152 | 147 |
| 153 /** | 148 /** |
| 154 * Stores the information about the bookmark and folders being dragged. | 149 * Stores the information about the bookmark and folders being dragged. |
| 155 * @type {Object} | 150 * @type {Object} |
| 156 */ | 151 */ |
| 157 var dragData = null; | 152 var dragData = null; |
| 158 var dragInfo = { | 153 var dragInfo = { |
| 159 handleChromeDragEnter: function(newDragData) { | 154 handleChromeDragEnter: function(newDragData) { |
| 160 dragData = newDragData; | 155 dragData = newDragData; |
| 161 }, | 156 }, |
| 162 clearDragData: function() { | 157 clearDragData: function() { |
| 163 dragData = null; | 158 dragData = null; |
| 164 }, | 159 }, |
| 165 isDragValid: function() { | 160 isDragValid: function() { |
| 166 return !!dragData; | 161 return !!dragData; |
| (...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 332 e.preventDefault(); | 327 e.preventDefault(); |
| 333 | 328 |
| 334 // Do not allow dragging if there is an ephemeral item being edited at the | 329 // Do not allow dragging if there is an ephemeral item being edited at the |
| 335 // moment. | 330 // moment. |
| 336 if (bmm.list.hasEphemeral()) | 331 if (bmm.list.hasEphemeral()) |
| 337 return; | 332 return; |
| 338 | 333 |
| 339 if (draggedNodes.length) { | 334 if (draggedNodes.length) { |
| 340 // If we are dragging a single link, we can do the *Link* effect. | 335 // If we are dragging a single link, we can do the *Link* effect. |
| 341 // Otherwise, we only allow copy and move. | 336 // Otherwise, we only allow copy and move. |
| 342 e.dataTransfer.effectAllowed = draggedNodes.length == 1 && | 337 e.dataTransfer.effectAllowed = |
| 343 !bmm.isFolder(draggedNodes[0]) ? 'copyMoveLink' : 'copyMove'; | 338 draggedNodes.length == 1 && !bmm.isFolder(draggedNodes[0]) ? |
| 339 'copyMoveLink' : |
| 340 'copyMove'; |
| 344 | 341 |
| 345 chrome.bookmarkManagerPrivate.startDrag(draggedNodes.map(function(node) { | 342 chrome.bookmarkManagerPrivate.startDrag( |
| 346 return node.id; | 343 draggedNodes.map(function(node) { |
| 347 }), isFromTouch); | 344 return node.id; |
| 345 }), |
| 346 isFromTouch); |
| 348 var dragTarget = getBookmarkElement(e.target); | 347 var dragTarget = getBookmarkElement(e.target); |
| 349 if (dragTarget instanceof ListItem || | 348 if (dragTarget instanceof ListItem || |
| 350 dragTarget instanceof BookmarkList) { | 349 dragTarget instanceof BookmarkList) { |
| 351 chrome.metricsPrivate.recordUserAction( | 350 chrome.metricsPrivate.recordUserAction( |
| 352 'BookmarkManager_StartDragFromList'); | 351 'BookmarkManager_StartDragFromList'); |
| 353 } else if (dragTarget instanceof TreeItem) { | 352 } else if (dragTarget instanceof TreeItem) { |
| 354 chrome.metricsPrivate.recordUserAction( | 353 chrome.metricsPrivate.recordUserAction( |
| 355 'BookmarkManager_StartDragFromTree'); | 354 'BookmarkManager_StartDragFromTree'); |
| 356 } | 355 } |
| 357 | 356 |
| (...skipping 18 matching lines...) Expand all Loading... |
| 376 e.preventDefault(); | 375 e.preventDefault(); |
| 377 | 376 |
| 378 // Set to none. This will get set to something if we can do the drop. | 377 // Set to none. This will get set to something if we can do the drop. |
| 379 e.dataTransfer.dropEffect = 'none'; | 378 e.dataTransfer.dropEffect = 'none'; |
| 380 } | 379 } |
| 381 | 380 |
| 382 if (!dragInfo.isDragValid()) | 381 if (!dragInfo.isDragValid()) |
| 383 return; | 382 return; |
| 384 | 383 |
| 385 var overElement = getBookmarkElement(e.target) || | 384 var overElement = getBookmarkElement(e.target) || |
| 386 (e.target == bmm.list ? bmm.list : null); | 385 (e.target == bmm.list ? bmm.list : null); |
| 387 if (!overElement) | 386 if (!overElement) |
| 388 return; | 387 return; |
| 389 | 388 |
| 390 updateAutoExpander(e.timeStamp, overElement); | 389 updateAutoExpander(e.timeStamp, overElement); |
| 391 | 390 |
| 392 var canDropInfo = calculateValidDropTargets(overElement); | 391 var canDropInfo = calculateValidDropTargets(overElement); |
| 393 if (canDropInfo == DropPosition.NONE) | 392 if (canDropInfo == DropPosition.NONE) |
| 394 return; | 393 return; |
| 395 | 394 |
| 396 // Now we know that we can drop. Determine if we will drop above, on or | 395 // Now we know that we can drop. Determine if we will drop above, on or |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 return null; | 440 return null; |
| 442 } | 441 } |
| 443 | 442 |
| 444 function calculateDropInfo(eventTarget, dropDestination) { | 443 function calculateDropInfo(eventTarget, dropDestination) { |
| 445 if (!dropDestination || !dragInfo.isDragValid()) | 444 if (!dropDestination || !dragInfo.isDragValid()) |
| 446 return null; | 445 return null; |
| 447 | 446 |
| 448 var dropPos = dropDestination.position; | 447 var dropPos = dropDestination.position; |
| 449 var relatedNode = dropDestination.element.bookmarkNode; | 448 var relatedNode = dropDestination.element.bookmarkNode; |
| 450 var dropInfoResult = { | 449 var dropInfoResult = { |
| 451 selectTarget: null, | 450 selectTarget: null, |
| 452 selectedTreeId: -1, | 451 selectedTreeId: -1, |
| 453 parentId: dropPos == DropPosition.ON ? relatedNode.id : | 452 parentId: dropPos == DropPosition.ON ? relatedNode.id : |
| 454 relatedNode.parentId, | 453 relatedNode.parentId, |
| 455 index: -1, | 454 index: -1, |
| 456 relatedIndex: -1 | 455 relatedIndex: -1 |
| 457 }; | 456 }; |
| 458 | 457 |
| 459 // Try to find the index in the dataModel so we don't have to always keep | 458 // Try to find the index in the dataModel so we don't have to always keep |
| 460 // the index for the list items up to date. | 459 // the index for the list items up to date. |
| 461 var overElement = getBookmarkElement(eventTarget); | 460 var overElement = getBookmarkElement(eventTarget); |
| 462 if (overElement instanceof ListItem) { | 461 if (overElement instanceof ListItem) { |
| 463 dropInfoResult.relatedIndex = | 462 dropInfoResult.relatedIndex = |
| 464 overElement.parentNode.dataModel.indexOf(relatedNode); | 463 overElement.parentNode.dataModel.indexOf(relatedNode); |
| 465 dropInfoResult.selectTarget = bmm.list; | 464 dropInfoResult.selectTarget = bmm.list; |
| 466 } else if (overElement instanceof BookmarkList) { | 465 } else if (overElement instanceof BookmarkList) { |
| 467 dropInfoResult.relatedIndex = overElement.dataModel.length - 1; | 466 dropInfoResult.relatedIndex = overElement.dataModel.length - 1; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 482 return dropInfoResult; | 481 return dropInfoResult; |
| 483 } | 482 } |
| 484 | 483 |
| 485 function handleDragLeave(e) { | 484 function handleDragLeave(e) { |
| 486 dropIndicator.finish(); | 485 dropIndicator.finish(); |
| 487 } | 486 } |
| 488 | 487 |
| 489 function handleDrop(e) { | 488 function handleDrop(e) { |
| 490 var dropInfo = calculateDropInfo(e.target, dropDestination); | 489 var dropInfo = calculateDropInfo(e.target, dropDestination); |
| 491 if (dropInfo) { | 490 if (dropInfo) { |
| 492 selectItemsAfterUserAction(dropInfo.selectTarget, | 491 selectItemsAfterUserAction( |
| 493 dropInfo.selectedTreeId); | 492 dropInfo.selectTarget, dropInfo.selectedTreeId); |
| 494 if (dropInfo.index != -1) | 493 if (dropInfo.index != -1) |
| 495 chrome.bookmarkManagerPrivate.drop(dropInfo.parentId, dropInfo.index); | 494 chrome.bookmarkManagerPrivate.drop(dropInfo.parentId, dropInfo.index); |
| 496 else | 495 else |
| 497 chrome.bookmarkManagerPrivate.drop(dropInfo.parentId); | 496 chrome.bookmarkManagerPrivate.drop(dropInfo.parentId); |
| 498 | 497 |
| 499 e.preventDefault(); | 498 e.preventDefault(); |
| 500 | 499 |
| 501 var dragTarget = getBookmarkElement(e.target); | 500 var dragTarget = getBookmarkElement(e.target); |
| 502 var action; | 501 var action; |
| 503 if (dragTarget instanceof ListItem || | 502 if (dragTarget instanceof ListItem || |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 552 document.addEventListener('touchend', clearCurrentTouchTarget); | 551 document.addEventListener('touchend', clearCurrentTouchTarget); |
| 553 document.addEventListener('touchstart', setCurrentTouchTarget); | 552 document.addEventListener('touchstart', setCurrentTouchTarget); |
| 554 | 553 |
| 555 chrome.bookmarkManagerPrivate.onDragEnter.addListener( | 554 chrome.bookmarkManagerPrivate.onDragEnter.addListener( |
| 556 dragInfo.handleChromeDragEnter); | 555 dragInfo.handleChromeDragEnter); |
| 557 chrome.bookmarkManagerPrivate.onDragLeave.addListener(deferredClearData); | 556 chrome.bookmarkManagerPrivate.onDragLeave.addListener(deferredClearData); |
| 558 chrome.bookmarkManagerPrivate.onDrop.addListener(deferredClearData); | 557 chrome.bookmarkManagerPrivate.onDrop.addListener(deferredClearData); |
| 559 } | 558 } |
| 560 return {init: init}; | 559 return {init: init}; |
| 561 }); | 560 }); |
| OLD | NEW |