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 |