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

Side by Side Diff: include.postload.js

Issue 5468762555809792: Issue 1601 - Generate blocking filters for all URLs associated with the selected element (Closed)
Patch Set: Rebased, addressed comments, and restructured code Created Dec. 8, 2014, 4:43 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
178 { 178 {
179 Array.prototype.forEach.call( 179 Array.prototype.forEach.call(
180 document.querySelectorAll(highlightedElementsSelector), 180 document.querySelectorAll(highlightedElementsSelector),
181 unhighlightElement 181 unhighlightElement
182 ); 182 );
183 183
184 highlightedElementsSelector = null; 184 highlightedElementsSelector = null;
185 } 185 }
186 } 186 }
187 187
188 function getURLsFromObjectElement(element)
189 {
190 var url = element.getAttribute("data");
191 if (url)
192 return [resolveURL(url)];
193
194 for (var i = 0; i < element.children.length; i++)
195 {
196 var child = element.children[i];
197 if (child.localName != "param")
198 continue;
199
200 var name = child.getAttribute("name");
201 if (name != "movie" && // Adobe Flash
202 name != "source" && // Silverlight
203 name != "src" && // Real Media + Quicktime
204 name != "FileName") // Windows Media
205 continue;
206
207 var value = child.getAttribute("value");
208 if (!value)
209 continue;
210
211 return [resolveURL(value)];
212 }
213
214 return [];
215 }
216
217 function getURLsFromAttributes(element)
218 {
219 var urls = [];
220
221 if (element.src)
222 urls.push(element.src);
223
224 if (element.srcset)
225 {
226 var candidates = element.srcset.split(",");
227 for (var i = 0; i < candidates.length; i++)
228 {
229 var url = candidates[i].trim().replace(/\s+\S+$/, "");
230 if (url)
231 urls.push(resolveURL(url));
232 }
233 }
234
235 return urls;
236 }
237
238 function getURLsFromMediaElement(element)
239 {
240 var urls = getURLsFromAttributes(element);
241
242 for (var i = 0; i < element.children.length; i++)
243 {
244 var child = element.children[i];
245 if (child.localName != "source" || child.localName != "track")
Wladimir Palant 2014/12/08 20:31:09 This should be == rather than !=, right? Currently
Sebastian Noack 2014/12/08 21:12:49 Ouch, you are right. Originally, it was in the for
246 urls.push.apply(urls, getURLsFromAttributes(child));
Wladimir Palant 2014/12/08 20:31:09 I think for the <track> element you need to call g
Sebastian Noack 2014/12/08 21:12:49 If I didn't misread the standard, a <track> elemen
Wladimir Palant 2014/12/09 08:27:21 It seems that I indeed misunderstood the standard,
247 }
248
249 if (element.poster)
250 urls.push(element.poster);
251
252 return urls;
253 }
254
255 function getURLsFromElement(element) {
256 switch (element.localName)
257 {
258 case "object":
259 return getURLsFromObjectElement(element);
260
261 case "video":
262 case "audio":
263 case "picture":
264 return getURLsFromMediaElement(element);
265 }
266
267 return getURLsFromAttributes(element);
268 }
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
188 // Gets the absolute position of an element by walking up the DOM tree, 288 // Gets the absolute position of an element by walking up the DOM tree,
189 // adding up offsets. 289 // adding up offsets.
190 // I hope there's a better way because it just seems absolutely stupid 290 // I hope there's a better way because it just seems absolutely stupid
191 // that the DOM wouldn't have a direct way to get this, given that it 291 // that the DOM wouldn't have a direct way to get this, given that it
192 // has hundreds and hundreds of other methods that do random junk. 292 // has hundreds and hundreds of other methods that do random junk.
193 function getAbsolutePosition(elt) { 293 function getAbsolutePosition(elt) {
194 var l = 0; 294 var l = 0;
195 var t = 0; 295 var t = 0;
196 for(; elt; elt = elt.offsetParent) { 296 for(; elt; elt = elt.offsetParent) {
197 l += elt.offsetLeft; 297 l += elt.offsetLeft;
198 t += elt.offsetTop; 298 t += elt.offsetTop;
199 } 299 }
200 return [l, t]; 300 return [l, t];
201 } 301 }
202 302
203 // Adds an overlay to an element, which is probably a Flash object 303 // Adds an overlay to an element, which is probably a Flash object
204 function addElementOverlay(elt) { 304 function addElementOverlay(elt) {
205 // If this element is enclosed in an object tag, we prefer to block that inste ad 305 // If this element is enclosed in an object tag, we prefer to block that inste ad
206 if(!elt) 306 if(!elt)
207 return null; 307 return null;
208 308
209 // If element doesn't have at least one of class name, ID or URL, give up 309 // If element doesn't have at least one of class name, ID or URL, give up
210 // because we don't know how to construct a filter rule for it 310 // because we don't know how to construct a filter rule for it
211 var url = getElementURL(elt); 311 if(!isBlockable(elt))
212 if(!elt.className && !elt.id && !url)
213 return; 312 return;
214 313
215 // If the element isn't rendered (since its or one of its ancestor's 314 // If the element isn't rendered (since its or one of its ancestor's
216 // "display" property is "none"), the overlay wouldn't match the element. 315 // "display" property is "none"), the overlay wouldn't match the element.
217 if (!elt.offsetParent) 316 if (!elt.offsetParent)
218 return; 317 return;
219 318
220 var thisStyle = getComputedStyle(elt, null); 319 var thisStyle = getComputedStyle(elt, null);
221 var overlay = document.createElement('div'); 320 var overlay = document.createElement('div');
222 overlay.prisoner = elt; 321 overlay.prisoner = elt;
223 overlay.prisonerURL = url;
224 overlay.className = "__adblockplus__overlay"; 322 overlay.className = "__adblockplus__overlay";
225 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;'); 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;');
226 var pos = getAbsolutePosition(elt); 324 var pos = getAbsolutePosition(elt);
227 overlay.style.left = pos[0] + "px"; 325 overlay.style.left = pos[0] + "px";
228 overlay.style.top = pos[1] + "px"; 326 overlay.style.top = pos[1] + "px";
229 327
230 if (thisStyle.position != "static") 328 if (thisStyle.position != "static")
231 overlay.style.zIndex = thisStyle.zIndex; 329 overlay.style.zIndex = thisStyle.zIndex;
232 else 330 else
233 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; 331 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 // Turn on the choose element to create filter thing 374 // Turn on the choose element to create filter thing
277 function clickHide_activate() { 375 function clickHide_activate() {
278 if(document == null) 376 if(document == null)
279 return; 377 return;
280 378
281 // If we are already selecting, abort now 379 // If we are already selecting, abort now
282 if (clickHide_activated || clickHideFiltersDialog) 380 if (clickHide_activated || clickHideFiltersDialog)
283 clickHide_deactivate(); 381 clickHide_deactivate();
284 382
285 // Add overlays for elements with URLs so user can easily click them 383 // Add overlays for elements with URLs so user can easily click them
286 var elts = document.querySelectorAll('object,embed,img,iframe'); 384 var elts = document.querySelectorAll('object,embed,img,iframe,video,audio,pict ure');
287 for(var i=0; i<elts.length; i++) 385 for(var i=0; i<elts.length; i++)
288 addElementOverlay(elts[i]); 386 addElementOverlay(elts[i]);
289 387
290 clickHide_activated = true; 388 clickHide_activated = true;
291 document.addEventListener("mouseover", clickHide_mouseOver, true); 389 document.addEventListener("mouseover", clickHide_mouseOver, true);
292 document.addEventListener("mouseout", clickHide_mouseOut, true); 390 document.addEventListener("mouseout", clickHide_mouseOut, true);
293 document.addEventListener("click", clickHide_mouseClick, true); 391 document.addEventListener("click", clickHide_mouseClick, true);
294 document.addEventListener("keydown", clickHide_keyDown, true); 392 document.addEventListener("keydown", clickHide_keyDown, true);
295 } 393 }
296 394
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
345 clickHide_mouseClick(ev); 443 clickHide_mouseClick(ev);
346 } 444 }
347 445
348 // Hovering over an element so highlight it 446 // Hovering over an element so highlight it
349 function clickHide_mouseOver(e) 447 function clickHide_mouseOver(e)
350 { 448 {
351 if (clickHide_activated == false) 449 if (clickHide_activated == false)
352 return; 450 return;
353 451
354 var target = e.target; 452 var target = e.target;
355 while (target.parentNode && !(target.id || target.className || target.src || / :.+:/.test(getOriginalStyle(target)))) 453 while (target.parentNode && !isBlockable(target))
356 target = target.parentNode; 454 target = target.parentNode;
357 if (target == document.documentElement || target == document.body) 455 if (target == document.documentElement || target == document.body)
358 target = null; 456 target = null;
359 457
360 if (target && target instanceof HTMLElement) 458 if (target && target instanceof HTMLElement)
361 { 459 {
362 currentElement = target; 460 currentElement = target;
363 461
364 highlightElement(target, "#d6d84b", "#f8fa47"); 462 highlightElement(target, "#d6d84b", "#f8fa47");
365 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); 463 target.addEventListener("contextmenu", clickHide_elementClickHandler, true);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 496
399 // When the user clicks, the currentElement is the one we want. 497 // When the user clicks, the currentElement is the one we want.
400 // We should have ABP rules ready for when the 498 // We should have ABP rules ready for when the
401 // popup asks for them. 499 // popup asks for them.
402 function clickHide_mouseClick(e) 500 function clickHide_mouseClick(e)
403 { 501 {
404 if (!currentElement || !clickHide_activated) 502 if (!currentElement || !clickHide_activated)
405 return; 503 return;
406 504
407 var elt = currentElement; 505 var elt = currentElement;
408 var url = null;
409 if (currentElement.classList.contains("__adblockplus__overlay")) 506 if (currentElement.classList.contains("__adblockplus__overlay"))
410 {
411 elt = currentElement.prisoner; 507 elt = currentElement.prisoner;
412 url = currentElement.prisonerURL;
413 }
414 else if (elt.src)
415 url = elt.src;
416 508
417 clickHideFilters = new Array(); 509 clickHideFilters = new Array();
418 selectorList = new Array(); 510 selectorList = new Array();
419 511
420 var addSelector = function(selector) 512 var addSelector = function(selector)
421 { 513 {
514 if (selectorList.indexOf(selector) != -1)
515 return;
516
422 clickHideFilters.push(document.domain + "##" + selector); 517 clickHideFilters.push(document.domain + "##" + selector);
423 selectorList.push(selector); 518 selectorList.push(selector);
424 }; 519 };
425 520
426 if (elt.id) 521 if (elt.id)
427 addSelector("#" + escapeCSS(elt.id)); 522 addSelector("#" + escapeCSS(elt.id));
428 523
429 if (elt.classList.length > 0) 524 if (elt.classList.length > 0)
430 { 525 {
431 var selector = ""; 526 var selector = "";
432 527
433 for (var i = 0; i < elt.classList.length; i++) 528 for (var i = 0; i < elt.classList.length; i++)
434 selector += "." + escapeCSS(elt.classList[i]); 529 selector += "." + escapeCSS(elt.classList[i]);
435 530
436 addSelector(selector); 531 addSelector(selector);
437 } 532 }
438 533
439 if (url) 534 var urls = getURLsFromElement(elt);
535 for (var i = 0; i < urls.length; i++)
440 { 536 {
441 var src = elt.getAttribute("src"); 537 var url = urls[i];
442 var selector = src && escapeCSS(elt.localName) + '[src=' + quote(src) + ']';
443 538
444 if (/^https?:/i.test(url)) 539 if (/^https?:/i.test(url))
445 { 540 {
446 clickHideFilters.push(url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||")); 541 var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||");
447 542
448 if (selector) 543 if (clickHideFilters.indexOf(filter) == -1)
449 selectorList.push(selector); 544 clickHideFilters.push(filter);
545
546 continue;
450 } 547 }
451 else if (selector) 548
452 addSelector(selector); 549 if (url == elt.src)
550 addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("s rc")) + ']');
453 } 551 }
454 552
455 // as last resort, create a filter based on inline styles 553 // as last resort, create a filter based on inline styles
456 if (clickHideFilters.length == 0) 554 if (clickHideFilters.length == 0)
457 { 555 {
458 var style = getOriginalStyle(elt); 556 var style = getOriginalStyle(elt);
459 if (style) 557 if (style)
460 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']'); 558 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']');
461 } 559 }
462 560
463 // Show popup 561 // Show popup
464 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); 562 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters);
465 563
466 // Highlight the elements specified by selector in yellow 564 // Highlight the elements specified by selector in yellow
467 if (selectorList.length > 0) 565 if (selectorList.length > 0)
468 highlightElements(selectorList.join(",")); 566 highlightElements(selectorList.join(","));
469 // Now, actually highlight the element the user clicked on in red 567 // Now, actually highlight the element the user clicked on in red
470 highlightElement(currentElement, "#fd1708", "#f6a1b5"); 568 highlightElement(currentElement, "#fd1708", "#f6a1b5");
471 569
472 // Make sure the browser doesn't handle this click 570 // Make sure the browser doesn't handle this click
473 e.preventDefault(); 571 e.preventDefault();
474 e.stopPropagation(); 572 e.stopPropagation();
475 } 573 }
476 574
477 // Extracts source URL from an IMG, OBJECT, EMBED, or IFRAME
478 function getElementURL(elt) {
479 // Check children of object nodes for "param" nodes with name="movie" that spe cify a URL
480 // in value attribute
481 var url;
482 if(elt.localName.toUpperCase() == "OBJECT" && !(url = elt.getAttribute("data") )) {
483 // No data attribute, look in PARAM child tags for a URL for the swf file
484 var params = elt.querySelectorAll("param[name=\"movie\"]");
485 // This OBJECT could contain an EMBED we already nuked, in which case there' s no URL
486 if(params[0])
487 url = params[0].getAttribute("value");
488 else {
489 params = elt.querySelectorAll("param[name=\"src\"]");
490 if(params[0])
491 url = params[0].getAttribute("value");
492 }
493
494 if (url)
495 url = resolveURL(url);
496 } else if(!url) {
497 url = elt.src || elt.href;
498 }
499 return url;
500 }
501
502 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js 575 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js
503 // and licensed under the MIT license. See jquery-*.min.js for details. 576 // and licensed under the MIT license. See jquery-*.min.js for details.
504 function removeDotSegments(u) { 577 function removeDotSegments(u) {
505 var r = '', m = []; 578 var r = '', m = [];
506 if (/\./.test(u)) { 579 if (/\./.test(u)) {
507 while (u !== undefined && u !== '') { 580 while (u !== undefined && u !== '') {
508 if (u === '.' || u === '..') { 581 if (u === '.' || u === '..') {
509 u = ''; 582 u = '';
510 } else if (/^\.\.\//.test(u)) { // starts with ../ 583 } else if (/^\.\.\//.test(u)) { // starts with ../
511 u = u.substring(3); 584 u = u.substring(3);
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
691 break; 764 break;
692 default: 765 default:
693 sendResponse({}); 766 sendResponse({});
694 break; 767 break;
695 } 768 }
696 }); 769 });
697 770
698 if (window == window.top) 771 if (window == window.top)
699 ext.backgroundPage.sendMessage({type: "report-html-page"}); 772 ext.backgroundPage.sendMessage({type: "report-html-page"});
700 } 773 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld