Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 /* | 1 /* |
2 * This file is part of Adblock Plus <http://adblockplus.org/>, | 2 * This file is part of Adblock Plus <http://adblockplus.org/>, |
3 * Copyright (C) 2006-2014 Eyeo GmbH | 3 * Copyright (C) 2006-2014 Eyeo GmbH |
4 * | 4 * |
5 * Adblock Plus is free software: you can redistribute it and/or modify | 5 * Adblock Plus is free software: you can redistribute it and/or modify |
6 * it under the terms of the GNU General Public License version 3 as | 6 * it under the terms of the GNU General Public License version 3 as |
7 * published by the Free Software Foundation. | 7 * published by the Free Software Foundation. |
8 * | 8 * |
9 * Adblock Plus is distributed in the hope that it will be useful, | 9 * Adblock Plus is distributed in the hope that it will be useful, |
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
168 { | 168 { |
169 Array.prototype.forEach.call( | 169 Array.prototype.forEach.call( |
170 document.querySelectorAll(highlightedElementsSelector), | 170 document.querySelectorAll(highlightedElementsSelector), |
171 unhighlightElement | 171 unhighlightElement |
172 ); | 172 ); |
173 | 173 |
174 highlightedElementsSelector = null; | 174 highlightedElementsSelector = null; |
175 } | 175 } |
176 } | 176 } |
177 | 177 |
178 function getElementURLs(element) { | |
179 var urls = []; | |
180 | |
181 if (element.src) | |
182 urls.push(element.src); | |
183 | |
184 switch (element.localName) | |
185 { | |
186 case "object": | |
187 var url = element.getAttribute("data"); | |
188 if (url) | |
189 return [resolveURL(url)]; | |
190 | |
191 for (var i = 0; i < element.children.length; i++) | |
192 { | |
193 var child = element.children[i]; | |
194 if (child.localName != "param") | |
195 continue; | |
196 | |
197 var name = child.getAttribute("name"); | |
198 if (name != "movie" && name != "src") | |
199 continue; | |
200 | |
201 var value = child.getAttribute("value"); | |
202 if (!value) | |
203 continue; | |
204 | |
205 return [resolveURL(value)]; | |
206 } | |
207 | |
208 return []; | |
209 | |
210 case "video": | |
211 case "audio": | |
212 case "picture": | |
213 for (var i = 0; i < element.children.length; i++) | |
214 { | |
215 var child = element.children[i]; | |
216 | |
217 if (child.localName != "source") | |
218 continue; | |
219 | |
220 if (child.src) | |
221 urls.push(child.src); | |
222 | |
223 urls = urls.concat(parseSrcSet(child)); | |
224 } | |
225 | |
226 if (element.poster) | |
227 urls.push(element.poster); | |
228 | |
229 break; | |
230 | |
231 case "img": | |
232 urls = urls.concat(parseSrcSet(element)); | |
233 } | |
234 | |
235 return urls; | |
236 } | |
237 | |
238 function isBlockable(element) | |
239 { | |
240 if (element.id) | |
241 return true; | |
242 if (element.classList.length > 0) | |
243 return true; | |
244 if (getElementURLs(element).length > 0) | |
245 return true; | |
246 | |
247 // We only generate filters based on the "style" attribute, | |
248 // if this is the only way we can generate a filter, and | |
249 // only if there are at least two CSS properties defined. | |
250 if (/:.+:/.test(element.getAttribute("style"))) | |
251 return true; | |
252 | |
253 return false; | |
254 } | |
255 | |
178 // Gets the absolute position of an element by walking up the DOM tree, | 256 // Gets the absolute position of an element by walking up the DOM tree, |
179 // adding up offsets. | 257 // adding up offsets. |
180 // I hope there's a better way because it just seems absolutely stupid | 258 // I hope there's a better way because it just seems absolutely stupid |
181 // that the DOM wouldn't have a direct way to get this, given that it | 259 // that the DOM wouldn't have a direct way to get this, given that it |
182 // has hundreds and hundreds of other methods that do random junk. | 260 // has hundreds and hundreds of other methods that do random junk. |
183 function getAbsolutePosition(elt) { | 261 function getAbsolutePosition(elt) { |
184 var l = 0; | 262 var l = 0; |
185 var t = 0; | 263 var t = 0; |
186 for(; elt; elt = elt.offsetParent) { | 264 for(; elt; elt = elt.offsetParent) { |
187 l += elt.offsetLeft; | 265 l += elt.offsetLeft; |
188 t += elt.offsetTop; | 266 t += elt.offsetTop; |
189 } | 267 } |
190 return [l, t]; | 268 return [l, t]; |
191 } | 269 } |
192 | 270 |
193 // Adds an overlay to an element, which is probably a Flash object | 271 // Adds an overlay to an element, which is probably a Flash object |
194 function addElementOverlay(elt) { | 272 function addElementOverlay(elt) { |
195 // If this element is enclosed in an object tag, we prefer to block that inste ad | 273 // If this element is enclosed in an object tag, we prefer to block that inste ad |
196 if(!elt) | 274 if(!elt) |
197 return null; | 275 return null; |
198 | 276 |
199 // If element doesn't have at least one of class name, ID or URL, give up | 277 // If element doesn't have at least one of class name, ID or URL, give up |
200 // because we don't know how to construct a filter rule for it | 278 // because we don't know how to construct a filter rule for it |
201 if(!hasFilters(elt)) | 279 if(!isBlockable(elt)) |
202 return; | 280 return; |
281 | |
282 // If the element isn't rendered (since its or one of its ancestor's | |
283 // "diplay" property is "none"), the overlay wouldn't match the element. | |
284 if (!elt.offsetParent) | |
285 return; | |
286 | |
203 var thisStyle = getComputedStyle(elt, null); | 287 var thisStyle = getComputedStyle(elt, null); |
204 var overlay = document.createElement('div'); | 288 var overlay = document.createElement('div'); |
205 overlay.prisoner = elt; | 289 overlay.prisoner = elt; |
206 overlay.className = "__adblockplus__overlay"; | 290 overlay.className = "__adblockplus__overlay"; |
207 overlay.setAttribute('style', 'opacity:0.4; background-color:#ffffff; display: inline-box; ' + 'width:' + thisStyle.width + '; height:' + thisStyle.height + '; position:absolute; overflow:hidden; -webkit-box-sizing:border-box; z-index: 999 99'); | 291 overlay.setAttribute('style', 'opacity:0.4; background-color:#ffffff; display: inline-box; ' + 'width:' + thisStyle.width + '; height:' + thisStyle.height + '; position:absolute; overflow:hidden; -webkit-box-sizing:border-box;'); |
208 var pos = getAbsolutePosition(elt); | 292 var pos = getAbsolutePosition(elt); |
209 overlay.style.left = pos[0] + "px"; | 293 overlay.style.left = pos[0] + "px"; |
210 overlay.style.top = pos[1] + "px"; | 294 overlay.style.top = pos[1] + "px"; |
295 | |
296 if (thisStyle.position != "static") | |
297 overlay.style.zIndex = thisStyle.zIndex; | |
298 else | |
299 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; | |
300 | |
211 // elt.parentNode.appendChild(overlay, elt); | 301 // elt.parentNode.appendChild(overlay, elt); |
212 document.body.appendChild(overlay); | 302 document.body.appendChild(overlay); |
213 return overlay; | 303 return overlay; |
214 } | 304 } |
215 | 305 |
216 // Show dialog asking user whether she wants to add the proposed filters derived | 306 // Show dialog asking user whether she wants to add the proposed filters derived |
217 // from selected page element | 307 // from selected page element |
218 function clickHide_showDialog(left, top, filters) | 308 function clickHide_showDialog(left, top, filters) |
219 { | 309 { |
220 // If we are already selecting, abort now | 310 // If we are already selecting, abort now |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
274 // on whether the user actually wants these filters | 364 // on whether the user actually wants these filters |
275 function clickHide_rulesPending() { | 365 function clickHide_rulesPending() { |
276 clickHide_activated = false; | 366 clickHide_activated = false; |
277 document.removeEventListener("mouseover", clickHide_mouseOver, true); | 367 document.removeEventListener("mouseover", clickHide_mouseOver, true); |
278 document.removeEventListener("mouseout", clickHide_mouseOut, true); | 368 document.removeEventListener("mouseout", clickHide_mouseOut, true); |
279 document.removeEventListener("click", clickHide_mouseClick, true); | 369 document.removeEventListener("click", clickHide_mouseClick, true); |
280 document.removeEventListener("keydown", clickHide_keyDown, true); | 370 document.removeEventListener("keydown", clickHide_keyDown, true); |
281 } | 371 } |
282 | 372 |
283 // Turn off click-to-hide | 373 // Turn off click-to-hide |
284 function clickHide_deactivate(keepOverlays) | 374 function clickHide_deactivate(keepOverlays) |
kzar
2014/11/26 14:14:04
We're relying on the legacy code not passing this
Sebastian Noack
2014/11/26 14:41:39
Correct. I tried to keep the patch as compact as p
| |
285 { | 375 { |
286 if (clickHideFiltersDialog) | 376 if (clickHideFiltersDialog) |
287 { | 377 { |
288 document.body.removeChild(clickHideFiltersDialog); | 378 document.body.removeChild(clickHideFiltersDialog); |
289 clickHideFiltersDialog = null; | 379 clickHideFiltersDialog = null; |
290 } | 380 } |
291 | 381 |
292 clickHide_activated = false; | 382 clickHide_activated = false; |
293 clickHide_filters = null; | 383 clickHide_filters = null; |
294 if(!document) | 384 if(!document) |
295 return; // This can happen inside a nuked iframe...I think | 385 return; // This can happen inside a nuked iframe...I think |
296 document.removeEventListener("mouseover", clickHide_mouseOver, true); | 386 document.removeEventListener("mouseover", clickHide_mouseOver, true); |
297 document.removeEventListener("mouseout", clickHide_mouseOut, true); | 387 document.removeEventListener("mouseout", clickHide_mouseOut, true); |
298 document.removeEventListener("click", clickHide_mouseClick, true); | 388 document.removeEventListener("click", clickHide_mouseClick, true); |
299 document.removeEventListener("keydown", clickHide_keyDown, true); | 389 document.removeEventListener("keydown", clickHide_keyDown, true); |
300 | 390 |
301 if (!keepOverlays) | 391 if (!keepOverlays) |
302 { | 392 { |
303 if(currentElement) { | 393 if (currentElement) { |
kzar
2014/11/26 14:14:04
Nitpick: Should be space between "if" and "("?
Sebastian Noack
2014/11/26 14:41:39
I just copied the code from above, but I have adde
| |
304 currentElement.removeEventListener("contextmenu", clickHide_elementClickHa ndler, false); | 394 currentElement.removeEventListener("contextmenu", clickHide_elementClickH andler, true); |
kzar
2014/11/26 14:14:04
Last parameter should be true?
Sebastian Noack
2014/11/26 14:41:39
Yes, this patch was created on top of a version, w
| |
305 unhighlightElements(); | 395 unhighlightElements(); |
306 unhighlightElement(currentElement); | 396 unhighlightElement(currentElement); |
307 currentElement = null; | 397 currentElement = null; |
308 clickHideFilters = null; | 398 clickHideFilters = null; |
309 } | 399 } |
310 unhighlightElements(); | 400 unhighlightElements(); |
311 | 401 |
312 var overlays = document.getElementsByClassName("__adblockplus__overlay"); | 402 var overlays = document.getElementsByClassName("__adblockplus__overlay"); |
313 while (overlays.length > 0) | 403 while (overlays.length > 0) |
314 overlays[0].parentNode.removeChild(overlays[0]); | 404 overlays[0].parentNode.removeChild(overlays[0]); |
315 } | 405 } |
316 } | 406 } |
317 | 407 |
318 function clickHide_elementClickHandler(ev) { | 408 function clickHide_elementClickHandler(ev) { |
319 ev.preventDefault(); | 409 ev.preventDefault(); |
320 ev.stopPropagation(); | 410 ev.stopPropagation(); |
321 clickHide_mouseClick(ev); | 411 clickHide_mouseClick(ev); |
322 } | 412 } |
323 | 413 |
324 // Hovering over an element so highlight it | 414 // Hovering over an element so highlight it |
325 function clickHide_mouseOver(e) | 415 function clickHide_mouseOver(e) |
326 { | 416 { |
327 if (clickHide_activated == false) | 417 if (clickHide_activated == false) |
328 return; | 418 return; |
329 | 419 |
330 var target = e.target; | 420 var target = e.target; |
331 while (target.parentNode && !hasFilters(target)) | 421 while (target.parentNode && !isBlockable(target)) |
332 target = target.parentNode; | 422 target = target.parentNode; |
333 if (target == document.documentElement || target == document.body) | 423 if (target == document.documentElement || target == document.body) |
334 target = null; | 424 target = null; |
335 | 425 |
336 if (target && target instanceof HTMLElement) | 426 if (target && target instanceof HTMLElement) |
337 { | 427 { |
338 currentElement = target; | 428 currentElement = target; |
339 | 429 |
340 highlightElement(target, "#d6d84b", "#f8fa47"); | 430 highlightElement(target, "#d6d84b", "#f8fa47"); |
341 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); | 431 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); |
(...skipping 23 matching lines...) Expand all Loading... | |
365 payload: | 455 payload: |
366 { | 456 { |
367 type: "clickhide-deactivate" | 457 type: "clickhide-deactivate" |
368 } | 458 } |
369 }); | 459 }); |
370 e.preventDefault(); | 460 e.preventDefault(); |
371 e.stopPropagation(); | 461 e.stopPropagation(); |
372 } | 462 } |
373 } | 463 } |
374 | 464 |
375 | |
376 | |
377 // When the user clicks, the currentElement is the one we want. | 465 // When the user clicks, the currentElement is the one we want. |
378 // We should have ABP rules ready for when the | 466 // We should have ABP rules ready for when the |
379 // popup asks for them. | 467 // popup asks for them. |
380 function clickHide_mouseClick(e) | 468 function clickHide_mouseClick(e) |
381 { | 469 { |
382 if (!currentElement || !clickHide_activated) | 470 if (!currentElement || !clickHide_activated) |
383 return; | 471 return; |
384 | 472 |
385 var elt = currentElement; | 473 var elt = currentElement; |
386 if (currentElement.classList.contains("__adblockplus__overlay")) | 474 if (currentElement.classList.contains("__adblockplus__overlay")) |
(...skipping 21 matching lines...) Expand all Loading... | |
408 for (var i = 0; i < elt.classList.length; i++) | 496 for (var i = 0; i < elt.classList.length; i++) |
409 selector += "." + escapeCSS(elt.classList[i]); | 497 selector += "." + escapeCSS(elt.classList[i]); |
410 | 498 |
411 addSelector(selector); | 499 addSelector(selector); |
412 } | 500 } |
413 | 501 |
414 var urls = getElementURLs(elt); | 502 var urls = getElementURLs(elt); |
415 for (var i = 0; i < urls.length; i++) | 503 for (var i = 0; i < urls.length; i++) |
416 { | 504 { |
417 var url = urls[i]; | 505 var url = urls[i]; |
418 var isHTTP = /^https?:/i.test(url); | 506 |
419 | 507 if (/^https?:/i.test(url)) |
420 if (isHTTP) | |
421 { | 508 { |
422 var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||"); | 509 var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||"); |
423 | 510 |
424 if (clickHideFilters.indexOf(filter) != -1) | 511 if (clickHideFilters.indexOf(filter) == -1) |
425 continue; | 512 clickHideFilters.push(filter); |
426 | 513 |
427 clickHideFilters.push(filter); | 514 continue; |
428 } | 515 } |
429 | 516 |
430 if (url == elt.src) | 517 if (url == elt.src) |
431 { | 518 addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("s rc")) + ']'); |
432 var selector = escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute ("src")) + ']'; | |
433 | |
434 if (isHTTP) | |
435 selectorList.push(selector); | |
436 else | |
437 addSelector(selector); | |
438 } | |
439 } | 519 } |
440 | 520 |
441 // restore the original style, before generating the fallback filter that | 521 // restore the original style, before generating the fallback filter that |
442 // will include the style, and to prevent highlightElements from saving those | 522 // will include the style, and to prevent highlightElements from saving those |
443 unhighlightElement(currentElement); | 523 unhighlightElement(currentElement); |
444 | 524 |
445 // as last resort, create a filter based on inline styles | 525 // as last resort, create a filter based on inline styles |
446 if (clickHideFilters.length == 0) | 526 if (clickHideFilters.length == 0) |
447 { | 527 { |
448 var style = elt.getAttribute("style"); | 528 var style = elt.getAttribute("style"); |
(...skipping 24 matching lines...) Expand all Loading... | |
473 for (var i = 0; i < urls.length; i++) | 553 for (var i = 0; i < urls.length; i++) |
474 { | 554 { |
475 var url = urls[i].replace(/^\s+/, "").replace(/(\s+\S+)?\s*$/, ""); | 555 var url = urls[i].replace(/^\s+/, "").replace(/(\s+\S+)?\s*$/, ""); |
476 if (url) | 556 if (url) |
477 urls[i] = resolveURL(url); | 557 urls[i] = resolveURL(url); |
478 else | 558 else |
479 urls.splice(i--, 1); | 559 urls.splice(i--, 1); |
480 } | 560 } |
481 | 561 |
482 return urls; | 562 return urls; |
483 } | |
484 | |
485 function getElementURLs(elt) { | |
486 var urls = []; | |
487 | |
488 if (elt.src) | |
489 urls.push(elt.src); | |
490 | |
491 switch (elt.localName) | |
492 { | |
493 case "object": | |
494 var url = elt.getAttribute("data"); | |
495 if (url) | |
496 return [resolveURL(url)]; | |
497 | |
498 for (var i = 0; i < elt.children.length; i++) | |
499 { | |
500 var child = elt.children[i]; | |
501 if (child.localName != "param") | |
502 continue; | |
503 | |
504 var name = child.getAttribute("name"); | |
505 if (name != "movie" && name != "src") | |
506 continue; | |
507 | |
508 var value = child.getAttribute("value"); | |
509 if (!value) | |
510 continue; | |
511 | |
512 return [resolveURL(value)]; | |
513 } | |
514 | |
515 return []; | |
516 | |
517 case "video": | |
518 case "audio": | |
519 case "picture": | |
520 for (var i = 0; i < elt.children.length; i++) | |
521 { | |
522 var child = elt.children[i]; | |
523 | |
524 if (child.localName != "source") | |
525 continue; | |
526 | |
527 if (child.src) | |
528 urls.push(child.src); | |
529 | |
530 urls = urls.concat(parseSrcSet(child)); | |
531 } | |
532 | |
533 if (elt.poster) | |
534 urls.push(elt.poster); | |
535 | |
536 break; | |
537 | |
538 case "img": | |
539 urls = urls.concat(parseSrcSet(elt)); | |
540 } | |
541 | |
542 return urls; | |
543 } | |
544 | |
545 function hasFilters(element) | |
546 { | |
547 if (element.id) | |
548 return true; | |
549 if (element.classList.length > 0) | |
550 return true; | |
551 if (getElementURLs(element).length > 0) | |
552 return true; | |
553 if (/:.+:/.test(element.getAttribute("style"))) | |
554 return true; | |
555 | |
556 return false; | |
557 } | 563 } |
558 | 564 |
559 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js | 565 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js |
560 // and licensed under the MIT license. See jquery-*.min.js for details. | 566 // and licensed under the MIT license. See jquery-*.min.js for details. |
561 function removeDotSegments(u) { | 567 function removeDotSegments(u) { |
562 var r = '', m = []; | 568 var r = '', m = []; |
563 if (/\./.test(u)) { | 569 if (/\./.test(u)) { |
564 while (u !== undefined && u !== '') { | 570 while (u !== undefined && u !== '') { |
565 if (u === '.' || u === '..') { | 571 if (u === '.' || u === '..') { |
566 u = ''; | 572 u = ''; |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
709 break; | 715 break; |
710 default: | 716 default: |
711 sendResponse({}); | 717 sendResponse({}); |
712 break; | 718 break; |
713 } | 719 } |
714 }); | 720 }); |
715 | 721 |
716 if (window == window.top) | 722 if (window == window.top) |
717 ext.backgroundPage.sendMessage({type: "report-html-page"}); | 723 ext.backgroundPage.sendMessage({type: "report-html-page"}); |
718 } | 724 } |
LEFT | RIGHT |