|
1 #ifdef 0 |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file, |
|
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 #endif |
|
6 |
|
7 /** |
|
8 * This singleton implements site dragging functionality. |
|
9 */ |
|
10 let gDrag = { |
|
11 /** |
|
12 * The site offset to the drag start point. |
|
13 */ |
|
14 _offsetX: null, |
|
15 _offsetY: null, |
|
16 |
|
17 /** |
|
18 * The site that is dragged. |
|
19 */ |
|
20 _draggedSite: null, |
|
21 get draggedSite() this._draggedSite, |
|
22 |
|
23 /** |
|
24 * The cell width/height at the point the drag started. |
|
25 */ |
|
26 _cellWidth: null, |
|
27 _cellHeight: null, |
|
28 get cellWidth() this._cellWidth, |
|
29 get cellHeight() this._cellHeight, |
|
30 |
|
31 /** |
|
32 * Start a new drag operation. |
|
33 * @param aSite The site that's being dragged. |
|
34 * @param aEvent The 'dragstart' event. |
|
35 */ |
|
36 start: function Drag_start(aSite, aEvent) { |
|
37 this._draggedSite = aSite; |
|
38 |
|
39 // Mark nodes as being dragged. |
|
40 let selector = ".newtab-site, .newtab-control, .newtab-thumbnail"; |
|
41 let parentCell = aSite.node.parentNode; |
|
42 let nodes = parentCell.querySelectorAll(selector); |
|
43 for (let i = 0; i < nodes.length; i++) |
|
44 nodes[i].setAttribute("dragged", "true"); |
|
45 |
|
46 parentCell.setAttribute("dragged", "true"); |
|
47 |
|
48 this._setDragData(aSite, aEvent); |
|
49 |
|
50 // Store the cursor offset. |
|
51 let node = aSite.node; |
|
52 let rect = node.getBoundingClientRect(); |
|
53 this._offsetX = aEvent.clientX - rect.left; |
|
54 this._offsetY = aEvent.clientY - rect.top; |
|
55 |
|
56 // Store the cell dimensions. |
|
57 let cellNode = aSite.cell.node; |
|
58 this._cellWidth = cellNode.offsetWidth; |
|
59 this._cellHeight = cellNode.offsetHeight; |
|
60 |
|
61 gTransformation.freezeSitePosition(aSite); |
|
62 }, |
|
63 |
|
64 /** |
|
65 * Handles the 'drag' event. |
|
66 * @param aSite The site that's being dragged. |
|
67 * @param aEvent The 'drag' event. |
|
68 */ |
|
69 drag: function Drag_drag(aSite, aEvent) { |
|
70 // Get the viewport size. |
|
71 let {clientWidth, clientHeight} = document.documentElement; |
|
72 |
|
73 // We'll want a padding of 5px. |
|
74 let border = 5; |
|
75 |
|
76 // Enforce minimum constraints to keep the drag image inside the window. |
|
77 let left = Math.max(scrollX + aEvent.clientX - this._offsetX, border); |
|
78 let top = Math.max(scrollY + aEvent.clientY - this._offsetY, border); |
|
79 |
|
80 // Enforce maximum constraints to keep the drag image inside the window. |
|
81 left = Math.min(left, scrollX + clientWidth - this.cellWidth - border); |
|
82 top = Math.min(top, scrollY + clientHeight - this.cellHeight - border); |
|
83 |
|
84 // Update the drag image's position. |
|
85 gTransformation.setSitePosition(aSite, {left: left, top: top}); |
|
86 }, |
|
87 |
|
88 /** |
|
89 * Ends the current drag operation. |
|
90 * @param aSite The site that's being dragged. |
|
91 * @param aEvent The 'dragend' event. |
|
92 */ |
|
93 end: function Drag_end(aSite, aEvent) { |
|
94 let nodes = gGrid.node.querySelectorAll("[dragged]") |
|
95 for (let i = 0; i < nodes.length; i++) |
|
96 nodes[i].removeAttribute("dragged"); |
|
97 |
|
98 // Slide the dragged site back into its cell (may be the old or the new cell). |
|
99 gTransformation.slideSiteTo(aSite, aSite.cell, {unfreeze: true}); |
|
100 |
|
101 this._draggedSite = null; |
|
102 }, |
|
103 |
|
104 /** |
|
105 * Checks whether we're responsible for a given drag event. |
|
106 * @param aEvent The drag event to check. |
|
107 * @return Whether we should handle this drag and drop operation. |
|
108 */ |
|
109 isValid: function Drag_isValid(aEvent) { |
|
110 let link = gDragDataHelper.getLinkFromDragEvent(aEvent); |
|
111 |
|
112 // Check that the drag data is non-empty. |
|
113 // Can happen when dragging places folders. |
|
114 if (!link || !link.url) { |
|
115 return false; |
|
116 } |
|
117 |
|
118 // Check that we're not accepting URLs which would inherit the caller's |
|
119 // principal (such as javascript: or data:). |
|
120 return gLinkChecker.checkLoadURI(link.url); |
|
121 }, |
|
122 |
|
123 /** |
|
124 * Initializes the drag data for the current drag operation. |
|
125 * @param aSite The site that's being dragged. |
|
126 * @param aEvent The 'dragstart' event. |
|
127 */ |
|
128 _setDragData: function Drag_setDragData(aSite, aEvent) { |
|
129 let {url, title} = aSite; |
|
130 |
|
131 let dt = aEvent.dataTransfer; |
|
132 dt.mozCursor = "default"; |
|
133 dt.effectAllowed = "move"; |
|
134 dt.setData("text/plain", url); |
|
135 dt.setData("text/uri-list", url); |
|
136 dt.setData("text/x-moz-url", url + "\n" + title); |
|
137 dt.setData("text/html", "<a href=\"" + url + "\">" + url + "</a>"); |
|
138 |
|
139 // Create and use an empty drag element. We don't want to use the default |
|
140 // drag image with its default opacity. |
|
141 let dragElement = document.createElementNS(HTML_NAMESPACE, "div"); |
|
142 dragElement.classList.add("newtab-drag"); |
|
143 let scrollbox = document.getElementById("newtab-scrollbox"); |
|
144 scrollbox.appendChild(dragElement); |
|
145 dt.setDragImage(dragElement, 0, 0); |
|
146 |
|
147 // After the 'dragstart' event has been processed we can remove the |
|
148 // temporary drag element from the DOM. |
|
149 setTimeout(function () scrollbox.removeChild(dragElement), 0); |
|
150 } |
|
151 }; |