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

Side by Side Diff: include.postload.js

Issue 5225119261655040: Issue 1282 - Don't generate filters conflicting with existing exception rules (Closed)
Patch Set: Created Dec. 15, 2014, 2:47 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
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 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
260 260
261 case "video": 261 case "video":
262 case "audio": 262 case "audio":
263 case "picture": 263 case "picture":
264 return getURLsFromMediaElement(element); 264 return getURLsFromMediaElement(element);
265 } 265 }
266 266
267 return getURLsFromAttributes(element); 267 return getURLsFromAttributes(element);
268 } 268 }
269 269
270 function isBlockable(element)
271 {
272 if (element.id)
273 return true;
274 if (element.classList.length > 0)
275 return true;
276 if (getURLsFromElement(element).length > 0)
277 return true;
278
279 // We only generate filters based on the "style" attribute,
280 // if this is the only way we can generate a filter, and
281 // only if there are at least two CSS properties defined.
282 if (/:.+:/.test(getOriginalStyle(element)))
283 return true;
284
285 return false;
286 }
287
288 // Gets the absolute position of an element by walking up the DOM tree, 270 // Gets the absolute position of an element by walking up the DOM tree,
289 // adding up offsets. 271 // adding up offsets.
290 // I hope there's a better way because it just seems absolutely stupid 272 // I hope there's a better way because it just seems absolutely stupid
291 // that the DOM wouldn't have a direct way to get this, given that it 273 // that the DOM wouldn't have a direct way to get this, given that it
292 // has hundreds and hundreds of other methods that do random junk. 274 // has hundreds and hundreds of other methods that do random junk.
293 function getAbsolutePosition(elt) { 275 function getAbsolutePosition(elt) {
294 var l = 0; 276 var l = 0;
295 var t = 0; 277 var t = 0;
296 for(; elt; elt = elt.offsetParent) { 278 for(; elt; elt = elt.offsetParent) {
297 l += elt.offsetLeft; 279 l += elt.offsetLeft;
298 t += elt.offsetTop; 280 t += elt.offsetTop;
299 } 281 }
300 return [l, t]; 282 return [l, t];
301 } 283 }
302 284
303 // Adds an overlay to an element, which is probably a Flash object 285 // Adds an overlay to an element, which is probably a Flash object
304 function addElementOverlay(elt) { 286 function addElementOverlay(elt, callback) {
305 // If this element is enclosed in an object tag, we prefer to block that inste ad 287 // If this element is enclosed in an object tag, we prefer to block that inste ad
306 if(!elt) 288 if(!elt)
307 return null;
308
309 // If element doesn't have at least one of class name, ID or URL, give up
310 // because we don't know how to construct a filter rule for it
311 if(!isBlockable(elt))
312 return; 289 return;
313 290
314 // If the element isn't rendered (since its or one of its ancestor's 291 // If the element isn't rendered (since its or one of its ancestor's
315 // "display" property is "none"), the overlay wouldn't match the element. 292 // "display" property is "none"), the overlay wouldn't match the element.
316 if (!elt.offsetParent) 293 if (!elt.offsetParent)
317 return; 294 return;
318 295
319 var thisStyle = getComputedStyle(elt, null); 296 generateFilters(elt, function(filters)
320 var overlay = document.createElement('div'); 297 {
321 overlay.prisoner = elt; 298 if (filters.length == 0)
322 overlay.className = "__adblockplus__overlay"; 299 return;
323 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;');
324 var pos = getAbsolutePosition(elt);
325 overlay.style.left = pos[0] + "px";
326 overlay.style.top = pos[1] + "px";
327 300
328 if (thisStyle.position != "static") 301 var thisStyle = getComputedStyle(elt, null);
329 overlay.style.zIndex = thisStyle.zIndex; 302 var overlay = document.createElement('div');
330 else 303 overlay.prisoner = elt;
331 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; 304 overlay.className = "__adblockplus__overlay";
305 overlay.setAttribute('style', 'opacity:0.4; background-color:#ffffff; displa y:inline-box; ' + 'width:' + thisStyle.width + '; height:' + thisStyle.height + '; position:absolute; overflow:hidden; -webkit-box-sizing:border-box;');
306 var pos = getAbsolutePosition(elt);
307 overlay.style.left = pos[0] + "px";
308 overlay.style.top = pos[1] + "px";
332 309
333 // elt.parentNode.appendChild(overlay, elt); 310 if (thisStyle.position != "static")
334 document.body.appendChild(overlay); 311 overlay.style.zIndex = thisStyle.zIndex;
335 return overlay; 312 else
313 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex;
314
315 document.body.appendChild(overlay);
316
317 if (callback)
318 callback(overlay);
319 });
336 } 320 }
337 321
338 // Show dialog asking user whether she wants to add the proposed filters derived 322 // Show dialog asking user whether she wants to add the proposed filters derived
339 // from selected page element 323 // from selected page element
340 function clickHide_showDialog(left, top, filters) 324 function clickHide_showDialog(left, top, filters)
341 { 325 {
342 // If we are already selecting, abort now 326 // If we are already selecting, abort now
343 if (clickHide_activated || clickHideFiltersDialog) 327 if (clickHide_activated || clickHideFiltersDialog)
344 clickHide_deactivate(true); 328 clickHide_deactivate(true);
345 329
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 overlays[0].parentNode.removeChild(overlays[0]); 420 overlays[0].parentNode.removeChild(overlays[0]);
437 } 421 }
438 } 422 }
439 423
440 function clickHide_elementClickHandler(ev) { 424 function clickHide_elementClickHandler(ev) {
441 ev.preventDefault(); 425 ev.preventDefault();
442 ev.stopPropagation(); 426 ev.stopPropagation();
443 clickHide_mouseClick(ev); 427 clickHide_mouseClick(ev);
444 } 428 }
445 429
430 function getBlockableElementOrAncestor(element, callback)
431 {
432 if (element && element != document.documentElement
433 && element != document.body)
434 {
435 generateFilters(element, function(filters)
436 {
437 if (filters.length > 0)
438 callback(element);
439 else
440 getBlockableElementOrAncestor(element.parentElement, callback);
441 });
442 }
443 else
444 {
445 callback(null);
446 }
447 }
448
446 // Hovering over an element so highlight it 449 // Hovering over an element so highlight it
447 function clickHide_mouseOver(e) 450 function clickHide_mouseOver(e)
448 { 451 {
449 if (clickHide_activated == false) 452 if (clickHide_activated == false)
450 return; 453 return;
451 454
452 var target = e.target; 455 getBlockableElementOrAncestor(e.target, function(element)
453 while (target.parentNode && !isBlockable(target)) 456 {
454 target = target.parentNode; 457 if (currentElement)
455 if (target == document.documentElement || target == document.body) 458 unhighlightElement(currentElement);
456 target = null;
457 459
458 if (target && target instanceof HTMLElement) 460 if (element)
459 { 461 {
460 currentElement = target; 462 highlightElement(element, "#d6d84b", "#f8fa47");
463 element.addEventListener("contextmenu", clickHide_elementClickHandler, tru e);
464 }
461 465
462 highlightElement(target, "#d6d84b", "#f8fa47"); 466 currentElement = element;
463 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); 467 });
464 }
465 } 468 }
466 469
467 // No longer hovering over this element so unhighlight it 470 // No longer hovering over this element so unhighlight it
468 function clickHide_mouseOut(e) 471 function clickHide_mouseOut(e)
469 { 472 {
470 if (!clickHide_activated || !currentElement) 473 if (!clickHide_activated || currentElement != e.target)
471 return; 474 return;
472 475
473 unhighlightElement(currentElement); 476 unhighlightElement(currentElement);
474 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, true); 477 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, true);
475 } 478 }
476 479
477 // Selects the currently hovered-over filter or cancels selection 480 // Selects the currently hovered-over filter or cancels selection
478 function clickHide_keyDown(e) 481 function clickHide_keyDown(e)
479 { 482 {
480 if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 13 /*DOM_VK_RETURN* /) 483 if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 13 /*DOM_VK_RETURN* /)
481 clickHide_mouseClick(e); 484 clickHide_mouseClick(e);
482 else if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 27 /*DOM_VK_ES CAPE*/) 485 else if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 27 /*DOM_VK_ES CAPE*/)
483 { 486 {
484 ext.backgroundPage.sendMessage( 487 ext.backgroundPage.sendMessage(
485 { 488 {
486 type: "forward", 489 type: "forward",
487 payload: 490 payload:
488 { 491 {
489 type: "clickhide-deactivate" 492 type: "clickhide-deactivate"
490 } 493 }
491 }); 494 });
492 e.preventDefault(); 495 e.preventDefault();
493 e.stopPropagation(); 496 e.stopPropagation();
494 } 497 }
495 } 498 }
496 499
500 function generateFilters(element, callback)
501 {
502 function addStyleAttributeFilter(filters, selectors)
503 {
504 var style = getOriginalStyle(element);
505 if (style && filters.length == 0)
506 {
507 ext.backgroundPage.sendMessage(
508 {
509 type: "get-filters-from-selectors",
510 selectors: [escapeCSS(element.localName) + '[style=' + quote(style) + ']']
511 },
512
513 function(response)
514 {
515 callback(filters.concat(response.filters), selectors.concat(response.s electors));
516 }
517 );
518 }
519 else
520 callback(filters, selectors);
521 }
522
523 function addElemHideFilter(filters, selectors)
524 {
525 if (selectors.length > 0)
526 {
527 ext.backgroundPage.sendMessage(
528 {
529 type: "get-filters-from-selectors",
530 selectors: selectors
531 },
532
533 function(response)
534 {
535 addStyleAttributeFilter(filters.concat(response.filters), response.sel ectors);
536 }
537 );
538 }
539 else
540 addStyleAttributeFilter(filters, selectors);
541 }
542
543 var filters = [];
544 var selectors = [];
545
546 if (element.id)
547 selectors.push("#" + escapeCSS(element.id));
548
549 if (element.classList.length > 0)
550 {
551 var selector = "";
552
553 for (var i = 0; i < element.classList.length; i++)
554 selector += "." + escapeCSS(element.classList[i]);
555
556 selectors.push(selector);
557 }
558
559 var urls = getURLsFromElement(element);
560 if (urls.length > 0)
561 {
562 ext.backgroundPage.sendMessage(
563 {
564 type: "check-whitelisted-urls",
565 mediatype: typeMap[element.localName],
566 urls: urls
567 },
568
569 function(whitelisted)
570 {
571 for (var i = 0; i < urls.length; i++)
572 {
573 var url = urls[i];
574
575 if (!whitelisted[url] && /^https?:/i.test(url))
576 {
577 var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||");
578
579 if (filters.indexOf(filter) == -1)
580 filters.push(filter);
581
582 continue;
583 }
584
585 if (url == element.src)
586 {
587 var selector = escapeCSS(element.localName) + '[src=' + quote(elemen t.getAttribute("src")) + ']';
588
589 if (selectors.indexOf(selector) == -1)
590 selectors.push(selector);
591 }
592 }
593
594 addElemHideFilter(filters, selectors);
595 }
596 );
597 }
598 else
599 addElemHideFilter(filters, selectors);
600 }
601
497 // When the user clicks, the currentElement is the one we want. 602 // When the user clicks, the currentElement is the one we want.
498 // We should have ABP rules ready for when the 603 // We should have ABP rules ready for when the
499 // popup asks for them. 604 // popup asks for them.
500 function clickHide_mouseClick(e) 605 function clickHide_mouseClick(e)
501 { 606 {
502 if (!currentElement || !clickHide_activated) 607 if (!currentElement || !clickHide_activated)
503 return; 608 return;
504 609
505 var elt = currentElement; 610 var elt = currentElement;
506 if (currentElement.classList.contains("__adblockplus__overlay")) 611 if (currentElement.classList.contains("__adblockplus__overlay"))
507 elt = currentElement.prisoner; 612 elt = currentElement.prisoner;
508 613
509 clickHideFilters = new Array(); 614 generateFilters(elt, function(filters, selectors)
510 selectorList = new Array(); 615 {
616 clickHide_showDialog(e.clientX, e.clientY, filters);
511 617
512 var addSelector = function(selector) 618 // Highlight the elements specified by selector in yellow
513 { 619 if (selectors.length > 0)
514 if (selectorList.indexOf(selector) != -1) 620 highlightElements(selectors.join(","));
515 return;
516 621
517 clickHideFilters.push(document.domain + "##" + selector); 622 // Now, actually highlight the element the user clicked on in red
518 selectorList.push(selector); 623 highlightElement(currentElement, "#fd1708", "#f6a1b5");
519 }; 624 });
520
521 if (elt.id)
522 addSelector("#" + escapeCSS(elt.id));
523
524 if (elt.classList.length > 0)
525 {
526 var selector = "";
527
528 for (var i = 0; i < elt.classList.length; i++)
529 selector += "." + escapeCSS(elt.classList[i]);
530
531 addSelector(selector);
532 }
533
534 var urls = getURLsFromElement(elt);
535 for (var i = 0; i < urls.length; i++)
536 {
537 var url = urls[i];
538
539 if (/^https?:/i.test(url))
540 {
541 var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||");
542
543 if (clickHideFilters.indexOf(filter) == -1)
544 clickHideFilters.push(filter);
545
546 continue;
547 }
548
549 if (url == elt.src)
550 addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("s rc")) + ']');
551 }
552
553 // as last resort, create a filter based on inline styles
554 if (clickHideFilters.length == 0)
555 {
556 var style = getOriginalStyle(elt);
557 if (style)
558 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']');
559 }
560
561 // Show popup
562 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters);
563
564 // Highlight the elements specified by selector in yellow
565 if (selectorList.length > 0)
566 highlightElements(selectorList.join(","));
567 // Now, actually highlight the element the user clicked on in red
568 highlightElement(currentElement, "#fd1708", "#f6a1b5");
569 625
570 // Make sure the browser doesn't handle this click 626 // Make sure the browser doesn't handle this click
571 e.preventDefault(); 627 e.preventDefault();
572 e.stopPropagation(); 628 e.stopPropagation();
573 } 629 }
574 630
575 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js 631 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js
576 // and licensed under the MIT license. See jquery-*.min.js for details. 632 // and licensed under the MIT license. See jquery-*.min.js for details.
577 function removeDotSegments(u) { 633 function removeDotSegments(u) {
578 var r = '', m = []; 634 var r = '', m = [];
(...skipping 106 matching lines...) Expand 10 before | Expand all | Expand 10 after
685 break; 741 break;
686 case "clickhide-activate": 742 case "clickhide-activate":
687 clickHide_activate(); 743 clickHide_activate();
688 break; 744 break;
689 case "clickhide-deactivate": 745 case "clickhide-deactivate":
690 clickHide_deactivate(); 746 clickHide_deactivate();
691 break; 747 break;
692 case "clickhide-new-filter": 748 case "clickhide-new-filter":
693 if(lastRightClickEvent) 749 if(lastRightClickEvent)
694 { 750 {
695 clickHide_activated = true; 751 var event = lastRightClickEvent;
696 currentElement = addElementOverlay(lastRightClickEvent.target); 752
697 clickHide_mouseClick(lastRightClickEvent); 753 addElementOverlay(event.target, function(overlay)
754 {
755 clickHide_activated = true;
756 currentElement = overlay;
757 clickHide_mouseClick(event);
758 });
698 } 759 }
699 break; 760 break;
700 case "clickhide-init": 761 case "clickhide-init":
701 if (clickHideFiltersDialog) 762 if (clickHideFiltersDialog)
702 { 763 {
703 sendResponse({filters: clickHide_filters}); 764 sendResponse({filters: clickHide_filters});
704 765
705 clickHideFiltersDialog.style.width = msg.width + "px"; 766 clickHideFiltersDialog.style.width = msg.width + "px";
706 clickHideFiltersDialog.style.height = msg.height + "px"; 767 clickHideFiltersDialog.style.height = msg.height + "px";
707 clickHideFiltersDialog.style.visibility = "visible"; 768 clickHideFiltersDialog.style.visibility = "visible";
(...skipping 18 matching lines...) Expand all
726 break; 787 break;
727 default: 788 default:
728 sendResponse({}); 789 sendResponse({});
729 break; 790 break;
730 } 791 }
731 }); 792 });
732 793
733 if (window == window.top) 794 if (window == window.top)
734 ext.backgroundPage.sendMessage({type: "report-html-page"}); 795 ext.backgroundPage.sendMessage({type: "report-html-page"});
735 } 796 }
OLDNEW
« no previous file with comments | « background.js ('k') | include.preload.js » ('j') | include.preload.js » ('J')

Powered by Google App Engine
This is Rietveld