OLD | NEW |
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 var url = getElementURL(elt); | 279 if(!isBlockable(elt)) |
202 if(!elt.className && !elt.id && !url) | |
203 return; | 280 return; |
204 var thisStyle = getComputedStyle(elt, null); | 281 var thisStyle = getComputedStyle(elt, null); |
205 var overlay = document.createElement('div'); | 282 var overlay = document.createElement('div'); |
206 overlay.prisoner = elt; | 283 overlay.prisoner = elt; |
207 overlay.prisonerURL = url; | |
208 overlay.className = "__adblockplus__overlay"; | 284 overlay.className = "__adblockplus__overlay"; |
209 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'); | 285 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'); |
210 var pos = getAbsolutePosition(elt); | 286 var pos = getAbsolutePosition(elt); |
211 overlay.style.left = pos[0] + "px"; | 287 overlay.style.left = pos[0] + "px"; |
212 overlay.style.top = pos[1] + "px"; | 288 overlay.style.top = pos[1] + "px"; |
213 // elt.parentNode.appendChild(overlay, elt); | 289 // elt.parentNode.appendChild(overlay, elt); |
214 document.body.appendChild(overlay); | 290 document.body.appendChild(overlay); |
215 return overlay; | 291 return overlay; |
216 } | 292 } |
217 | 293 |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
258 // Turn on the choose element to create filter thing | 334 // Turn on the choose element to create filter thing |
259 function clickHide_activate() { | 335 function clickHide_activate() { |
260 if(document == null) | 336 if(document == null) |
261 return; | 337 return; |
262 | 338 |
263 // If we are already selecting, abort now | 339 // If we are already selecting, abort now |
264 if (clickHide_activated || clickHideFiltersDialog) | 340 if (clickHide_activated || clickHideFiltersDialog) |
265 clickHide_deactivate(); | 341 clickHide_deactivate(); |
266 | 342 |
267 // Add overlays for elements with URLs so user can easily click them | 343 // Add overlays for elements with URLs so user can easily click them |
268 var elts = document.querySelectorAll('object,embed,img,iframe'); | 344 var elts = document.querySelectorAll('object,embed,img,iframe,video,audio,pict
ure'); |
269 for(var i=0; i<elts.length; i++) | 345 for(var i=0; i<elts.length; i++) |
270 addElementOverlay(elts[i]); | 346 addElementOverlay(elts[i]); |
271 | 347 |
272 clickHide_activated = true; | 348 clickHide_activated = true; |
273 document.addEventListener("mouseover", clickHide_mouseOver, true); | 349 document.addEventListener("mouseover", clickHide_mouseOver, true); |
274 document.addEventListener("mouseout", clickHide_mouseOut, true); | 350 document.addEventListener("mouseout", clickHide_mouseOut, true); |
275 document.addEventListener("click", clickHide_mouseClick, true); | 351 document.addEventListener("click", clickHide_mouseClick, true); |
276 document.addEventListener("keydown", clickHide_keyDown, true); | 352 document.addEventListener("keydown", clickHide_keyDown, true); |
277 } | 353 } |
278 | 354 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 clickHide_mouseClick(ev); | 402 clickHide_mouseClick(ev); |
327 } | 403 } |
328 | 404 |
329 // Hovering over an element so highlight it | 405 // Hovering over an element so highlight it |
330 function clickHide_mouseOver(e) | 406 function clickHide_mouseOver(e) |
331 { | 407 { |
332 if (clickHide_activated == false) | 408 if (clickHide_activated == false) |
333 return; | 409 return; |
334 | 410 |
335 var target = e.target; | 411 var target = e.target; |
336 while (target.parentNode && !(target.id || target.className || target.src || /
:.+:/.test(target.getAttribute("style")))) | 412 while (target.parentNode && !isBlockable(target)) |
337 target = target.parentNode; | 413 target = target.parentNode; |
338 if (target == document.documentElement || target == document.body) | 414 if (target == document.documentElement || target == document.body) |
339 target = null; | 415 target = null; |
340 | 416 |
341 if (target && target instanceof HTMLElement) | 417 if (target && target instanceof HTMLElement) |
342 { | 418 { |
343 currentElement = target; | 419 currentElement = target; |
344 | 420 |
345 highlightElement(target, "#d6d84b", "#f8fa47"); | 421 highlightElement(target, "#d6d84b", "#f8fa47"); |
346 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); | 422 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 | 455 |
380 // When the user clicks, the currentElement is the one we want. | 456 // When the user clicks, the currentElement is the one we want. |
381 // We should have ABP rules ready for when the | 457 // We should have ABP rules ready for when the |
382 // popup asks for them. | 458 // popup asks for them. |
383 function clickHide_mouseClick(e) | 459 function clickHide_mouseClick(e) |
384 { | 460 { |
385 if (!currentElement || !clickHide_activated) | 461 if (!currentElement || !clickHide_activated) |
386 return; | 462 return; |
387 | 463 |
388 var elt = currentElement; | 464 var elt = currentElement; |
389 var url = null; | |
390 if (currentElement.classList.contains("__adblockplus__overlay")) | 465 if (currentElement.classList.contains("__adblockplus__overlay")) |
391 { | |
392 elt = currentElement.prisoner; | 466 elt = currentElement.prisoner; |
393 url = currentElement.prisonerURL; | |
394 } | |
395 else if (elt.src) | |
396 url = elt.src; | |
397 | 467 |
398 clickHideFilters = new Array(); | 468 clickHideFilters = new Array(); |
399 selectorList = new Array(); | 469 selectorList = new Array(); |
400 | 470 |
401 var addSelector = function(selector) | 471 var addSelector = function(selector) |
402 { | 472 { |
| 473 if (selectorList.indexOf(selector) != -1) |
| 474 return; |
| 475 |
403 clickHideFilters.push(document.domain + "##" + selector); | 476 clickHideFilters.push(document.domain + "##" + selector); |
404 selectorList.push(selector); | 477 selectorList.push(selector); |
405 }; | 478 }; |
406 | 479 |
407 if (elt.id) | 480 if (elt.id) |
408 addSelector("#" + escapeCSS(elt.id)); | 481 addSelector("#" + escapeCSS(elt.id)); |
409 | 482 |
410 if (elt.classList.length > 0) | 483 if (elt.classList.length > 0) |
411 { | 484 { |
412 var selector = ""; | 485 var selector = ""; |
413 | 486 |
414 for (var i = 0; i < elt.classList.length; i++) | 487 for (var i = 0; i < elt.classList.length; i++) |
415 selector += "." + escapeCSS(elt.classList[i]); | 488 selector += "." + escapeCSS(elt.classList[i]); |
416 | 489 |
417 addSelector(selector); | 490 addSelector(selector); |
418 } | 491 } |
419 | 492 |
420 if (url) | 493 var urls = getElementURLs(elt); |
| 494 for (var i = 0; i < urls.length; i++) |
421 { | 495 { |
422 var src = elt.getAttribute("src"); | 496 var url = urls[i]; |
423 var selector = src && escapeCSS(elt.localName) + '[src=' + quote(src) + ']'; | 497 var isHTTP = /^https?:/i.test(url); |
424 | 498 |
425 if (/^https?:/i.test(url)) | 499 if (isHTTP) |
426 { | 500 { |
427 clickHideFilters.push(url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||")); | 501 var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||"); |
428 | 502 |
429 if (selector) | 503 if (clickHideFilters.indexOf(filter) != -1) |
| 504 continue; |
| 505 |
| 506 clickHideFilters.push(filter); |
| 507 } |
| 508 |
| 509 if (url == elt.src) |
| 510 { |
| 511 var selector = escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute
("src")) + ']'; |
| 512 |
| 513 if (isHTTP) |
430 selectorList.push(selector); | 514 selectorList.push(selector); |
| 515 else |
| 516 addSelector(selector); |
431 } | 517 } |
432 else if (selector) | |
433 addSelector(selector); | |
434 } | 518 } |
435 | 519 |
436 // restore the original style, before generating the fallback filter that | 520 // restore the original style, before generating the fallback filter that |
437 // will include the style, and to prevent highlightElements from saving those | 521 // will include the style, and to prevent highlightElements from saving those |
438 unhighlightElement(currentElement); | 522 unhighlightElement(currentElement); |
439 | 523 |
440 // as last resort, create a filter based on inline styles | 524 // as last resort, create a filter based on inline styles |
441 if (clickHideFilters.length == 0) | 525 if (clickHideFilters.length == 0) |
442 { | 526 { |
443 var style = elt.getAttribute("style"); | 527 var style = elt.getAttribute("style"); |
444 if (style) | 528 if (style) |
445 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']'); | 529 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']'); |
446 } | 530 } |
447 | 531 |
448 // Show popup | 532 // Show popup |
449 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); | 533 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); |
450 | 534 |
451 // Highlight the elements specified by selector in yellow | 535 // Highlight the elements specified by selector in yellow |
452 highlightElements(selectorList.join(",")); | 536 highlightElements(selectorList.join(",")); |
453 // Now, actually highlight the element the user clicked on in red | 537 // Now, actually highlight the element the user clicked on in red |
454 highlightElement(currentElement, "#fd1708", "#f6a1b5"); | 538 highlightElement(currentElement, "#fd1708", "#f6a1b5"); |
455 | 539 |
456 // Make sure the browser doesn't handle this click | 540 // Make sure the browser doesn't handle this click |
457 e.preventDefault(); | 541 e.preventDefault(); |
458 e.stopPropagation(); | 542 e.stopPropagation(); |
459 } | 543 } |
460 | 544 |
461 // Extracts source URL from an IMG, OBJECT, EMBED, or IFRAME | 545 function parseSrcSet(element) |
462 function getElementURL(elt) { | 546 { |
463 // Check children of object nodes for "param" nodes with name="movie" that spe
cify a URL | 547 if (!element.srcset) |
464 // in value attribute | 548 return []; |
465 var url; | |
466 if(elt.localName.toUpperCase() == "OBJECT" && !(url = elt.getAttribute("data")
)) { | |
467 // No data attribute, look in PARAM child tags for a URL for the swf file | |
468 var params = elt.querySelectorAll("param[name=\"movie\"]"); | |
469 // This OBJECT could contain an EMBED we already nuked, in which case there'
s no URL | |
470 if(params[0]) | |
471 url = params[0].getAttribute("value"); | |
472 else { | |
473 params = elt.querySelectorAll("param[name=\"src\"]"); | |
474 if(params[0]) | |
475 url = params[0].getAttribute("value"); | |
476 } | |
477 | 549 |
| 550 var urls = element.srcset.split(","); |
| 551 for (var i = 0; i < urls.length; i++) |
| 552 { |
| 553 var url = urls[i].replace(/^\s+/, "").replace(/(\s+\S+)?\s*$/, ""); |
478 if (url) | 554 if (url) |
479 url = resolveURL(url); | 555 urls[i] = resolveURL(url); |
480 } else if(!url) { | 556 else |
481 url = elt.src || elt.href; | 557 urls.splice(i--, 1); |
482 } | 558 } |
483 return url; | 559 |
| 560 return urls; |
484 } | 561 } |
485 | 562 |
486 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js | 563 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js |
487 // and licensed under the MIT license. See jquery-*.min.js for details. | 564 // and licensed under the MIT license. See jquery-*.min.js for details. |
488 function removeDotSegments(u) { | 565 function removeDotSegments(u) { |
489 var r = '', m = []; | 566 var r = '', m = []; |
490 if (/\./.test(u)) { | 567 if (/\./.test(u)) { |
491 while (u !== undefined && u !== '') { | 568 while (u !== undefined && u !== '') { |
492 if (u === '.' || u === '..') { | 569 if (u === '.' || u === '..') { |
493 u = ''; | 570 u = ''; |
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
674 break; | 751 break; |
675 default: | 752 default: |
676 sendResponse({}); | 753 sendResponse({}); |
677 break; | 754 break; |
678 } | 755 } |
679 }); | 756 }); |
680 | 757 |
681 if (window == window.top) | 758 if (window == window.top) |
682 ext.backgroundPage.sendMessage({type: "report-html-page"}); | 759 ext.backgroundPage.sendMessage({type: "report-html-page"}); |
683 } | 760 } |
OLD | NEW |