Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: lib/child/selection.js

Issue 29363476: Issue 2879 - Move element selection into the content process (Closed) Base URL: https://hg.adblockplus.org/elemhidehelper
Patch Set: Created Nov. 17, 2016, 1:17 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld