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: Simplified code Created Nov. 26, 2014, 1:55 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 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
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");
Wladimir Palant 2014/12/08 11:43:00 For reference: <object> also has archive and codeb
Sebastian Noack 2014/12/08 16:45:04 I agree, also note they are obsolete since HTML5,
Wladimir Palant 2014/12/08 20:31:09 Oh, you didn't have to deal with Java? :)
Sebastian Noack 2014/12/08 21:12:49 I see, that stuff is for Java. I prefer to ignore
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;
Wladimir Palant 2014/12/08 11:43:00 It seems that we need to handle <track> elements a
Sebastian Noack 2014/12/08 16:45:04 Done.
219
220 if (child.src)
221 urls.push(child.src);
222
223 urls = urls.concat(parseSrcSet(child));
Wladimir Palant 2014/12/08 11:43:00 Rather than generate a new array, I'd prefer: url
Sebastian Noack 2014/12/08 16:45:04 Right, I forgot that push() can add multiple items
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 281
205 // If the element isn't rendered (since its or one of its ancestor's 282 // If the element isn't rendered (since its or one of its ancestor's
206 // "diplay" property is "none"), the overlay wouldn't match the element. 283 // "diplay" property is "none"), the overlay wouldn't match the element.
207 if (!elt.offsetParent) 284 if (!elt.offsetParent)
208 return; 285 return;
209 286
210 var thisStyle = getComputedStyle(elt, null); 287 var thisStyle = getComputedStyle(elt, null);
211 var overlay = document.createElement('div'); 288 var overlay = document.createElement('div');
212 overlay.prisoner = elt; 289 overlay.prisoner = elt;
213 overlay.prisonerURL = url;
214 overlay.className = "__adblockplus__overlay"; 290 overlay.className = "__adblockplus__overlay";
215 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;'); 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;');
216 var pos = getAbsolutePosition(elt); 292 var pos = getAbsolutePosition(elt);
217 overlay.style.left = pos[0] + "px"; 293 overlay.style.left = pos[0] + "px";
218 overlay.style.top = pos[1] + "px"; 294 overlay.style.top = pos[1] + "px";
219 295
220 if (thisStyle.position != "static") 296 if (thisStyle.position != "static")
221 overlay.style.zIndex = thisStyle.zIndex; 297 overlay.style.zIndex = thisStyle.zIndex;
222 else 298 else
223 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; 299 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 // Turn on the choose element to create filter thing 346 // Turn on the choose element to create filter thing
271 function clickHide_activate() { 347 function clickHide_activate() {
272 if(document == null) 348 if(document == null)
273 return; 349 return;
274 350
275 // If we are already selecting, abort now 351 // If we are already selecting, abort now
276 if (clickHide_activated || clickHideFiltersDialog) 352 if (clickHide_activated || clickHideFiltersDialog)
277 clickHide_deactivate(); 353 clickHide_deactivate();
278 354
279 // Add overlays for elements with URLs so user can easily click them 355 // Add overlays for elements with URLs so user can easily click them
280 var elts = document.querySelectorAll('object,embed,img,iframe'); 356 var elts = document.querySelectorAll('object,embed,img,iframe,video,audio,pict ure');
281 for(var i=0; i<elts.length; i++) 357 for(var i=0; i<elts.length; i++)
282 addElementOverlay(elts[i]); 358 addElementOverlay(elts[i]);
283 359
284 clickHide_activated = true; 360 clickHide_activated = true;
285 document.addEventListener("mouseover", clickHide_mouseOver, true); 361 document.addEventListener("mouseover", clickHide_mouseOver, true);
286 document.addEventListener("mouseout", clickHide_mouseOut, true); 362 document.addEventListener("mouseout", clickHide_mouseOut, true);
287 document.addEventListener("click", clickHide_mouseClick, true); 363 document.addEventListener("click", clickHide_mouseClick, true);
288 document.addEventListener("keydown", clickHide_keyDown, true); 364 document.addEventListener("keydown", clickHide_keyDown, true);
289 } 365 }
290 366
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
338 clickHide_mouseClick(ev); 414 clickHide_mouseClick(ev);
339 } 415 }
340 416
341 // Hovering over an element so highlight it 417 // Hovering over an element so highlight it
342 function clickHide_mouseOver(e) 418 function clickHide_mouseOver(e)
343 { 419 {
344 if (clickHide_activated == false) 420 if (clickHide_activated == false)
345 return; 421 return;
346 422
347 var target = e.target; 423 var target = e.target;
348 while (target.parentNode && !(target.id || target.className || target.src || / :.+:/.test(target.getAttribute("style")))) 424 while (target.parentNode && !isBlockable(target))
349 target = target.parentNode; 425 target = target.parentNode;
350 if (target == document.documentElement || target == document.body) 426 if (target == document.documentElement || target == document.body)
351 target = null; 427 target = null;
352 428
353 if (target && target instanceof HTMLElement) 429 if (target && target instanceof HTMLElement)
354 { 430 {
355 currentElement = target; 431 currentElement = target;
356 432
357 highlightElement(target, "#d6d84b", "#f8fa47"); 433 highlightElement(target, "#d6d84b", "#f8fa47");
358 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); 434 target.addEventListener("contextmenu", clickHide_elementClickHandler, true);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
391 467
392 // When the user clicks, the currentElement is the one we want. 468 // When the user clicks, the currentElement is the one we want.
393 // We should have ABP rules ready for when the 469 // We should have ABP rules ready for when the
394 // popup asks for them. 470 // popup asks for them.
395 function clickHide_mouseClick(e) 471 function clickHide_mouseClick(e)
396 { 472 {
397 if (!currentElement || !clickHide_activated) 473 if (!currentElement || !clickHide_activated)
398 return; 474 return;
399 475
400 var elt = currentElement; 476 var elt = currentElement;
401 var url = null;
402 if (currentElement.classList.contains("__adblockplus__overlay")) 477 if (currentElement.classList.contains("__adblockplus__overlay"))
403 {
404 elt = currentElement.prisoner; 478 elt = currentElement.prisoner;
405 url = currentElement.prisonerURL;
406 }
407 else if (elt.src)
408 url = elt.src;
409 479
410 clickHideFilters = new Array(); 480 clickHideFilters = new Array();
411 selectorList = new Array(); 481 selectorList = new Array();
412 482
413 var addSelector = function(selector) 483 var addSelector = function(selector)
414 { 484 {
485 if (selectorList.indexOf(selector) != -1)
486 return;
487
415 clickHideFilters.push(document.domain + "##" + selector); 488 clickHideFilters.push(document.domain + "##" + selector);
416 selectorList.push(selector); 489 selectorList.push(selector);
417 }; 490 };
418 491
419 if (elt.id) 492 if (elt.id)
420 addSelector("#" + escapeCSS(elt.id)); 493 addSelector("#" + escapeCSS(elt.id));
421 494
422 if (elt.classList.length > 0) 495 if (elt.classList.length > 0)
423 { 496 {
424 var selector = ""; 497 var selector = "";
425 498
426 for (var i = 0; i < elt.classList.length; i++) 499 for (var i = 0; i < elt.classList.length; i++)
427 selector += "." + escapeCSS(elt.classList[i]); 500 selector += "." + escapeCSS(elt.classList[i]);
428 501
429 addSelector(selector); 502 addSelector(selector);
430 } 503 }
431 504
432 if (url) 505 var urls = getElementURLs(elt);
506 for (var i = 0; i < urls.length; i++)
433 { 507 {
434 var src = elt.getAttribute("src"); 508 var url = urls[i];
435 var selector = src && escapeCSS(elt.localName) + '[src=' + quote(src) + ']';
436 509
Sebastian Noack 2014/11/26 14:01:22 A fair amount of complexity here, only came from g
437 if (/^https?:/i.test(url)) 510 if (/^https?:/i.test(url))
438 { 511 {
439 clickHideFilters.push(url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||")); 512 var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||");
440 513
441 if (selector) 514 if (clickHideFilters.indexOf(filter) == -1)
442 selectorList.push(selector); 515 clickHideFilters.push(filter);
516
517 continue;
443 } 518 }
444 else if (selector) 519
445 addSelector(selector); 520 if (url == elt.src)
521 addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("s rc")) + ']');
446 } 522 }
447 523
448 // restore the original style, before generating the fallback filter that 524 // restore the original style, before generating the fallback filter that
449 // will include the style, and to prevent highlightElements from saving those 525 // will include the style, and to prevent highlightElements from saving those
450 unhighlightElement(currentElement); 526 unhighlightElement(currentElement);
451 527
452 // as last resort, create a filter based on inline styles 528 // as last resort, create a filter based on inline styles
453 if (clickHideFilters.length == 0) 529 if (clickHideFilters.length == 0)
454 { 530 {
455 var style = elt.getAttribute("style"); 531 var style = elt.getAttribute("style");
456 if (style) 532 if (style)
457 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']'); 533 addSelector(escapeCSS(elt.localName) + '[style=' + quote(style) + ']');
458 } 534 }
459 535
460 // Show popup 536 // Show popup
461 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); 537 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters);
462 538
463 // Highlight the elements specified by selector in yellow 539 // Highlight the elements specified by selector in yellow
464 highlightElements(selectorList.join(",")); 540 highlightElements(selectorList.join(","));
465 // Now, actually highlight the element the user clicked on in red 541 // Now, actually highlight the element the user clicked on in red
466 highlightElement(currentElement, "#fd1708", "#f6a1b5"); 542 highlightElement(currentElement, "#fd1708", "#f6a1b5");
467 543
468 // Make sure the browser doesn't handle this click 544 // Make sure the browser doesn't handle this click
469 e.preventDefault(); 545 e.preventDefault();
470 e.stopPropagation(); 546 e.stopPropagation();
471 } 547 }
472 548
473 // Extracts source URL from an IMG, OBJECT, EMBED, or IFRAME 549 function parseSrcSet(element)
474 function getElementURL(elt) { 550 {
475 // Check children of object nodes for "param" nodes with name="movie" that spe cify a URL 551 if (!element.srcset)
476 // in value attribute 552 return [];
477 var url;
478 if(elt.localName.toUpperCase() == "OBJECT" && !(url = elt.getAttribute("data") )) {
479 // No data attribute, look in PARAM child tags for a URL for the swf file
480 var params = elt.querySelectorAll("param[name=\"movie\"]");
481 // This OBJECT could contain an EMBED we already nuked, in which case there' s no URL
482 if(params[0])
483 url = params[0].getAttribute("value");
484 else {
485 params = elt.querySelectorAll("param[name=\"src\"]");
486 if(params[0])
487 url = params[0].getAttribute("value");
488 }
489 553
554 var urls = element.srcset.split(",");
555 for (var i = 0; i < urls.length; i++)
556 {
557 var url = urls[i].replace(/^\s+/, "").replace(/(\s+\S+)?\s*$/, "");
Wladimir Palant 2014/12/08 11:43:00 Use urls[i].trim()? According to http://kangax.git
Sebastian Noack 2014/12/08 16:45:04 Done.
490 if (url) 558 if (url)
491 url = resolveURL(url); 559 urls[i] = resolveURL(url);
Wladimir Palant 2014/12/08 11:43:00 What about descriptions? See http://html5hub.com/s
Sebastian Noack 2014/12/08 16:45:04 Those are stripped by the regex above.
492 } else if(!url) { 560 else
493 url = elt.src || elt.href; 561 urls.splice(i--, 1);
494 } 562 }
495 return url; 563
564 return urls;
496 } 565 }
497 566
498 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js 567 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js
499 // and licensed under the MIT license. See jquery-*.min.js for details. 568 // and licensed under the MIT license. See jquery-*.min.js for details.
500 function removeDotSegments(u) { 569 function removeDotSegments(u) {
501 var r = '', m = []; 570 var r = '', m = [];
502 if (/\./.test(u)) { 571 if (/\./.test(u)) {
503 while (u !== undefined && u !== '') { 572 while (u !== undefined && u !== '') {
504 if (u === '.' || u === '..') { 573 if (u === '.' || u === '..') {
505 u = ''; 574 u = '';
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
686 break; 755 break;
687 default: 756 default:
688 sendResponse({}); 757 sendResponse({});
689 break; 758 break;
690 } 759 }
691 }); 760 });
692 761
693 if (window == window.top) 762 if (window == window.top)
694 ext.backgroundPage.sendMessage({type: "report-html-page"}); 763 ext.backgroundPage.sendMessage({type: "report-html-page"});
695 } 764 }
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