Adrià Vilanova MartÃnez | f19ea43 | 2024-01-23 20:20:52 +0100 | [diff] [blame] | 1 | // Copyright 2016 The Chromium Authors |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
Copybara | 854996b | 2021-09-07 19:36:02 +0000 | [diff] [blame] | 4 | |
| 5 | /** |
| 6 | * Functions used by Monorail to control drag-and-drop re-orderable lists |
| 7 | * |
| 8 | */ |
| 9 | |
| 10 | /** |
| 11 | * Initializes the drag-and-drop functionality on the elements of a |
| 12 | * container node. |
| 13 | * TODO(lukasperaza): allow bulk drag-and-drop |
| 14 | * @param {Element} container The HTML container element to turn into |
| 15 | * a drag-and-drop list. The items of the list must have the |
| 16 | * class 'drag_item' |
| 17 | */ |
| 18 | function TKR_initDragAndDrop(container, opt_onDrop, opt_preventMultiple) { |
| 19 | let dragSrc = null; |
| 20 | let dragLocation = null; |
| 21 | let dragItems = container.getElementsByClassName('drag_item'); |
| 22 | let target = null; |
| 23 | |
| 24 | opt_preventMultiple = opt_preventMultiple || false; |
| 25 | opt_onDrop = opt_onDrop || function() {}; |
| 26 | |
| 27 | function _handleMouseDown(event) { |
| 28 | target = event.target; |
| 29 | } |
| 30 | |
| 31 | function _handleDragStart(event) { |
| 32 | let el = event.currentTarget; |
| 33 | let gripper = el.getElementsByClassName('gripper'); |
| 34 | if (gripper.length && !gripper[0].contains(target)) { |
| 35 | event.preventDefault(); |
| 36 | return; |
| 37 | } |
| 38 | el.style.opacity = 0.4; |
| 39 | event.dataTransfer.setData('text/html', el.outerHTML); |
| 40 | event.dataTransfer.dropEffect = 'move'; |
| 41 | dragSrc = el; |
| 42 | } |
| 43 | |
| 44 | function inRect(rect, x, y) { |
| 45 | if (x < rect.left || x > rect.right) { |
| 46 | return ''; |
| 47 | } else if (rect.top <= y && y <= rect.top + rect.height / 2) { |
| 48 | return 'top'; |
| 49 | } else { |
| 50 | return 'bottom'; |
| 51 | } |
| 52 | } |
| 53 | |
| 54 | function _handleDragOver(event) { |
| 55 | if (dragSrc == null) { |
| 56 | return true; |
| 57 | } |
| 58 | event.preventDefault(); |
| 59 | let el = event.currentTarget; |
| 60 | let rect = el.getBoundingClientRect(), |
| 61 | classes = el.classList; |
| 62 | let section = inRect(rect, event.clientX, event.clientY); |
| 63 | if (section == 'top' && !classes.contains('top')) { |
| 64 | dragLocation = 'top'; |
| 65 | classes.remove('bottom'); |
| 66 | classes.add('top'); |
| 67 | } else if (section == 'bottom' && !classes.contains('bottom')) { |
| 68 | dragLocation = 'bottom'; |
| 69 | classes.remove('top'); |
| 70 | classes.add('bottom'); |
| 71 | } |
| 72 | return false; |
| 73 | } |
| 74 | |
| 75 | function removeClasses(el) { |
| 76 | el.classList.remove('top'); |
| 77 | el.classList.remove('bottom'); |
| 78 | } |
| 79 | |
| 80 | function _handleDragDrop(event) { |
| 81 | let el = event.currentTarget; |
| 82 | if (dragSrc == null || el == dragSrc) { |
| 83 | return true; |
| 84 | } |
| 85 | |
| 86 | if (opt_preventMultiple) { |
| 87 | let dragItems = container.getElementsByClassName('drag_item'); |
| 88 | for (let i = 0; i < dragItems.length; i++) { |
| 89 | dragItems[i].setAttribute('draggable', false); |
| 90 | } |
| 91 | } |
| 92 | |
| 93 | let srcID = dragSrc.getAttribute('data-id'); |
| 94 | let id = el.getAttribute('data-id'); |
| 95 | |
| 96 | if (dragLocation == 'top') { |
| 97 | el.parentNode.insertBefore(dragSrc, el); |
| 98 | opt_onDrop(srcID, id, 'above'); |
| 99 | } else if (dragLocation == 'bottom') { |
| 100 | el.parentNode.insertBefore(dragSrc, el.nextSibling); |
| 101 | opt_onDrop(srcID, id, 'below'); |
| 102 | } |
| 103 | dragSrc.style.opacity = 0.4; |
| 104 | dragSrc = null; |
| 105 | } |
| 106 | |
| 107 | function _handleDragEnd(event) { |
| 108 | if (dragSrc) { |
| 109 | dragSrc.style.opacity = 1; |
| 110 | dragSrc = null; |
| 111 | } |
| 112 | for (let i = 0; i < dragItems.length; i++) { |
| 113 | removeClasses(dragItems[i]); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | for (let i = 0; i < dragItems.length; i++) { |
| 118 | let el = dragItems[i]; |
| 119 | el.setAttribute('draggable', true); |
| 120 | el.addEventListener('mousedown', _handleMouseDown); |
| 121 | el.addEventListener('dragstart', _handleDragStart); |
| 122 | el.addEventListener('dragover', _handleDragOver); |
| 123 | el.addEventListener('drop', _handleDragDrop); |
| 124 | el.addEventListener('dragend', _handleDragEnd); |
| 125 | el.addEventListener('dragleave', function(event) { |
| 126 | removeClasses(event.currentTarget); |
| 127 | }); |
| 128 | } |
| 129 | } |