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

Delta Between Two Patch Sets: include.postload.js

Issue 5225119261655040: Issue 1282 - Don't generate filters conflicting with existing exception rules (Closed)
Left Patch Set: Rebased Created Jan. 25, 2015, 1:23 p.m.
Right Patch Set: Addressed comment Created March 3, 2015, 2:59 p.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « background.js ('k') | include.preload.js » ('j') | lib/filterComposer.js » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-2015 Eyeo GmbH 3 * Copyright (C) 2006-2015 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
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 17
18 // Click-to-hide stuff 18 // Click-to-hide stuff
19 var clickHide_activated = false; 19 var clickHide_activated = false;
20 var clickHide_filters = null; 20 var clickHide_filters = null;
21 var currentElement = null; 21 var currentElement = null;
22 var highlightedElementsSelector = null; 22 var highlightedElementsSelector = null;
23 var clickHideFiltersDialog = null; 23 var clickHideFiltersDialog = null;
24 var lastRightClickEvent = null; 24 var lastRightClickEvent = null;
25 var lastRightClickEventValid = false; 25 var lastRightClickEventValid = false;
26 var lastMouseOverEvent = null;
26 27
27 function highlightElement(element, shadowColor, backgroundColor) 28 function highlightElement(element, shadowColor, backgroundColor)
28 { 29 {
29 unhighlightElement(element); 30 unhighlightElement(element);
30 31
31 var highlightWithOverlay = function() 32 var highlightWithOverlay = function()
32 { 33 {
33 var overlay = addElementOverlay(element); 34 var overlay = addElementOverlay(element);
35
36 // If the element isn't displayed no overlay will be added.
37 // Moreover, we don't need to highlight anything then.
38 if (!overlay)
39 return;
34 40
35 highlightElement(overlay, shadowColor, backgroundColor); 41 highlightElement(overlay, shadowColor, backgroundColor);
36 overlay.style.pointerEvents = "none"; 42 overlay.style.pointerEvents = "none";
37 43
38 element._unhighlight = function() 44 element._unhighlight = function()
39 { 45 {
40 overlay.parentNode.removeChild(overlay); 46 overlay.parentNode.removeChild(overlay);
41 }; 47 };
42 }; 48 };
43 49
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after
186 192
187 case "video": 193 case "video":
188 case "audio": 194 case "audio":
189 case "picture": 195 case "picture":
190 return getURLsFromMediaElement(element); 196 return getURLsFromMediaElement(element);
191 } 197 }
192 198
193 return getURLsFromAttributes(element); 199 return getURLsFromAttributes(element);
194 } 200 }
195 201
196 // Gets the absolute position of an element by walking up the DOM tree,
197 // adding up offsets.
198 // I hope there's a better way because it just seems absolutely stupid
199 // that the DOM wouldn't have a direct way to get this, given that it
200 // has hundreds and hundreds of other methods that do random junk.
201 function getAbsolutePosition(elt) {
202 var l = 0;
203 var t = 0;
204 for(; elt; elt = elt.offsetParent) {
205 l += elt.offsetLeft;
206 t += elt.offsetTop;
207 }
208 return [l, t];
209 }
210
211 // Adds an overlay to an element, which is probably a Flash object 202 // Adds an overlay to an element, which is probably a Flash object
212 function addElementOverlay(elt) { 203 function addElementOverlay(elt) {
213 var zIndex = "auto"; 204 var zIndex = "auto";
214 var position = "absolute"; 205 var position = "absolute";
215 206
216 for (var e = elt; e; e = e.parentElement) 207 for (var e = elt; e; e = e.parentElement)
217 { 208 {
218 var style = getComputedStyle(e); 209 var style = getComputedStyle(e);
219 210
220 // If the element isn't rendered (since its or one of its ancestor's 211 // If the element isn't rendered (since its or one of its ancestor's
221 // "display" property is "none"), the overlay wouldn't match the element. 212 // "display" property is "none"), the overlay wouldn't match the element.
222 if (style.display == "none") 213 if (style.display == "none")
223 return null; 214 return null;
224 215
225 // If the element or one of its ancestors uses fixed postioning, the overlay 216 // If the element or one of its ancestors uses fixed postioning, the overlay
226 // has to use fixed postioning too. Otherwise it might not match the element . 217 // has to use fixed postioning too. Otherwise it might not match the element .
227 if (style.position == "fixed") 218 if (style.position == "fixed")
228 position = "fixed"; 219 position = "fixed";
229 220
230 // Determine the effective z-index, which is the highest z-index used 221 // Determine the effective z-index, which is the highest z-index used
231 // by the element and its offset ancestors. When using a lower z-index 222 // by the element and its offset ancestors, and increase it by one.
232 // the element would cover the overlay. When using a higher z-index the 223 // When using a lower z-index the element would cover the overlay.
233 // overlay might also cover other elements. 224 // When using a higher z-index the overlay might also cover other elements.
234 if (style.position != "static" && style.zIndex != "auto") 225 if (style.position != "static" && style.zIndex != "auto")
235 { 226 {
236 if (zIndex == "auto") 227 var curZIndex = parseInt(style.zIndex, 10) + 1;
237 zIndex = style.zIndex; 228
238 else 229 if (zIndex == "auto" || curZIndex > zIndex)
239 zIndex = Math.max(zIndex, style.zIndex); 230 zIndex = curZIndex;
240 } 231 }
241 } 232 }
242 233
243 var overlay = document.createElement('div'); 234 var overlay = document.createElement('div');
244 overlay.prisoner = elt; 235 overlay.prisoner = elt;
245 overlay.className = "__adblockplus__overlay"; 236 overlay.className = "__adblockplus__overlay";
246 overlay.setAttribute('style', 'opacity:0.4; display:inline-box; overflow:hidde n; box-sizing:border-box;'); 237 overlay.setAttribute('style', 'opacity:0.4; display:inline-box; overflow:hidde n; box-sizing:border-box;');
247 var pos = getAbsolutePosition(elt); 238 var rect = elt.getBoundingClientRect();
248 overlay.style.width = elt.offsetWidth + "px"; 239 overlay.style.width = rect.width + "px";
249 overlay.style.height = elt.offsetHeight + "px"; 240 overlay.style.height = rect.height + "px";
250 overlay.style.left = pos[0] + "px"; 241 overlay.style.left = (rect.left + window.scrollX) + "px";
251 overlay.style.top = pos[1] + "px"; 242 overlay.style.top = (rect.top + window.scrollY) + "px";
252 overlay.style.position = position; 243 overlay.style.position = position;
253 overlay.style.zIndex = zIndex; 244 overlay.style.zIndex = zIndex;
254 245
255 // elt.parentNode.appendChild(overlay, elt); 246 // elt.parentNode.appendChild(overlay, elt);
256 document.body.appendChild(overlay); 247 document.documentElement.appendChild(overlay);
257 return overlay; 248 return overlay;
258 } 249 }
259 250
260 // Show dialog asking user whether she wants to add the proposed filters derived 251 // Show dialog asking user whether she wants to add the proposed filters derived
261 // from selected page element 252 // from selected page element
262 function clickHide_showDialog(left, top, filters) 253 function clickHide_showDialog(left, top, filters)
263 { 254 {
264 // If we are already selecting, abort now 255 // If we are already selecting, abort now
265 if (clickHide_activated || clickHideFiltersDialog) 256 if (clickHide_activated || clickHideFiltersDialog)
266 clickHide_deactivate(true); 257 clickHide_deactivate(true);
(...skipping 16 matching lines...) Expand all
283 { 274 {
284 if (clickHideFiltersDialog) 275 if (clickHideFiltersDialog)
285 clickHideFiltersDialog.style.setProperty("opacity", "0.7"); 276 clickHideFiltersDialog.style.setProperty("opacity", "0.7");
286 }; 277 };
287 clickHideFiltersDialog.onmouseover = function() 278 clickHideFiltersDialog.onmouseover = function()
288 { 279 {
289 if (clickHideFiltersDialog) 280 if (clickHideFiltersDialog)
290 clickHideFiltersDialog.style.setProperty("opacity", "1.0"); 281 clickHideFiltersDialog.style.setProperty("opacity", "1.0");
291 }; 282 };
292 283
293 document.body.appendChild(clickHideFiltersDialog); 284 document.documentElement.appendChild(clickHideFiltersDialog);
294 } 285 }
295 286
296 // Turn on the choose element to create filter thing 287 // Turn on the choose element to create filter thing
297 function clickHide_activate() { 288 function clickHide_activate() {
298 if(document == null) 289 if(document == null)
299 return; 290 return;
300 291
301 // If we are already selecting, abort now 292 // If we are already selecting, abort now
302 if (clickHide_activated || clickHideFiltersDialog) 293 if (clickHide_activated || clickHideFiltersDialog)
303 clickHide_deactivate(); 294 clickHide_deactivate();
304 295
305 // Add overlays for blockable elements that don't emit mouse events that they can still be selected 296 // Add overlays for blockable elements that don't emit mouse events,
297 // so that they can still be selected.
306 [].forEach.call( 298 [].forEach.call(
307 document.querySelectorAll('object,embed,iframe'), 299 document.querySelectorAll('object,embed,iframe,frame'),
308 function(element) 300 function(element)
309 { 301 {
310 getFiltersForElement(element, function(filters) 302 getFiltersForElement(element, function(filters)
311 { 303 {
312 if (filters.length > 0) 304 if (filters.length > 0)
313 addElementOverlay(element); 305 addElementOverlay(element);
314 }); 306 });
315 } 307 }
316 ); 308 );
317 309
318 clickHide_activated = true; 310 clickHide_activated = true;
311 document.addEventListener("mousedown", clickHide_stopPropagation, true);
312 document.addEventListener("mouseup", clickHide_stopPropagation, true);
313 document.addEventListener("mouseenter", clickHide_stopPropagation, true);
314 document.addEventListener("mouseleave", clickHide_stopPropagation, true);
319 document.addEventListener("mouseover", clickHide_mouseOver, true); 315 document.addEventListener("mouseover", clickHide_mouseOver, true);
320 document.addEventListener("mouseout", clickHide_mouseOut, true); 316 document.addEventListener("mouseout", clickHide_mouseOut, true);
321 document.addEventListener("click", clickHide_mouseClick, true); 317 document.addEventListener("click", clickHide_mouseClick, true);
322 document.addEventListener("keydown", clickHide_keyDown, true); 318 document.addEventListener("keydown", clickHide_keyDown, true);
319
320 ext.onExtensionUnloaded.addListener(clickHide_deactivate);
323 } 321 }
324 322
325 // Called when user has clicked on something and we are waiting for confirmation 323 // Called when user has clicked on something and we are waiting for confirmation
326 // on whether the user actually wants these filters 324 // on whether the user actually wants these filters
327 function clickHide_rulesPending() { 325 function clickHide_rulesPending() {
328 clickHide_activated = false; 326 clickHide_activated = false;
327 document.removeEventListener("mousedown", clickHide_stopPropagation, true);
328 document.removeEventListener("mouseup", clickHide_stopPropagation, true);
329 document.removeEventListener("mouseenter", clickHide_stopPropagation, true);
330 document.removeEventListener("mouseleave", clickHide_stopPropagation, true);
329 document.removeEventListener("mouseover", clickHide_mouseOver, true); 331 document.removeEventListener("mouseover", clickHide_mouseOver, true);
330 document.removeEventListener("mouseout", clickHide_mouseOut, true); 332 document.removeEventListener("mouseout", clickHide_mouseOut, true);
331 document.removeEventListener("click", clickHide_mouseClick, true); 333 document.removeEventListener("click", clickHide_mouseClick, true);
332 document.removeEventListener("keydown", clickHide_keyDown, true); 334 document.removeEventListener("keydown", clickHide_keyDown, true);
333 } 335 }
334 336
335 // Turn off click-to-hide 337 // Turn off click-to-hide
336 function clickHide_deactivate(keepOverlays) 338 function clickHide_deactivate(keepOverlays)
337 { 339 {
338 if (clickHideFiltersDialog) 340 if (clickHideFiltersDialog)
339 { 341 {
340 document.body.removeChild(clickHideFiltersDialog); 342 document.documentElement.removeChild(clickHideFiltersDialog);
341 clickHideFiltersDialog = null; 343 clickHideFiltersDialog = null;
342 } 344 }
343 345
344 clickHide_activated = false; 346 clickHide_activated = false;
345 clickHide_filters = null; 347 clickHide_filters = null;
346 if(!document) 348 if(!document)
347 return; // This can happen inside a nuked iframe...I think 349 return; // This can happen inside a nuked iframe...I think
350
351 document.removeEventListener("mousedown", clickHide_stopPropagation, true);
352 document.removeEventListener("mouseup", clickHide_stopPropagation, true);
353 document.removeEventListener("mouseenter", clickHide_stopPropagation, true);
354 document.removeEventListener("mouseleave", clickHide_stopPropagation, true);
348 document.removeEventListener("mouseover", clickHide_mouseOver, true); 355 document.removeEventListener("mouseover", clickHide_mouseOver, true);
349 document.removeEventListener("mouseout", clickHide_mouseOut, true); 356 document.removeEventListener("mouseout", clickHide_mouseOut, true);
350 document.removeEventListener("click", clickHide_mouseClick, true); 357 document.removeEventListener("click", clickHide_mouseClick, true);
351 document.removeEventListener("keydown", clickHide_keyDown, true); 358 document.removeEventListener("keydown", clickHide_keyDown, true);
352 359
353 if (!keepOverlays) 360 if (keepOverlays !== true)
354 { 361 {
355 lastRightClickEvent = null; 362 lastRightClickEvent = null;
356 363
357 if (currentElement) { 364 if (currentElement) {
358 currentElement.removeEventListener("contextmenu", clickHide_elementClickH andler, true); 365 currentElement.removeEventListener("contextmenu", clickHide_elementClickH andler, true);
359 unhighlightElements(); 366 unhighlightElements();
360 unhighlightElement(currentElement); 367 unhighlightElement(currentElement);
361 currentElement = null; 368 currentElement = null;
362 } 369 }
363 unhighlightElements(); 370 unhighlightElements();
364 371
365 var overlays = document.getElementsByClassName("__adblockplus__overlay"); 372 var overlays = document.getElementsByClassName("__adblockplus__overlay");
366 while (overlays.length > 0) 373 while (overlays.length > 0)
367 overlays[0].parentNode.removeChild(overlays[0]); 374 overlays[0].parentNode.removeChild(overlays[0]);
368 } 375
369 } 376 ext.onExtensionUnloaded.removeListener(clickHide_deactivate);
370 377 }
371 function clickHide_elementClickHandler(ev) { 378 }
372 ev.preventDefault(); 379
373 ev.stopPropagation(); 380 function clickHide_stopPropagation(e)
374 clickHide_mouseClick(ev); 381 {
382 e.stopPropagation();
383 }
384
385 function clickHide_elementClickHandler(e) {
386 e.preventDefault();
387 e.stopPropagation();
388 clickHide_mouseClick(e);
375 } 389 }
376 390
377 function getBlockableElementOrAncestor(element, callback) 391 function getBlockableElementOrAncestor(element, callback)
378 { 392 {
379 if (element && element != document.documentElement && 393 // We assume that the user doesn't want to block the whole page.
380 element != document.body) 394 // So we never consider the <html> or <body> element.
381 { 395 while (element && element != document.documentElement
382 if (element instanceof HTMLElement) 396 && element != document.body)
397 {
398 // We can't handle non-HTML (like SVG) elements, as well as
399 // <area> elements (see below). So fall back to the parent element.
400 if (!(element instanceof HTMLElement) || element.localName == "area")
401 element = element.parentElement;
402
403 // If image maps are used mouse events occur for the <area> element.
404 // But we have to block the image associated with the <map> element.
405 else if (element.localName == "map")
406 {
407 var images = document.querySelectorAll("img[usemap]");
408 var image = null;
409
410 for (var i = 0; i < images.length; i++)
411 {
412 var usemap = image.getAttribute("usemap");
413 var index = usemap.indexOf("#");
414
415 if (index != -1 && usemap.substr(index + 1) == element.name)
416 {
417 image = images[i];
418 break;
419 }
420 }
421
422 element = image;
423 }
424
425 // Finally, if none of the above is true, check whether we can generate
426 // any filters for this element. Otherwise fall back to its parent element.
427 else
383 { 428 {
384 getFiltersForElement(element, function(filters) 429 getFiltersForElement(element, function(filters)
385 { 430 {
386 if (filters.length > 0) 431 if (filters.length > 0)
387 callback(element); 432 callback(element);
388 else 433 else
389 getBlockableElementOrAncestor(element.parentElement, callback); 434 getBlockableElementOrAncestor(element.parentElement, callback);
390 }); 435 });
391 } 436
392 else 437 return;
393 { 438 }
394 getBlockableElementOrAncestor(element.parentElement, callback); 439 }
395 } 440
396 } 441 // We reached the document root without finding a blockable element.
397 else 442 callback(null);
398 {
399 callback(null);
400 }
401 } 443 }
402 444
403 // Hovering over an element so highlight it 445 // Hovering over an element so highlight it
404 function clickHide_mouseOver(e) 446 function clickHide_mouseOver(e)
405 { 447 {
406 if (clickHide_activated == false) 448 lastMouseOverEvent = e;
407 return;
408 449
409 getBlockableElementOrAncestor(e.target, function(element) 450 getBlockableElementOrAncestor(e.target, function(element)
410 { 451 {
411 if (currentElement) 452 if (e == lastMouseOverEvent)
412 unhighlightElement(currentElement); 453 {
413 454 lastMouseOverEvent = null;
414 if (element) 455
415 { 456 if (clickHide_activated)
416 highlightElement(element, "#d6d84b", "#f8fa47"); 457 {
417 element.addEventListener("contextmenu", clickHide_elementClickHandler, tru e); 458 if (currentElement)
418 } 459 unhighlightElement(currentElement);
419 460
420 currentElement = element; 461 if (element)
462 {
463 highlightElement(element, "#d6d84b", "#f8fa47");
464 element.addEventListener("contextmenu", clickHide_elementClickHandler, true);
465 }
466
467 currentElement = element;
468 }
469 }
421 }); 470 });
471
472 e.stopPropagation();
422 } 473 }
423 474
424 // No longer hovering over this element so unhighlight it 475 // No longer hovering over this element so unhighlight it
425 function clickHide_mouseOut(e) 476 function clickHide_mouseOut(e)
426 { 477 {
427 if (!clickHide_activated || currentElement != e.target) 478 if (!clickHide_activated || currentElement != e.target)
428 return; 479 return;
429 480
430 unhighlightElement(currentElement); 481 unhighlightElement(currentElement);
431 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, true); 482 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, true);
483 e.stopPropagation();
432 } 484 }
433 485
434 // Selects the currently hovered-over filter or cancels selection 486 // Selects the currently hovered-over filter or cancels selection
435 function clickHide_keyDown(e) 487 function clickHide_keyDown(e)
436 { 488 {
437 if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 13 /*DOM_VK_RETURN* /) 489 if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 13 /*DOM_VK_RETURN* /)
438 clickHide_mouseClick(e); 490 clickHide_mouseClick(e);
439 else if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 27 /*DOM_VK_ES CAPE*/) 491 else if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 27 /*DOM_VK_ES CAPE*/)
440 { 492 {
441 ext.backgroundPage.sendMessage( 493 ext.backgroundPage.sendMessage(
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
634 break; 686 break;
635 case "clickhide-activate": 687 case "clickhide-activate":
636 clickHide_activate(); 688 clickHide_activate();
637 break; 689 break;
638 case "clickhide-deactivate": 690 case "clickhide-deactivate":
639 clickHide_deactivate(); 691 clickHide_deactivate();
640 break; 692 break;
641 case "clickhide-new-filter": 693 case "clickhide-new-filter":
642 if(lastRightClickEvent) 694 if(lastRightClickEvent)
643 { 695 {
644 clickHide_activated = true; 696 getBlockableElementOrAncestor(lastRightClickEvent.target, function(ele ment)
645 currentElement = lastRightClickEvent.target; 697 {
646 clickHide_mouseClick(lastRightClickEvent); 698 clickHide_activated = true;
699 currentElement = element;
700 clickHide_mouseClick(lastRightClickEvent);
701 });
647 } 702 }
648 break; 703 break;
649 case "clickhide-init": 704 case "clickhide-init":
650 if (clickHideFiltersDialog) 705 if (clickHideFiltersDialog)
651 { 706 {
652 sendResponse({filters: clickHide_filters}); 707 sendResponse({filters: clickHide_filters});
653 708
654 clickHideFiltersDialog.style.width = msg.width + "px"; 709 clickHideFiltersDialog.style.width = msg.width + "px";
655 clickHideFiltersDialog.style.height = msg.height + "px"; 710 clickHideFiltersDialog.style.height = msg.height + "px";
656 clickHideFiltersDialog.style.visibility = "visible"; 711 clickHideFiltersDialog.style.visibility = "visible";
(...skipping 27 matching lines...) Expand all
684 lastRightClickEventValid = false; 739 lastRightClickEventValid = false;
685 else 740 else
686 lastRightClickEvent = null; 741 lastRightClickEvent = null;
687 break; 742 break;
688 } 743 }
689 }); 744 });
690 745
691 if (window == window.top) 746 if (window == window.top)
692 ext.backgroundPage.sendMessage({type: "report-html-page"}); 747 ext.backgroundPage.sendMessage({type: "report-html-page"});
693 } 748 }
LEFTRIGHT

Powered by Google App Engine
This is Rietveld