Merge lp:~osomon/webbrowser-app/blacklist-selection into lp:webbrowser-app
- blacklist-selection
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Olivier Tilloy |
Approved revision: | 451 |
Merged at revision: | 451 |
Proposed branch: | lp:~osomon/webbrowser-app/blacklist-selection |
Merge into: | lp:webbrowser-app |
Diff against target: |
348 lines (+175/-160) 1 file modified
src/Ubuntu/Components/Extras/Browser/selection.js (+175/-160) |
To merge this branch: | bzr merge lp:~osomon/webbrowser-app/blacklist-selection |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandre Abreu (community) | Approve | ||
PS Jenkins bot | continuous-integration | Approve | |
Review via email: mp+206747@code.launchpad.net |
Commit message
Do not install the selection event handlers on certain domains known to interfere with touch events.
Description of the change
Olivier Tilloy (osomon) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:451
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Chris Wayne (cwayne) wrote : | # |
I've just tested this and verified that it fixed the issue!
Alexandre Abreu (abreu-alexandre) : | # |
Gustavo Pichorim Boiko (boiko) wrote : | # |
As a formality before the MR enters the CI train, could the reviewer (in this case Chris) please go through the MP Review Checklist (https:/
Gustavo Pichorim Boiko (boiko) wrote : | # |
> As a formality before the MR enters the CI train, could the reviewer (in this
> case Chris) please go through the MP Review Checklist
> (https:/
> questions in a comment on the MR?
Oups, I just noticed it was not Chris who approved the MR, it was Alexandre, so if he could please go through that, it would be nice.
Alexandre Abreu (abreu-alexandre) wrote : | # |
Did you perform an exploratory manual test run of the code change and any related functionality on device or emulator? YES
Did you successfully run all tests found in your component's Test Plan (https:/
Did CI run pass? If not, please explain why. YES
Have you checked that submitter has accurately filled out the submitter checklist and has taken no shortcut? YES
- 452. By Olivier Tilloy
-
Let the selection handler listen to 'touchcancel' events for completeness.
Preview Diff
1 | === modified file 'src/Ubuntu/Components/Extras/Browser/selection.js' |
2 | --- src/Ubuntu/Components/Extras/Browser/selection.js 2013-10-10 12:02:43 +0000 |
3 | +++ src/Ubuntu/Components/Extras/Browser/selection.js 2014-02-19 15:54:03 +0000 |
4 | @@ -1,5 +1,5 @@ |
5 | /* |
6 | - * Copyright 2013 Canonical Ltd. |
7 | + * Copyright 2013-2014 Canonical Ltd. |
8 | * |
9 | * This file is part of webbrowser-app. |
10 | * |
11 | @@ -16,163 +16,178 @@ |
12 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
13 | */ |
14 | |
15 | -function elementContainedInBox(element, box) { |
16 | - var rect = element.getBoundingClientRect(); |
17 | - return ((box.left <= rect.left) && (box.right >= rect.right) && |
18 | - (box.top <= rect.top) && (box.bottom >= rect.bottom)); |
19 | -} |
20 | - |
21 | -function getImgFullUri(uri) { |
22 | - if ((uri.slice(0, 7) === 'http://') || |
23 | - (uri.slice(0, 8) === 'https://') || |
24 | - (uri.slice(0, 7) === 'file://')) { |
25 | - return uri; |
26 | - } else if (uri.slice(0, 1) === '/') { |
27 | - var docuri = document.documentURI; |
28 | - var firstcolon = docuri.indexOf('://'); |
29 | - var protocol = 'http://'; |
30 | - if (firstcolon !== -1) { |
31 | - protocol = docuri.slice(0, firstcolon + 3); |
32 | - } |
33 | - return protocol + document.domain + uri; |
34 | - } else { |
35 | - var base = document.baseURI; |
36 | - var lastslash = base.lastIndexOf('/'); |
37 | - if (lastslash === -1) { |
38 | - return base + '/' + uri; |
39 | +// List of domains known to interfere with touch events listeners |
40 | +var blacklist = [ |
41 | + "m.8tracks.com", // http://pad.lv/1279903 |
42 | +]; |
43 | +if (blacklist.indexOf(document.domain) === -1) { |
44 | + |
45 | + function elementContainedInBox(element, box) { |
46 | + var rect = element.getBoundingClientRect(); |
47 | + return ((box.left <= rect.left) && (box.right >= rect.right) && |
48 | + (box.top <= rect.top) && (box.bottom >= rect.bottom)); |
49 | + } |
50 | + |
51 | + function getImgFullUri(uri) { |
52 | + if ((uri.slice(0, 7) === 'http://') || |
53 | + (uri.slice(0, 8) === 'https://') || |
54 | + (uri.slice(0, 7) === 'file://')) { |
55 | + return uri; |
56 | + } else if (uri.slice(0, 1) === '/') { |
57 | + var docuri = document.documentURI; |
58 | + var firstcolon = docuri.indexOf('://'); |
59 | + var protocol = 'http://'; |
60 | + if (firstcolon !== -1) { |
61 | + protocol = docuri.slice(0, firstcolon + 3); |
62 | + } |
63 | + return protocol + document.domain + uri; |
64 | } else { |
65 | - return base.slice(0, lastslash + 1) + uri; |
66 | - } |
67 | - } |
68 | -} |
69 | - |
70 | -function getSelectedData(element) { |
71 | - var node = element; |
72 | - var data = new Object; |
73 | - |
74 | - var nodeName = node.nodeName.toLowerCase(); |
75 | - if (nodeName === 'img') { |
76 | - data.img = getImgFullUri(node.getAttribute('src')); |
77 | - } else if (nodeName === 'a') { |
78 | - data.href = node.href; |
79 | - data.title = node.title; |
80 | - } |
81 | - |
82 | - // If the parent tag is a hyperlink, we want it too. |
83 | - var parent = node.parentNode; |
84 | - if ((nodeName !== 'a') && parent && (parent.nodeName.toLowerCase() === 'a')) { |
85 | - data.href = parent.href; |
86 | - data.title = parent.title; |
87 | - node = parent; |
88 | - } |
89 | - |
90 | - var boundingRect = node.getBoundingClientRect(); |
91 | - data.left = boundingRect.left; |
92 | - data.top = boundingRect.top; |
93 | - data.width = boundingRect.width; |
94 | - data.height = boundingRect.height; |
95 | - |
96 | - node = node.cloneNode(true); |
97 | - // filter out script nodes |
98 | - var scripts = node.getElementsByTagName('script'); |
99 | - while (scripts.length > 0) { |
100 | - var scriptNode = scripts[0]; |
101 | - if (scriptNode.parentNode) { |
102 | - scriptNode.parentNode.removeChild(scriptNode); |
103 | - } |
104 | - } |
105 | - data.html = node.outerHTML; |
106 | - data.nodeName = node.nodeName.toLowerCase(); |
107 | - // FIXME: extract the text and images in the order they appear in the block, |
108 | - // so that this order is respected when the data is pushed to the clipboard. |
109 | - data.text = node.textContent; |
110 | - var images = []; |
111 | - var imgs = node.getElementsByTagName('img'); |
112 | - for (var i = 0; i < imgs.length; i++) { |
113 | - images.push(getImgFullUri(imgs[i].getAttribute('src'))); |
114 | - } |
115 | - if (images.length > 0) { |
116 | - data.images = images; |
117 | - } |
118 | - |
119 | - return data; |
120 | -} |
121 | - |
122 | -function adjustSelection(selection) { |
123 | - // FIXME: allow selecting two consecutive blocks, instead of |
124 | - // interpolating to the containing block. |
125 | - var centerX = (selection.left + selection.right) / 2; |
126 | - var centerY = (selection.top + selection.bottom) / 2; |
127 | - var element = document.elementFromPoint(centerX, centerY); |
128 | - var parent = element; |
129 | - while (elementContainedInBox(parent, selection)) { |
130 | - parent = parent.parentNode; |
131 | - } |
132 | - element = parent; |
133 | - return getSelectedData(element); |
134 | -} |
135 | - |
136 | -function distance(touch1, touch2) { |
137 | - return Math.sqrt(Math.pow(touch2.clientX - touch1.clientX, 2) + |
138 | - Math.pow(touch2.clientY - touch1.clientY, 2)); |
139 | -} |
140 | - |
141 | -navigator.qt.onmessage = function(message) { |
142 | - var data = null; |
143 | - try { |
144 | - data = JSON.parse(message.data); |
145 | - } catch (error) { |
146 | - return; |
147 | - } |
148 | - if ('query' in data) { |
149 | - if (data.query === 'adjustselection') { |
150 | - var selection = adjustSelection(data); |
151 | - selection.event = 'selectionadjusted'; |
152 | - navigator.qt.postMessage(JSON.stringify(selection)); |
153 | - } |
154 | - } |
155 | -} |
156 | - |
157 | -var longpressObserver = -1; |
158 | -var currentTouch = null; |
159 | -var longpressDetected = false; |
160 | - |
161 | -function longPressDetected(x, y) { |
162 | - longpressDetected = true; |
163 | - var element = document.elementFromPoint(x, y); |
164 | - var data = getSelectedData(element); |
165 | - data.event = 'longpress'; |
166 | - navigator.qt.postMessage(JSON.stringify(data)); |
167 | -} |
168 | - |
169 | -function clearLongpressTimeout() { |
170 | - clearTimeout(longpressObserver); |
171 | - longpressObserver = -1; |
172 | - currentTouch = null; |
173 | -} |
174 | - |
175 | -var doc = document.documentElement; |
176 | - |
177 | -doc.addEventListener('touchstart', function(event) { |
178 | - if (event.touches.length == 1) { |
179 | - currentTouch = event.touches[0]; |
180 | - longpressObserver = setTimeout(longPressDetected, 800, currentTouch.clientX, currentTouch.clientY); |
181 | - } |
182 | -}); |
183 | - |
184 | -doc.addEventListener('touchend', function(event) { |
185 | - if (longpressDetected) { |
186 | - longpressDetected = false; |
187 | - event.preventDefault(); |
188 | - } |
189 | - clearLongpressTimeout(); |
190 | -}); |
191 | - |
192 | -doc.addEventListener('touchmove', function(event) { |
193 | - if (!currentTouch) { |
194 | - return; |
195 | - } |
196 | - if ((event.changedTouches.length > 1) || (distance(event.changedTouches[0], currentTouch) > 3)) { |
197 | - clearLongpressTimeout(); |
198 | - } |
199 | -}); |
200 | + var base = document.baseURI; |
201 | + var lastslash = base.lastIndexOf('/'); |
202 | + if (lastslash === -1) { |
203 | + return base + '/' + uri; |
204 | + } else { |
205 | + return base.slice(0, lastslash + 1) + uri; |
206 | + } |
207 | + } |
208 | + } |
209 | + |
210 | + function getSelectedData(element) { |
211 | + var node = element; |
212 | + var data = new Object; |
213 | + |
214 | + var nodeName = node.nodeName.toLowerCase(); |
215 | + if (nodeName === 'img') { |
216 | + data.img = getImgFullUri(node.getAttribute('src')); |
217 | + } else if (nodeName === 'a') { |
218 | + data.href = node.href; |
219 | + data.title = node.title; |
220 | + } |
221 | + |
222 | + // If the parent tag is a hyperlink, we want it too. |
223 | + var parent = node.parentNode; |
224 | + if ((nodeName !== 'a') && parent && (parent.nodeName.toLowerCase() === 'a')) { |
225 | + data.href = parent.href; |
226 | + data.title = parent.title; |
227 | + node = parent; |
228 | + } |
229 | + |
230 | + var boundingRect = node.getBoundingClientRect(); |
231 | + data.left = boundingRect.left; |
232 | + data.top = boundingRect.top; |
233 | + data.width = boundingRect.width; |
234 | + data.height = boundingRect.height; |
235 | + |
236 | + node = node.cloneNode(true); |
237 | + // filter out script nodes |
238 | + var scripts = node.getElementsByTagName('script'); |
239 | + while (scripts.length > 0) { |
240 | + var scriptNode = scripts[0]; |
241 | + if (scriptNode.parentNode) { |
242 | + scriptNode.parentNode.removeChild(scriptNode); |
243 | + } |
244 | + } |
245 | + data.html = node.outerHTML; |
246 | + data.nodeName = node.nodeName.toLowerCase(); |
247 | + // FIXME: extract the text and images in the order they appear in the block, |
248 | + // so that this order is respected when the data is pushed to the clipboard. |
249 | + data.text = node.textContent; |
250 | + var images = []; |
251 | + var imgs = node.getElementsByTagName('img'); |
252 | + for (var i = 0; i < imgs.length; i++) { |
253 | + images.push(getImgFullUri(imgs[i].getAttribute('src'))); |
254 | + } |
255 | + if (images.length > 0) { |
256 | + data.images = images; |
257 | + } |
258 | + |
259 | + return data; |
260 | + } |
261 | + |
262 | + function adjustSelection(selection) { |
263 | + // FIXME: allow selecting two consecutive blocks, instead of |
264 | + // interpolating to the containing block. |
265 | + var centerX = (selection.left + selection.right) / 2; |
266 | + var centerY = (selection.top + selection.bottom) / 2; |
267 | + var element = document.elementFromPoint(centerX, centerY); |
268 | + var parent = element; |
269 | + while (elementContainedInBox(parent, selection)) { |
270 | + parent = parent.parentNode; |
271 | + } |
272 | + element = parent; |
273 | + return getSelectedData(element); |
274 | + } |
275 | + |
276 | + function distance(touch1, touch2) { |
277 | + return Math.sqrt(Math.pow(touch2.clientX - touch1.clientX, 2) + |
278 | + Math.pow(touch2.clientY - touch1.clientY, 2)); |
279 | + } |
280 | + |
281 | + navigator.qt.onmessage = function(message) { |
282 | + var data = null; |
283 | + try { |
284 | + data = JSON.parse(message.data); |
285 | + } catch (error) { |
286 | + return; |
287 | + } |
288 | + if ('query' in data) { |
289 | + if (data.query === 'adjustselection') { |
290 | + var selection = adjustSelection(data); |
291 | + selection.event = 'selectionadjusted'; |
292 | + navigator.qt.postMessage(JSON.stringify(selection)); |
293 | + } |
294 | + } |
295 | + } |
296 | + |
297 | + var longpressObserver = -1; |
298 | + var currentTouch = null; |
299 | + var longpressDetected = false; |
300 | + |
301 | + function longPressDetected(x, y) { |
302 | + longpressDetected = true; |
303 | + var element = document.elementFromPoint(x, y); |
304 | + var data = getSelectedData(element); |
305 | + data.event = 'longpress'; |
306 | + navigator.qt.postMessage(JSON.stringify(data)); |
307 | + } |
308 | + |
309 | + function clearLongpressTimeout() { |
310 | + clearTimeout(longpressObserver); |
311 | + longpressObserver = -1; |
312 | + currentTouch = null; |
313 | + } |
314 | + |
315 | + var doc = document.documentElement; |
316 | + |
317 | + doc.addEventListener('touchstart', function(event) { |
318 | + if (event.touches.length == 1) { |
319 | + currentTouch = event.touches[0]; |
320 | + longpressObserver = setTimeout(longPressDetected, 800, currentTouch.clientX, currentTouch.clientY); |
321 | + } |
322 | + }); |
323 | + |
324 | + doc.addEventListener('touchend', function(event) { |
325 | + if (longpressDetected) { |
326 | + longpressDetected = false; |
327 | + event.preventDefault(); |
328 | + } |
329 | + clearLongpressTimeout(); |
330 | + }); |
331 | + |
332 | + doc.addEventListener('touchmove', function(event) { |
333 | + if (!currentTouch) { |
334 | + return; |
335 | + } |
336 | + if ((event.changedTouches.length > 1) || (distance(event.changedTouches[0], currentTouch) > 3)) { |
337 | + clearLongpressTimeout(); |
338 | + } |
339 | + }); |
340 | + |
341 | + doc.addEventListener('touchcancel', function(event) { |
342 | + if (longpressDetected) { |
343 | + longpressDetected = false; |
344 | + } |
345 | + clearLongpressTimeout(); |
346 | + }); |
347 | + |
348 | +} |
• Are there any related MPs required for this MP to build/function as expected? NO
• Is your branch in sync with latest trunk (e.g. bzr pull lp:trunk -> no changes) YES
• Did you perform an exploratory manual test run of your code change and any related functionality on device or emulator? YES, on Galaxy Nexus
• Did you successfully run all tests found in your component's Test Plan (https:/ /wiki.ubuntu. com/Process/ Merges/ TestPlan/<package-name>) on device or emulator? YES
• If you changed the UI, was the change specified/approved by design? N/A
• If you changed the packaging (debian), did you subscribe a core-dev to this MP? N/A