 Issue 4923599135703040:
  Issue 1610 - Don't remove overlays before the "Block element" dialog is closed  (Closed)
    
  
    Issue 4923599135703040:
  Issue 1610 - Don't remove overlays before the "Block element" dialog is closed  (Closed) 
  | Left: | ||
| Right: | 
| LEFT | RIGHT | 
|---|---|
| 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 if(!hasFilters(elt)) | 279 if(!isBlockable(elt)) | 
| 202 return; | 280 return; | 
| 281 | |
| 282 // If the element isn't rendered (since its or one of its ancestor's | |
| 283 // "diplay" property is "none"), the overlay wouldn't match the element. | |
| 284 if (!elt.offsetParent) | |
| 285 return; | |
| 286 | |
| 203 var thisStyle = getComputedStyle(elt, null); | 287 var thisStyle = getComputedStyle(elt, null); | 
| 204 var overlay = document.createElement('div'); | 288 var overlay = document.createElement('div'); | 
| 205 overlay.prisoner = elt; | 289 overlay.prisoner = elt; | 
| 206 overlay.className = "__adblockplus__overlay"; | 290 overlay.className = "__adblockplus__overlay"; | 
| 207 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'); | 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;'); | 
| 208 var pos = getAbsolutePosition(elt); | 292 var pos = getAbsolutePosition(elt); | 
| 209 overlay.style.left = pos[0] + "px"; | 293 overlay.style.left = pos[0] + "px"; | 
| 210 overlay.style.top = pos[1] + "px"; | 294 overlay.style.top = pos[1] + "px"; | 
| 295 | |
| 296 if (thisStyle.position != "static") | |
| 297 overlay.style.zIndex = thisStyle.zIndex; | |
| 298 else | |
| 299 overlay.style.zIndex = getComputedStyle(elt.offsetParent).zIndex; | |
| 300 | |
| 211 // elt.parentNode.appendChild(overlay, elt); | 301 // elt.parentNode.appendChild(overlay, elt); | 
| 212 document.body.appendChild(overlay); | 302 document.body.appendChild(overlay); | 
| 213 return overlay; | 303 return overlay; | 
| 214 } | 304 } | 
| 215 | 305 | 
| 216 // Show dialog asking user whether she wants to add the proposed filters derived | 306 // Show dialog asking user whether she wants to add the proposed filters derived | 
| 217 // from selected page element | 307 // from selected page element | 
| 218 function clickHide_showDialog(left, top, filters) | 308 function clickHide_showDialog(left, top, filters) | 
| 219 { | 309 { | 
| 220 // If we are already selecting, abort now | 310 // If we are already selecting, abort now | 
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 274 // on whether the user actually wants these filters | 364 // on whether the user actually wants these filters | 
| 275 function clickHide_rulesPending() { | 365 function clickHide_rulesPending() { | 
| 276 clickHide_activated = false; | 366 clickHide_activated = false; | 
| 277 document.removeEventListener("mouseover", clickHide_mouseOver, true); | 367 document.removeEventListener("mouseover", clickHide_mouseOver, true); | 
| 278 document.removeEventListener("mouseout", clickHide_mouseOut, true); | 368 document.removeEventListener("mouseout", clickHide_mouseOut, true); | 
| 279 document.removeEventListener("click", clickHide_mouseClick, true); | 369 document.removeEventListener("click", clickHide_mouseClick, true); | 
| 280 document.removeEventListener("keydown", clickHide_keyDown, true); | 370 document.removeEventListener("keydown", clickHide_keyDown, true); | 
| 281 } | 371 } | 
| 282 | 372 | 
| 283 // Turn off click-to-hide | 373 // Turn off click-to-hide | 
| 284 function clickHide_deactivate(keepOverlays) | 374 function clickHide_deactivate(keepOverlays) | 
| 
kzar
2014/11/26 14:14:04
We're relying on the legacy code not passing this
 
Sebastian Noack
2014/11/26 14:41:39
Correct. I tried to keep the patch as compact as p
 | |
| 285 { | 375 { | 
| 286 if (clickHideFiltersDialog) | 376 if (clickHideFiltersDialog) | 
| 287 { | 377 { | 
| 288 document.body.removeChild(clickHideFiltersDialog); | 378 document.body.removeChild(clickHideFiltersDialog); | 
| 289 clickHideFiltersDialog = null; | 379 clickHideFiltersDialog = null; | 
| 290 } | 380 } | 
| 291 | 381 | 
| 292 clickHide_activated = false; | 382 clickHide_activated = false; | 
| 293 clickHide_filters = null; | 383 clickHide_filters = null; | 
| 294 if(!document) | 384 if(!document) | 
| 295 return; // This can happen inside a nuked iframe...I think | 385 return; // This can happen inside a nuked iframe...I think | 
| 296 document.removeEventListener("mouseover", clickHide_mouseOver, true); | 386 document.removeEventListener("mouseover", clickHide_mouseOver, true); | 
| 297 document.removeEventListener("mouseout", clickHide_mouseOut, true); | 387 document.removeEventListener("mouseout", clickHide_mouseOut, true); | 
| 298 document.removeEventListener("click", clickHide_mouseClick, true); | 388 document.removeEventListener("click", clickHide_mouseClick, true); | 
| 299 document.removeEventListener("keydown", clickHide_keyDown, true); | 389 document.removeEventListener("keydown", clickHide_keyDown, true); | 
| 300 | 390 | 
| 301 if (!keepOverlays) | 391 if (!keepOverlays) | 
| 302 { | 392 { | 
| 303 if(currentElement) { | 393 if (currentElement) { | 
| 
kzar
2014/11/26 14:14:04
Nitpick: Should be space between "if" and "("?
 
Sebastian Noack
2014/11/26 14:41:39
I just copied the code from above, but I have adde
 | |
| 304 currentElement.removeEventListener("contextmenu", clickHide_elementClickHa ndler, false); | 394 currentElement.removeEventListener("contextmenu", clickHide_elementClickH andler, true); | 
| 
kzar
2014/11/26 14:14:04
Last parameter should be true?
 
Sebastian Noack
2014/11/26 14:41:39
Yes, this patch was created on top of a version, w
 | |
| 305 unhighlightElements(); | 395 unhighlightElements(); | 
| 306 unhighlightElement(currentElement); | 396 unhighlightElement(currentElement); | 
| 307 currentElement = null; | 397 currentElement = null; | 
| 308 clickHideFilters = null; | 398 clickHideFilters = null; | 
| 309 } | 399 } | 
| 310 unhighlightElements(); | 400 unhighlightElements(); | 
| 311 | 401 | 
| 312 var overlays = document.getElementsByClassName("__adblockplus__overlay"); | 402 var overlays = document.getElementsByClassName("__adblockplus__overlay"); | 
| 313 while (overlays.length > 0) | 403 while (overlays.length > 0) | 
| 314 overlays[0].parentNode.removeChild(overlays[0]); | 404 overlays[0].parentNode.removeChild(overlays[0]); | 
| 315 } | 405 } | 
| 316 } | 406 } | 
| 317 | 407 | 
| 318 function clickHide_elementClickHandler(ev) { | 408 function clickHide_elementClickHandler(ev) { | 
| 319 ev.preventDefault(); | 409 ev.preventDefault(); | 
| 320 ev.stopPropagation(); | 410 ev.stopPropagation(); | 
| 321 clickHide_mouseClick(ev); | 411 clickHide_mouseClick(ev); | 
| 322 } | 412 } | 
| 323 | 413 | 
| 324 // Hovering over an element so highlight it | 414 // Hovering over an element so highlight it | 
| 325 function clickHide_mouseOver(e) | 415 function clickHide_mouseOver(e) | 
| 326 { | 416 { | 
| 327 if (clickHide_activated == false) | 417 if (clickHide_activated == false) | 
| 328 return; | 418 return; | 
| 329 | 419 | 
| 330 var target = e.target; | 420 var target = e.target; | 
| 331 while (target.parentNode && !hasFilters(target)) | 421 while (target.parentNode && !isBlockable(target)) | 
| 332 target = target.parentNode; | 422 target = target.parentNode; | 
| 333 if (target == document.documentElement || target == document.body) | 423 if (target == document.documentElement || target == document.body) | 
| 334 target = null; | 424 target = null; | 
| 335 | 425 | 
| 336 if (target && target instanceof HTMLElement) | 426 if (target && target instanceof HTMLElement) | 
| 337 { | 427 { | 
| 338 currentElement = target; | 428 currentElement = target; | 
| 339 | 429 | 
| 340 highlightElement(target, "#d6d84b", "#f8fa47"); | 430 highlightElement(target, "#d6d84b", "#f8fa47"); | 
| 341 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); | 431 target.addEventListener("contextmenu", clickHide_elementClickHandler, true); | 
| (...skipping 23 matching lines...) Expand all Loading... | |
| 365 payload: | 455 payload: | 
| 366 { | 456 { | 
| 367 type: "clickhide-deactivate" | 457 type: "clickhide-deactivate" | 
| 368 } | 458 } | 
| 369 }); | 459 }); | 
| 370 e.preventDefault(); | 460 e.preventDefault(); | 
| 371 e.stopPropagation(); | 461 e.stopPropagation(); | 
| 372 } | 462 } | 
| 373 } | 463 } | 
| 374 | 464 | 
| 375 | |
| 376 | |
| 377 // When the user clicks, the currentElement is the one we want. | 465 // When the user clicks, the currentElement is the one we want. | 
| 378 // We should have ABP rules ready for when the | 466 // We should have ABP rules ready for when the | 
| 379 // popup asks for them. | 467 // popup asks for them. | 
| 380 function clickHide_mouseClick(e) | 468 function clickHide_mouseClick(e) | 
| 381 { | 469 { | 
| 382 if (!currentElement || !clickHide_activated) | 470 if (!currentElement || !clickHide_activated) | 
| 383 return; | 471 return; | 
| 384 | 472 | 
| 385 var elt = currentElement; | 473 var elt = currentElement; | 
| 386 if (currentElement.classList.contains("__adblockplus__overlay")) | 474 if (currentElement.classList.contains("__adblockplus__overlay")) | 
| (...skipping 21 matching lines...) Expand all Loading... | |
| 408 for (var i = 0; i < elt.classList.length; i++) | 496 for (var i = 0; i < elt.classList.length; i++) | 
| 409 selector += "." + escapeCSS(elt.classList[i]); | 497 selector += "." + escapeCSS(elt.classList[i]); | 
| 410 | 498 | 
| 411 addSelector(selector); | 499 addSelector(selector); | 
| 412 } | 500 } | 
| 413 | 501 | 
| 414 var urls = getElementURLs(elt); | 502 var urls = getElementURLs(elt); | 
| 415 for (var i = 0; i < urls.length; i++) | 503 for (var i = 0; i < urls.length; i++) | 
| 416 { | 504 { | 
| 417 var url = urls[i]; | 505 var url = urls[i]; | 
| 418 var isHTTP = /^https?:/i.test(url); | 506 | 
| 419 | 507 if (/^https?:/i.test(url)) | 
| 420 if (isHTTP) | |
| 421 { | 508 { | 
| 422 var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||"); | 509 var filter = url.replace(/^[\w\-]+:\/+(?:www\.)?/, "||"); | 
| 423 | 510 | 
| 424 if (clickHideFilters.indexOf(filter) != -1) | 511 if (clickHideFilters.indexOf(filter) == -1) | 
| 425 continue; | 512 clickHideFilters.push(filter); | 
| 426 | 513 | 
| 427 clickHideFilters.push(filter); | 514 continue; | 
| 428 } | 515 } | 
| 429 | 516 | 
| 430 if (url == elt.src) | 517 if (url == elt.src) | 
| 431 { | 518 addSelector(escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute("s rc")) + ']'); | 
| 432 var selector = escapeCSS(elt.localName) + '[src=' + quote(elt.getAttribute ("src")) + ']'; | |
| 433 | |
| 434 if (isHTTP) | |
| 435 selectorList.push(selector); | |
| 436 else | |
| 437 addSelector(selector); | |
| 438 } | |
| 439 } | 519 } | 
| 440 | 520 | 
| 441 // restore the original style, before generating the fallback filter that | 521 // restore the original style, before generating the fallback filter that | 
| 442 // will include the style, and to prevent highlightElements from saving those | 522 // will include the style, and to prevent highlightElements from saving those | 
| 443 unhighlightElement(currentElement); | 523 unhighlightElement(currentElement); | 
| 444 | 524 | 
| 445 // as last resort, create a filter based on inline styles | 525 // as last resort, create a filter based on inline styles | 
| 446 if (clickHideFilters.length == 0) | 526 if (clickHideFilters.length == 0) | 
| 447 { | 527 { | 
| 448 var style = elt.getAttribute("style"); | 528 var style = elt.getAttribute("style"); | 
| (...skipping 24 matching lines...) Expand all Loading... | |
| 473 for (var i = 0; i < urls.length; i++) | 553 for (var i = 0; i < urls.length; i++) | 
| 474 { | 554 { | 
| 475 var url = urls[i].replace(/^\s+/, "").replace(/(\s+\S+)?\s*$/, ""); | 555 var url = urls[i].replace(/^\s+/, "").replace(/(\s+\S+)?\s*$/, ""); | 
| 476 if (url) | 556 if (url) | 
| 477 urls[i] = resolveURL(url); | 557 urls[i] = resolveURL(url); | 
| 478 else | 558 else | 
| 479 urls.splice(i--, 1); | 559 urls.splice(i--, 1); | 
| 480 } | 560 } | 
| 481 | 561 | 
| 482 return urls; | 562 return urls; | 
| 483 } | |
| 484 | |
| 485 function getElementURLs(elt) { | |
| 486 var urls = []; | |
| 487 | |
| 488 if (elt.src) | |
| 489 urls.push(elt.src); | |
| 490 | |
| 491 switch (elt.localName) | |
| 492 { | |
| 493 case "object": | |
| 494 var url = elt.getAttribute("data"); | |
| 495 if (url) | |
| 496 return [resolveURL(url)]; | |
| 497 | |
| 498 for (var i = 0; i < elt.children.length; i++) | |
| 499 { | |
| 500 var child = elt.children[i]; | |
| 501 if (child.localName != "param") | |
| 502 continue; | |
| 503 | |
| 504 var name = child.getAttribute("name"); | |
| 505 if (name != "movie" && name != "src") | |
| 506 continue; | |
| 507 | |
| 508 var value = child.getAttribute("value"); | |
| 509 if (!value) | |
| 510 continue; | |
| 511 | |
| 512 return [resolveURL(value)]; | |
| 513 } | |
| 514 | |
| 515 return []; | |
| 516 | |
| 517 case "video": | |
| 518 case "audio": | |
| 519 case "picture": | |
| 520 for (var i = 0; i < elt.children.length; i++) | |
| 521 { | |
| 522 var child = elt.children[i]; | |
| 523 | |
| 524 if (child.localName != "source") | |
| 525 continue; | |
| 526 | |
| 527 if (child.src) | |
| 528 urls.push(child.src); | |
| 529 | |
| 530 urls = urls.concat(parseSrcSet(child)); | |
| 531 } | |
| 532 | |
| 533 if (elt.poster) | |
| 534 urls.push(elt.poster); | |
| 535 | |
| 536 break; | |
| 537 | |
| 538 case "img": | |
| 539 urls = urls.concat(parseSrcSet(elt)); | |
| 540 } | |
| 541 | |
| 542 return urls; | |
| 543 } | |
| 544 | |
| 545 function hasFilters(element) | |
| 546 { | |
| 547 if (element.id) | |
| 548 return true; | |
| 549 if (element.classList.length > 0) | |
| 550 return true; | |
| 551 if (getElementURLs(element).length > 0) | |
| 552 return true; | |
| 553 if (/:.+:/.test(element.getAttribute("style"))) | |
| 554 return true; | |
| 555 | |
| 556 return false; | |
| 557 } | 563 } | 
| 558 | 564 | 
| 559 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js | 565 // This function Copyright (c) 2008 Jeni Tennison, from jquery.uri.js | 
| 560 // and licensed under the MIT license. See jquery-*.min.js for details. | 566 // and licensed under the MIT license. See jquery-*.min.js for details. | 
| 561 function removeDotSegments(u) { | 567 function removeDotSegments(u) { | 
| 562 var r = '', m = []; | 568 var r = '', m = []; | 
| 563 if (/\./.test(u)) { | 569 if (/\./.test(u)) { | 
| 564 while (u !== undefined && u !== '') { | 570 while (u !== undefined && u !== '') { | 
| 565 if (u === '.' || u === '..') { | 571 if (u === '.' || u === '..') { | 
| 566 u = ''; | 572 u = ''; | 
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 709 break; | 715 break; | 
| 710 default: | 716 default: | 
| 711 sendResponse({}); | 717 sendResponse({}); | 
| 712 break; | 718 break; | 
| 713 } | 719 } | 
| 714 }); | 720 }); | 
| 715 | 721 | 
| 716 if (window == window.top) | 722 if (window == window.top) | 
| 717 ext.backgroundPage.sendMessage({type: "report-html-page"}); | 723 ext.backgroundPage.sendMessage({type: "report-html-page"}); | 
| 718 } | 724 } | 
| LEFT | RIGHT |