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: Addressed comments Created Sept. 23, 2014, 11:29 a.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 clone.createShadowRoot();
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("");
47 clone.appendChild(child);
48
49 var shadow = document.createElement("shadow");
50 clone.shadowRoot.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 // Use shadow DOM if posibble to avoid side effects when the
108 // web page updates style while highlighted. However, if the
109 // element has important styles we can't override them with shadow DOM.
110 if (supportsShadowRoot(element) && originalBoxShadowPriority != "importa nt" &&
111 originalBackgroundColorPriority != "importa nt")
112 highlightWithShadowDOM();
113 else
114 highlightWithStyleAttribute();
115 }
116
117
118 function unhighlightElement(element)
119 {
120 if ("_unhighlight" in element)
121 {
122 element._unhighlight();
123 delete element._unhighlight;
124 }
125 }
126
31 // Highlight elements according to selector string. This would include 127 // Highlight elements according to selector string. This would include
32 // all elements that would be affected by proposed filters. 128 // all elements that would be affected by proposed filters.
33 function highlightElements(selectorString) { 129 function highlightElements(selectorString) {
34 if(highlightedElementsSelector) 130 unhighlightElements();
35 unhighlightElements();
36 131
37 var highlightedElements = document.querySelectorAll(selectorString); 132 var highlightedElements = document.querySelectorAll(selectorString);
38 highlightedElementsSelector = selectorString; 133 highlightedElementsSelector = selectorString;
39 highlightedElementsBoxShadows = new Array();
40 highlightedElementsBGColors = new Array();
41 134
42 for(var i = 0; i < highlightedElements.length; i++) { 135 for(var i = 0; i < highlightedElements.length; i++)
43 highlightedElementsBoxShadows[i] = highlightedElements[i].style.getPropertyV alue("-webkit-box-shadow"); 136 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 } 137 }
49 138
50 // Unhighlight all elements, including those that would be affected by 139 // Unhighlight all elements, including those that would be affected by
51 // the proposed filters 140 // the proposed filters
52 function unhighlightElements() { 141 function unhighlightElements() {
53 if(highlightedElementsSelector == null) 142 if (highlightedElementsSelector)
54 return; 143 {
55 var highlightedElements = document.querySelectorAll(highlightedElementsSelecto r); 144 Array.prototype.forEach.call(
56 for(var i = 0; i < highlightedElements.length; i++) { 145 document.querySelectorAll(highlightedElementsSelector),
57 highlightedElements[i].style.setProperty("-webkit-box-shadow", highlightedEl ementsBoxShadows[i]); 146 unhighlightElement
58 highlightedElements[i].style.backgroundColor = highlightedElementsBGColors[i ]; 147 );
148
149 highlightedElementsSelector = null;
59 } 150 }
60 highlightedElementsSelector = null;
61 } 151 }
62 152
63 // Gets the absolute position of an element by walking up the DOM tree, 153 // Gets the absolute position of an element by walking up the DOM tree,
64 // adding up offsets. 154 // adding up offsets.
65 // I hope there's a better way because it just seems absolutely stupid 155 // 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 156 // 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. 157 // has hundreds and hundreds of other methods that do random junk.
68 function getAbsolutePosition(elt) { 158 function getAbsolutePosition(elt) {
69 var l = 0; 159 var l = 0;
70 var t = 0; 160 var t = 0;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
176 { 266 {
177 if (clickHideFiltersDialog) 267 if (clickHideFiltersDialog)
178 { 268 {
179 document.body.removeChild(clickHideFiltersDialog); 269 document.body.removeChild(clickHideFiltersDialog);
180 clickHideFiltersDialog = null; 270 clickHideFiltersDialog = null;
181 } 271 }
182 272
183 if(currentElement) { 273 if(currentElement) {
184 currentElement.removeEventListener("contextmenu", clickHide_elementClickHand ler, false); 274 currentElement.removeEventListener("contextmenu", clickHide_elementClickHand ler, false);
185 unhighlightElements(); 275 unhighlightElements();
186 currentElement.style.setProperty("-webkit-box-shadow", currentElement_boxSha dow); 276 unhighlightElement(currentElement);
187 currentElement.style.backgroundColor = currentElement_backgroundColor;
188 currentElement = null; 277 currentElement = null;
189 clickHideFilters = null; 278 clickHideFilters = null;
190 } 279 }
191 unhighlightElements(); 280 unhighlightElements();
192 281
193 clickHide_activated = false; 282 clickHide_activated = false;
194 clickHide_filters = null; 283 clickHide_filters = null;
195 if(!document) 284 if(!document)
196 return; // This can happen inside a nuked iframe...I think 285 return; // This can happen inside a nuked iframe...I think
197 document.removeEventListener("mouseover", clickHide_mouseOver, false); 286 document.removeEventListener("mouseover", clickHide_mouseOver, false);
(...skipping 22 matching lines...) Expand all
220 309
221 var target = e.target; 310 var target = e.target;
222 while (target.parentNode && !(target.id || target.className || target.src)) 311 while (target.parentNode && !(target.id || target.className || target.src))
223 target = target.parentNode; 312 target = target.parentNode;
224 if (target == document.documentElement || target == document.body) 313 if (target == document.documentElement || target == document.body)
225 target = null; 314 target = null;
226 315
227 if (target && target instanceof HTMLElement) 316 if (target && target instanceof HTMLElement)
228 { 317 {
229 currentElement = target; 318 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 319
320 highlightElement(target, "#d6d84b", "#f8fa47");
235 target.addEventListener("contextmenu", clickHide_elementClickHandler, false) ; 321 target.addEventListener("contextmenu", clickHide_elementClickHandler, false) ;
236 } 322 }
237 } 323 }
238 324
239 // No longer hovering over this element so unhighlight it 325 // No longer hovering over this element so unhighlight it
240 function clickHide_mouseOut(e) 326 function clickHide_mouseOut(e)
241 { 327 {
242 if (!clickHide_activated || !currentElement) 328 if (!clickHide_activated || !currentElement)
243 return; 329 return;
244 330
245 currentElement.style.setProperty("-webkit-box-shadow", currentElement_boxShado w); 331 unhighlightElement(currentElement);
246 currentElement.style.backgroundColor = currentElement_backgroundColor;
247
248 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, false); 332 currentElement.removeEventListener("contextmenu", clickHide_elementClickHandle r, false);
249 } 333 }
250 334
251 // Selects the currently hovered-over filter or cancels selection 335 // Selects the currently hovered-over filter or cancels selection
252 function clickHide_keyDown(e) 336 function clickHide_keyDown(e)
253 { 337 {
254 if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 13 /*DOM_VK_RETURN* /) 338 if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 13 /*DOM_VK_RETURN* /)
255 clickHide_mouseClick(e); 339 clickHide_mouseClick(e);
256 else if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 27 /*DOM_VK_ES CAPE*/) 340 else if (!e.ctrlKey && !e.altKey && !e.shiftKey && e.keyCode == 27 /*DOM_VK_ES CAPE*/)
257 { 341 {
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
313 { 397 {
314 clickHideFilters.push(relativeToAbsoluteUrl(url)); 398 clickHideFilters.push(relativeToAbsoluteUrl(url));
315 selectorList.push(elt.localName + '[src="' + url + '"]'); 399 selectorList.push(elt.localName + '[src="' + url + '"]');
316 } 400 }
317 401
318 // Show popup 402 // Show popup
319 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters); 403 clickHide_showDialog(e.clientX, e.clientY, clickHideFilters);
320 404
321 // Highlight the unlucky elements 405 // Highlight the unlucky elements
322 // Restore currentElement's box-shadow and bgcolor so that highlightElements w on't save those 406 // 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); 407 unhighlightElement(currentElement);
324 currentElement.style.backgroundColor = currentElement_backgroundColor;
325 // Highlight the elements specified by selector in yellow 408 // Highlight the elements specified by selector in yellow
326 highlightElements(selectorList.join(",")); 409 highlightElements(selectorList.join(","));
327 // Now, actually highlight the element the user clicked on in red 410 // Now, actually highlight the element the user clicked on in red
328 currentElement.style.setProperty("-webkit-box-shadow", "inset 0px 0px 5px #fd1 708"); 411 highlightElement(currentElement, "#fd1708", "#f6a1b5");
329 currentElement.style.backgroundColor = "#f6a1b5";
330 412
331 // Make sure the browser doesn't handle this click 413 // Make sure the browser doesn't handle this click
332 e.preventDefault(); 414 e.preventDefault();
333 e.stopPropagation(); 415 e.stopPropagation();
334 } 416 }
335 417
336 // Extracts source URL from an IMG, OBJECT, EMBED, or IFRAME 418 // Extracts source URL from an IMG, OBJECT, EMBED, or IFRAME
337 function getElementURL(elt) { 419 function getElementURL(elt) {
338 // Check children of object nodes for "param" nodes with name="movie" that spe cify a URL 420 // Check children of object nodes for "param" nodes with name="movie" that spe cify a URL
339 // in value attribute 421 // in value attribute
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 if(msg.filter === url) 601 if(msg.filter === url)
520 { 602 {
521 // This request would have come from the chrome.contextMenu handler, s o we 603 // 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. 604 // simulate the user having chosen the element to get rid of via the u sual means.
523 clickHide_activated = true; 605 clickHide_activated = true;
524 // FIXME: clickHideFilters is erased in clickHide_mouseClick anyway, s o why set it? 606 // FIXME: clickHideFilters is erased in clickHide_mouseClick anyway, s o why set it?
525 clickHideFilters = [msg.filter]; 607 clickHideFilters = [msg.filter];
526 // Coerce red highlighted overlay on top of element to remove. 608 // 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 609 // TODO: Wow, the design of the clickHide stuff is really dumb - gotta fix it sometime
528 currentElement = addElementOverlay(target); 610 currentElement = addElementOverlay(target);
529 currentElement_backgroundColor = target.style.backgroundColor;
530 // clickHide_mouseOver(lastRightClickEvent); 611 // clickHide_mouseOver(lastRightClickEvent);
531 clickHide_mouseClick(lastRightClickEvent); 612 clickHide_mouseClick(lastRightClickEvent);
532 } 613 }
533 else 614 else
534 console.log("clickhide-new-filter: URLs don't match. Couldn't find tha t element.", request.filter, url, lastRightClickEvent.target.src); 615 console.log("clickhide-new-filter: URLs don't match. Couldn't find tha t element.", request.filter, url, lastRightClickEvent.target.src);
535 break; 616 break;
536 case "clickhide-init": 617 case "clickhide-init":
537 if (clickHideFiltersDialog) 618 if (clickHideFiltersDialog)
538 { 619 {
539 sendResponse({filters: clickHide_filters}); 620 sendResponse({filters: clickHide_filters});
(...skipping 19 matching lines...) Expand all
559 640
560 clickHide_deactivate(); 641 clickHide_deactivate();
561 } 642 }
562 break; 643 break;
563 default: 644 default:
564 sendResponse({}); 645 sendResponse({});
565 break; 646 break;
566 } 647 }
567 }); 648 });
568 } 649 }
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