Left: | ||
Right: |
OLD | NEW |
---|---|
(Empty) | |
1 /* | |
saroyanm
2016/11/23 17:44:39
I thought that this code belongs to Aardvark ?
Wha
Wladimir Palant
2016/11/24 14:02:01
Yes, E10S is the reason for this whole change. Any
| |
2 * This Source Code is subject to the terms of the Mozilla Public License | |
3 * version 2.0 (the "License"). You can obtain a copy of the License at | |
4 * http://mozilla.org/MPL/2.0/. | |
5 */ | |
6 | |
7 "use strict"; | |
8 | |
9 let {Services} = Cu.import("resource://gre/modules/Services.jsm", {}); | |
10 | |
11 let messageManager = require("messageManager"); | |
12 let { | |
13 createElement, getWindowSize, getParentElement, getElementPosition | |
14 } = require("./utils"); | |
15 | |
16 let state = exports.state = {}; | |
Wladimir Palant
2016/11/17 13:54:48
Original code was storing the selection state as p
saroyanm
2016/11/23 17:44:39
We are setting the properties of state in other fu
Wladimir Palant
2016/11/24 14:02:02
Setting them here doesn't make sense - the definit
| |
17 | |
18 messageManager.addMessageListener("ElemHideHelper:StartSelection", startSelectio n); | |
19 | |
20 onShutdown.add(() => | |
21 { | |
22 messageManager.removeMessageListener("ElemHideHelper:StartSelection", startSel ection); | |
23 | |
24 stopSelection(); | |
25 }); | |
26 | |
27 function startSelection(message) | |
28 { | |
29 stopSelection(); | |
30 | |
31 let outerWindowID = message.data; | |
32 let wnd = Services.wm.getOuterWindowWithId(outerWindowID); | |
33 if (!wnd || !canSelect(wnd)) | |
34 return; | |
35 | |
36 state.window = wnd; | |
37 state.id = outerWindowID; | |
38 | |
39 wnd.addEventListener("click", onMouseClick, true); | |
40 wnd.addEventListener("wheel", onMouseScroll, true); | |
saroyanm
2016/11/23 17:44:39
It's a deprecated event:
https://developer.mozilla
Wladimir Palant
2016/11/24 14:02:02
That page is about the mousewheel event, not wheel
| |
41 wnd.addEventListener("mousemove", onMouseMove, true); | |
42 wnd.addEventListener("pagehide", onPageHide, true); | |
43 | |
44 wnd.focus(); | |
45 | |
46 let doc = wnd.document; | |
47 let {elementMarkerClass} = require("info"); | |
48 state.boxElement = createElement(doc, "div", {"class": elementMarkerClass}, [ | |
49 createElement(doc, "div", {"class": "ehh-border"}), | |
50 createElement(doc, "div", {"class": "ehh-label"}, [ | |
51 createElement(doc, "span", {"class": "ehh-labelTag"}), | |
52 createElement(doc, "span", {"class": "ehh-labelAddition"}) | |
53 ]) | |
54 ]); | |
55 | |
56 // Make sure to select some element immeditely (whichever is in the center of the browser window) | |
57 let [wndWidth, wndHeight] = getWindowSize(wnd); | |
58 state.isUserSelected = false; | |
59 onMouseMove({clientX: wndWidth / 2, clientY: wndHeight / 2, screenX: -1, scree nY: -1, target: null}); | |
60 | |
61 messageManager.sendAsyncMessage("ElemHideHelper:SelectionStarted"); | |
62 } | |
63 | |
64 function stopSelection() | |
65 { | |
66 if (!state.boxElement) | |
67 return; | |
68 | |
69 hideSelection(); | |
70 | |
71 let wnd = state.window; | |
72 wnd.removeEventListener("click", onMouseClick, true); | |
73 wnd.removeEventListener("wheel", onMouseScroll, true); | |
74 wnd.removeEventListener("mousemove", onMouseMove, true); | |
75 wnd.removeEventListener("pagehide", onPageHide, true); | |
76 | |
77 for (let key of Object.keys(state)) | |
78 delete state[key]; | |
79 | |
80 messageManager.sendAsyncMessage("ElemHideHelper:SelectionStopped"); | |
81 } | |
82 exports.stopSelection = stopSelection; | |
83 | |
84 function canSelect(wnd) | |
85 { | |
86 let acceptlocalfiles; | |
saroyanm
2016/11/23 17:44:39
Nit: camelCase is missing
Wladimir Palant
2016/11/24 14:02:02
Done.
| |
87 try | |
88 { | |
89 acceptlocalfiles = Services.prefs.getBoolPref("extensions.elemhidehelper.acc eptlocalfiles"); | |
saroyanm
2016/11/23 17:44:39
Nit: exceeding 80 chars.
Wladimir Palant
2016/11/24 14:02:01
Done.
| |
90 } | |
91 catch (e) | |
92 { | |
93 acceptlocalfiles = false; | |
94 } | |
95 | |
96 if (!acceptlocalfiles) | |
97 { | |
98 let localSchemes; | |
99 try | |
100 { | |
101 localSchemes = new Set( | |
102 Services.prefs.getCharPref("extensions.adblockplus.whitelistschemes") | |
103 .split(/\s+/) | |
104 ); | |
Wladimir Palant
2016/11/17 13:54:48
This changes the original logic which was simply h
| |
105 } | |
106 catch (e) | |
107 { | |
108 localSchemes = new Set(); | |
109 } | |
110 | |
111 if (localSchemes.has(wnd.location.protocol.replace(/:$/, ""))) | |
112 return false; | |
113 } | |
114 | |
115 return true; | |
116 } | |
117 | |
118 function getElementLabel(elem) | |
119 { | |
120 let tagName = elem.localName; | |
saroyanm
2016/11/23 17:44:39
localName is a deprecated property:
https://develo
Wladimir Palant
2016/11/24 14:02:02
That would have been surprising - the docs say tha
| |
121 let addition = ""; | |
122 if (elem.id != "") | |
123 addition += ", id: " + elem.id; | |
124 if (elem.className != "") | |
125 addition += ", class: " + elem.className; | |
126 if (elem.style.cssText != "") | |
127 addition += ", style: " + elem.style.cssText; | |
saroyanm
2016/11/23 17:44:39
Weak suggestion: What about mentioning that it's n
Wladimir Palant
2016/11/24 14:02:02
Hasn't lead to any confusion so far, we can just a
| |
128 | |
129 return [tagName, addition]; | |
130 } | |
131 | |
132 function setAnchorElement(anchor) | |
saroyanm
2016/11/23 17:44:39
What is the anchor element ? I assume it's not rel
Wladimir Palant
2016/11/24 14:02:01
Nope. I've documented the state properties now, sh
| |
133 { | |
134 state.anchorElement = anchor; | |
135 | |
136 let newSelection = anchor; | |
137 if (state.isUserSelected) | |
138 { | |
139 // User chose an element via wider/narrower commands, keep the selection if | |
140 // our new anchor is still a child of that element | |
141 let e = newSelection; | |
142 while (e && e != state.selectedElement) | |
143 e = getParentElement(e); | |
144 | |
145 if (e) | |
146 newSelection = state.selectedElement; | |
147 else | |
148 state.isUserSelected = false; | |
149 } | |
150 | |
151 selectElement(newSelection); | |
152 } | |
153 exports.setAnchorElement = setAnchorElement; | |
154 | |
155 function selectElement(elem) | |
156 { | |
157 state.selectedElement = elem; | |
158 state.prevSelectionUpdate = Date.now(); | |
159 | |
160 let border = state.boxElement.querySelector(".ehh-border"); | |
161 let label = state.boxElement.querySelector(".ehh-label"); | |
162 let labelTag = state.boxElement.querySelector(".ehh-labelTag"); | |
163 let labelAddition = state.boxElement.querySelector(".ehh-labelAddition"); | |
164 | |
165 let doc = state.window.document; | |
166 let [wndWidth, wndHeight] = getWindowSize(state.window); | |
167 | |
168 let pos = getElementPosition(elem); | |
169 state.boxElement.style.left = Math.min(pos.left - 1, wndWidth - 2) + "px"; | |
saroyanm
2016/11/23 17:44:38
Is this approach even working with RTL websites ?
Wladimir Palant
2016/11/24 14:02:01
Well, it works with RTL websites. Our UI is always
saroyanm
2016/11/25 16:18:13
Here you go: #4665
| |
170 state.boxElement.style.top = Math.min(pos.top - 1, wndHeight - 2) + "px"; | |
171 border.style.width = Math.max(pos.right - pos.left - 2, 0) + "px"; | |
172 border.style.height = Math.max(pos.bottom - pos.top - 2, 0) + "px"; | |
173 | |
174 [labelTag.textContent, labelAddition.textContent] = getElementLabel(elem); | |
175 | |
176 // If there is not enough space to show the label move it up a little | |
177 if (pos.bottom < wndHeight - 25) | |
178 label.className = "ehh-label"; | |
179 else | |
180 label.className = "ehh-label onTop"; | |
181 | |
182 doc.documentElement.appendChild(state.boxElement); | |
183 | |
184 state.prevPos = pos; | |
185 state.window.addEventListener("MozAfterPaint", onAfterPaint, false); | |
186 } | |
187 exports.selectElement = selectElement; | |
188 | |
189 function hideSelection() | |
190 { | |
191 if (!Cu.isDeadWrapper(state.boxElement) && state.boxElement.parentNode) | |
192 state.boxElement.parentNode.removeChild(state.boxElement); | |
193 | |
194 if (!Cu.isDeadWrapper(state.window)) | |
195 state.window.removeEventListener("MozAfterPaint", onAfterPaint, false); | |
196 } | |
197 | |
198 /****************** | |
199 * Event handlers * | |
200 ******************/ | |
201 | |
202 function onMouseClick(event) | |
203 { | |
204 if (event.button != 0 || event.shiftKey || event.altKey || event.ctrlKey || ev ent.metaKey) | |
205 return; | |
206 | |
207 require("./commands").select(); | |
208 event.preventDefault(); | |
209 } | |
210 | |
211 function onMouseScroll(event) | |
212 { | |
213 if (!event.shiftKey || event.altKey || event.ctrlKey || event.metaKey) | |
214 return; | |
215 | |
216 let delta = event.deltaY || event.deltaX; | |
Wladimir Palant
2016/11/17 13:54:48
This was dead code originally, using DOMMouseScrol
saroyanm
2016/11/23 17:44:38
Acknowledged.
| |
217 if (!delta) | |
218 return; | |
219 | |
220 let commands = require("./commands"); | |
saroyanm
2016/11/23 17:44:38
Detail: we already loading the module in onMouseCl
Wladimir Palant
2016/11/24 14:02:01
That would create a circular reference.
| |
221 if (delta > 0) | |
222 commands.wider(); | |
223 else | |
224 commands.narrower(); | |
225 event.preventDefault(); | |
226 } | |
227 | |
228 function onMouseMove(event) | |
229 { | |
230 hideSelection(); | |
231 | |
232 let x = event.clientX; | |
233 let y = event.clientY; | |
234 | |
235 // We might have coordinates relative to a frame, recalculate relative to top window | |
236 let node = event.target; | |
237 while (node && node.ownerDocument && node.ownerDocument.defaultView && node.ow nerDocument.defaultView.frameElement) | |
238 { | |
239 node = node.ownerDocument.defaultView.frameElement; | |
240 let rect = node.getBoundingClientRect(); | |
241 x += rect.left; | |
242 y += rect.top; | |
243 } | |
244 | |
245 // Get the element matching the coordinates, probably within a frame | |
246 let elem = state.window.document.elementFromPoint(x, y); | |
247 while (elem && "contentWindow" in elem && canSelect(elem.contentWindow)) | |
248 { | |
249 let rect = elem.getBoundingClientRect(); | |
250 x -= rect.left; | |
251 y -= rect.top; | |
252 elem = elem.contentWindow.document.elementFromPoint(x, y); | |
253 } | |
254 | |
255 if (elem) | |
256 { | |
257 if (!state.lockedAnchor) | |
258 setAnchorElement(elem); | |
259 else | |
260 { | |
261 state.lockedAnchor = elem; | |
262 selectElement(state.selectedElement); | |
263 } | |
264 } | |
265 } | |
266 | |
267 function onPageHide(event) | |
268 { | |
269 stopSelection(); | |
270 } | |
271 | |
272 function onAfterPaint(event) | |
Wladimir Palant
2016/11/17 13:54:48
This code path is untested, I'm not sure whether i
saroyanm
2016/11/23 17:44:39
We do have "onMouseScroll" function, I thought it
Wladimir Palant
2016/11/24 14:02:02
Given that the purpose of this function is selecti
| |
273 { | |
274 // Don't update position too often | |
275 if (state.selectedElement && Date.now() - state.prevSelectionUpdate > 20) | |
276 { | |
277 let pos = getElementPosition(state.selectedElement); | |
278 if (!state.prevPos || state.prevPos.left != pos.left || | |
279 state.prevPos.right != pos.right || state.prevPos.top != pos.top || | |
280 state.prevPos.bottom != pos.bottom) | |
281 { | |
282 selectElement(state.selectedElement); | |
283 } | |
284 } | |
285 } | |
OLD | NEW |