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

Side by Side Diff: include.postload.js

Issue 5455501458407424: Issue 1325 - Use Shadow DOM if possible when highlighting page elements (Closed)
Patch Set: Fixed typo in comment Created Sept. 22, 2014, 1:09 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
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 currentElement_boxShadow = null;
23 var currentElement_backgroundColor;
24 var clickHideFilters = null; 22 var clickHideFilters = null;
25 var highlightedElementsSelector = null; 23 var highlightedElementsSelector = null;
26 var highlightedElementsBoxShadows = null;
27 var highlightedElementsBGColors = null;
28 var clickHideFiltersDialog = null; 24 var clickHideFiltersDialog = null;
29 var lastRightClickEvent = null; 25 var lastRightClickEvent = null;
30 26
27 function supportsShadowRoot(element)
28 {
29 if (!("createShadowRoot" in element))
30 return false;
31
32 // There are some elements (e.g. <textarea>), which don't
33 // support author created shadow roots and throw an exception.
34 var clone = element.cloneNode(false);
35 try
36 {
37 var root = clone.createShadowRoot();
Wladimir Palant 2014/09/22 18:31:09 Please don't use variables outside the block where
Sebastian Noack 2014/09/23 11:30:07 Done, though I don't like that policy. :/
Wladimir Palant 2014/09/23 13:29:03 I think I explained my reasoning before - doing th
Sebastian Noack 2014/09/23 15:11:39 Yes, we did. And I think it is pointless to repeat
Wladimir Palant 2014/09/23 15:41:45 You are wrong about Perl, and in Python and PHP lo
Sebastian Noack 2014/09/23 16:37:33 I don't think so. Run following code if you don't
Wladimir Palant 2014/09/23 23:07:39 Please add "use strict;" at the top.
38 }
39 catch (e)
40 {
41 return false;
42 }
43
44 // There are some elements (e.g. <input>), which support
45 // author created shadow roots, but ignore insertion points.
46 var child = document.createTextNode('');
Wladimir Palant 2014/09/22 18:31:09 Double quotation marks please (same two lines belo
Sebastian Noack 2014/09/23 11:30:07 Done.
47 clone.appendChild(child);
48
49 var shadow = document.createElement('shadow');
50 root.appendChild(shadow);
51
52 return shadow.getDistributedNodes()[0] == child;
53 }
54
55 function highlightElement(element, shadowColor, backgroundColor)
56 {
57 unhighlightElement(element);
58
59 var originalBoxShadowPriority = element.style.getPropertyPriority("box-shadow" );
60 var originalBackgroundColorPriority = element.style.getPropertyPriority("backg round-color");
61 var boxShadow = "inset 0px 0px 5px " + shadowColor;
62
63 var highlightWithStyleAttribute = function()
64 {
65 var originalBoxShadow = element.style.getPropertyValue("box-shadow");
66 var originalBackgroundColor = element.style.getPropertyValue("background-col or");
67
68 element.style.setProperty("box-shadow", boxShadow, "important");
69 element.style.setProperty("background-color", backgroundColor, "important");
70
71 element._unhighlight = function()
72 {
73 this.style.removeProperty("box-shadow");
74 this.style.setProperty(
75 "box-shadow",
76 originalBoxShadow,
77 originalBoxShadowPriority
78 );
79
80 this.style.removeProperty("background-color");
81 this.style.setProperty(
82 "background-color",
83 originalBackgroundColor,
84 originalBackgroundColorPriority
85 );
86 };
87 };
88
89 var highlightWithShadowDOM = function()
90 {
91 var style = document.createElement("style");
92 style.textContent = ":host {" +
93 "box-shadow:" + boxShadow + " !important;" +
94 "background-color:" + backgroundColor + " !important;" +
95 "}";
96
97 var root = element.createShadowRoot();
98 root.appendChild(document.createElement("shadow"));
99 root.appendChild(style);
100
101 element._unhighlight = function()
102 {
103 root.removeChild(style);
104 };
105 };
106
107 if (supportsShadowRoot(element) && // Use Shadow DOM if posibble to avoid
108 // side effects when the web page updates
109 // style while highlighted.
Wladimir Palant 2014/09/22 18:31:09 Please put this comment before the line you are co
Sebastian Noack 2014/09/23 11:30:07 Done.
110
111 // However, if the element has important styles we have to replace
112 // the style attribute, and can't override them with shadow DOM.
113 originalBoxShadowPriority != "important" &&
114 originalBackgroundColorPriority != "important")
115 highlightWithShadowDOM();
116 else
117 highlightWithStyleAttribute();
118 }
119
120
121 function unhighlightElement(element)
122 {
123 if ("_unhighlight" in element)
124 {
125 element._unhighlight();
126 delete element._unhighlight;
127 }
128 }
129
31 // Highlight elements according to selector string. This would include 130 // Highlight elements according to selector string. This would include
32 // all elements that would be affected by proposed filters. 131 // all elements that would be affected by proposed filters.
33 function highlightElements(selectorString) { 132 function highlightElements(selectorString) {
34 if(highlightedElementsSelector) 133 unhighlightElements();
35 unhighlightElements();
36 134
37 var highlightedElements = document.querySelectorAll(selectorString); 135 var highlightedElements = document.querySelectorAll(selectorString);
38 highlightedElementsSelector = selectorString; 136 highlightedElementsSelector = selectorString;
39 highlightedElementsBoxShadows = new Array();
40 highlightedElementsBGColors = new Array();
41 137
42 for(var i = 0; i < highlightedElements.length; i++) { 138 for(var i = 0; i < highlightedElements.length; i++)
43 highlightedElementsBoxShadows[i] = highlightedElements[i].style.getPropertyV alue("-webkit-box-shadow"); 139 highlightElement(highlightedElements[i], "#fd6738", "#f6e1e5");
44 highlightedElementsBGColors[i] = highlightedElements[i].style.backgroundColo r;
45 highlightedElements[i].style.setProperty("-webkit-box-shadow", "inset 0px 0p x 5px #fd6738");
46 highlightedElements[i].style.backgroundColor = "#f6e1e5";
47 }
48 } 140 }
49 141
50 // Unhighlight all elements, including those that would be affected by 142 // Unhighlight all elements, including those that would be affected by
51 // the proposed filters 143 // the proposed filters
52 function unhighlightElements() { 144 function unhighlightElements() {
53 if(highlightedElementsSelector == null) 145 if (highlightedElementsSelector)
54 return; 146 {
55 var highlightedElements = document.querySelectorAll(highlightedElementsSelecto r); 147 Array.prototype.forEach.call(
56 for(var i = 0; i < highlightedElements.length; i++) { 148 document.querySelectorAll(highlightedElementsSelector),
57 highlightedElements[i].style.setProperty("-webkit-box-shadow", highlightedEl ementsBoxShadows[i]); 149 unhighlightElement
58 highlightedElements[i].style.backgroundColor = highlightedElementsBGColors[i ]; 150 );
151
152 highlightedElementsSelector = null;
59 } 153 }
60 highlightedElementsSelector = null;
61 } 154 }
62 155
63 // Gets the absolute position of an element by walking up the DOM tree, 156 // Gets the absolute position of an element by walking up the DOM tree,
64 // adding up offsets. 157 // adding up offsets.
65 // I hope there's a better way because it just seems absolutely stupid 158 // I hope there's a better way because it just seems absolutely stupid
66 // that the DOM wouldn't have a direct way to get this, given that it 159 // that the DOM wouldn't have a direct way to get this, given that it
67 // has hundreds and hundreds of other methods that do random junk. 160 // has hundreds and hundreds of other methods that do random junk.
68 function getAbsolutePosition(elt) { 161 function getAbsolutePosition(elt) {
69 var l = 0; 162 var l = 0;
70 var t = 0; 163 var t = 0;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 { 269 {
177 if (clickHideFiltersDialog) 270 if (clickHideFiltersDialog)
178 { 271 {
179 document.body.removeChild(clickHideFiltersDialog); 272 document.body.removeChild(clickHideFiltersDialog);
180 clickHideFiltersDialog = null; 273 clickHideFiltersDialog = null;
181 } 274 }
182 275
183 if(currentElement) { 276 if(currentElement) {
184 currentElement.removeEventListener("contextmenu", clickHide_elementClickHand ler, false); 277 currentElement.removeEventListener("contextmenu", clickHide_elementClickHand ler, false);
185 unhighlightElements(); 278 unhighlightElements();
186 currentElement.style.setProperty("-webkit-box-shadow", currentElement_boxSha dow); 279 unhighlightElement(currentElement);
187 currentElement.style.backgroundColor = currentElement_backgroundColor;
188 currentElement = null; 280 currentElement = null;
189 clickHideFilters = null; 281 clickHideFilters = null;
190 } 282 }
191 unhighlightElements(); 283 unhighlightElements();
192 284
193 clickHide_activated = false; 285 clickHide_activated = false;
194 clickHide_filters = null; 286 clickHide_filters = null;
195 if(!document) 287 if(!document)
196 return; // This can happen inside a nuked iframe...I think 288 return; // This can happen inside a nuked iframe...I think
197 document.removeEventListener("mouseover", clickHide_mouseOver, false); 289 document.removeEventListener("mouseover", clickHide_mouseOver, false);
(...skipping 22 matching lines...) Expand all
220 312
221 var target = e.target; 313 var target = e.target;
222 while (target.parentNode && !(target.id || target.className || target.src)) 314 while (target.parentNode && !(target.id || target.className || target.src))
223 target = target.parentNode; 315 target = target.parentNode;
224 if (target == document.documentElement || target == document.body) 316 if (target == document.documentElement || target == document.body)
225 target = null; 317 target = null;
226 318
227 if (target && target instanceof HTMLElement) 319 if (target && target instanceof HTMLElement)
228 { 320 {
229 currentElement = target; 321 currentElement = target;
230 currentElement_boxShadow = target.style.getPropertyValue("-webkit-box-shadow ");
231 currentElement_backgroundColor = target.style.backgroundColor;
232 target.style.setProperty("-webkit-box-shadow", "inset 0px 0px 5px #d6d84b");
233 target.style.backgroundColor = "#f8fa47";
234 322
323 highlightElement(target, "#d6d84b", "#f8fa47");
235 target.addEventListener("contextmenu", clickHide_elementClickHandler, false) ; 324 target.addEventListener("contextmenu", clickHide_elementClickHandler, false) ;
236 } 325 }
237 } 326 }
238 327
239 // No longer hovering over this element so unhighlight it 328 // No longer hovering over this element so unhighlight it
240 function clickHide_mouseOut(e) 329 function clickHide_mouseOut(e)
241 { 330 {
242 if (!clickHide_activated || !currentElement) 331 if (!clickHide_activated || !currentElement)
243 return; 332 return;
244 333
245 currentElement.style.setProperty("-webkit-box-shadow", currentElement_boxShado w); 334 unhighlightElement(currentElement);
246 currentElement.style.backgroundColor = currentElement_backgroundColor;
247
248 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, false); 335 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, false);
249 } 336 }
250 337
251 // Selects the currently hovered-over filter or cancels selection 338 // Selects the currently hovered-over filter or cancels selection
252 function clickHide_keyDown(e) 339 function clickHide_keyDown(e)
253 { 340 {
254 if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 13 /*DOM_VK_RETURN* /) 341 if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 13 /*DOM_VK_RETURN* /)
255 clickHide_mouseClick(e); 342 clickHide_mouseClick(e);
256 else if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 27 /*DOM_VK_ES CAPE*/) 343 else if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 27 /*DOM_VK_ES CAPE*/)
257 { 344 {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 { 400 {
314 clickHideFilters.push(relativeToAbsoluteUrl(url)); 401 clickHideFilters.push(relativeToAbsoluteUrl(url));
315 selectorList.push(elt.localName + '[src="' + url + '"]'); 402 selectorList.push(elt.localName + '[src="' + url + '"]');
316 } 403 }
317 404
318 // Show popup 405 // Show popup
319 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); 406 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters);
320 407
321 // Highlight the unlucky elements 408 // Highlight the unlucky elements
322 // Restore currentElement's box-shadow and bgcolor so that highlightElements w on't save those 409 // Restore currentElement's box-shadow and bgcolor so that highlightElements w on't save those
323 currentElement.style.setProperty("-webkit-box-shadow", currentElement_boxShado w); 410 unhighlightElement(currentElement);
324 currentElement.style.backgroundColor = currentElement_backgroundColor;
325 // Highlight the elements specified by selector in yellow 411 // Highlight the elements specified by selector in yellow
326 highlightElements(selectorList.join(",")); 412 highlightElements(selectorList.join(","));
327 // Now, actually highlight the element the user clicked on in red 413 // Now, actually highlight the element the user clicked on in red
328 currentElement.style.setProperty("-webkit-box-shadow", "inset 0px 0px 5px #fd1 708"); 414 highlightElement(currentElement, "#fd1708", "#f6a1b5");
329 currentElement.style.backgroundColor = "#f6a1b5";
330 415
331 // Make sure the browser doesn't handle this click 416 // Make sure the browser doesn't handle this click
332 e.preventDefault(); 417 e.preventDefault();
333 e.stopPropagation(); 418 e.stopPropagation();
334 } 419 }
335 420
336 // Extracts source URL from an IMG, OBJECT, EMBED, or IFRAME 421 // Extracts source URL from an IMG, OBJECT, EMBED, or IFRAME
337 function getElementURL(elt) { 422 function getElementURL(elt) {
338 // Check children of object nodes for "param" nodes with name="movie" that spe cify a URL 423 // Check children of object nodes for "param" nodes with name="movie" that spe cify a URL
339 // in value attribute 424 // in value attribute
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 if(msg.filter === url) 604 if(msg.filter === url)
520 { 605 {
521 // This request would have come from the chrome.contextMenu handler, s o we 606 // This request would have come from the chrome.contextMenu handler, s o we
522 // simulate the user having chosen the element to get rid of via the u sual means. 607 // simulate the user having chosen the element to get rid of via the u sual means.
523 clickHide_activated = true; 608 clickHide_activated = true;
524 // FIXME: clickHideFilters is erased in clickHide_mouseClick anyway, s o why set it? 609 // FIXME: clickHideFilters is erased in clickHide_mouseClick anyway, s o why set it?
525 clickHideFilters = [msg.filter]; 610 clickHideFilters = [msg.filter];
526 // Coerce red highlighted overlay on top of element to remove. 611 // Coerce red highlighted overlay on top of element to remove.
527 // TODO: Wow, the design of the clickHide stuff is really dumb - gotta fix it sometime 612 // TODO: Wow, the design of the clickHide stuff is really dumb - gotta fix it sometime
528 currentElement = addElementOverlay(target); 613 currentElement = addElementOverlay(target);
529 currentElement_backgroundColor = target.style.backgroundColor;
530 // clickHide_mouseOver(lastRightClickEvent); 614 // clickHide_mouseOver(lastRightClickEvent);
531 clickHide_mouseClick(lastRightClickEvent); 615 clickHide_mouseClick(lastRightClickEvent);
532 } 616 }
533 else 617 else
534 console.log("clickhide-new-filter: URLs don't match. Couldn't find tha t element.", request.filter, url, lastRightClickEvent.target.src); 618 console.log("clickhide-new-filter: URLs don't match. Couldn't find tha t element.", request.filter, url, lastRightClickEvent.target.src);
535 break; 619 break;
536 case "clickhide-init": 620 case "clickhide-init":
537 if (clickHideFiltersDialog) 621 if (clickHideFiltersDialog)
538 { 622 {
539 sendResponse({filters: clickHide_filters}); 623 sendResponse({filters: clickHide_filters});
(...skipping 19 matching lines...) Expand all
559 643
560 clickHide_deactivate(); 644 clickHide_deactivate();
561 } 645 }
562 break; 646 break;
563 default: 647 default:
564 sendResponse({}); 648 sendResponse({});
565 break; 649 break;
566 } 650 }
567 }); 651 });
568 } 652 }
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