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

Unified 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.
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: include.postload.js
===================================================================
--- a/include.postload.js
+++ b/include.postload.js
@@ -19,45 +19,135 @@
var clickHide_activated = false;
var clickHide_filters = null;
var currentElement = null;
-var currentElement_boxShadow = null;
-var currentElement_backgroundColor;
var clickHideFilters = null;
var highlightedElementsSelector = null;
-var highlightedElementsBoxShadows = null;
-var highlightedElementsBGColors = null;
var clickHideFiltersDialog = null;
var lastRightClickEvent = null;
+function supportsShadowRoot(element)
+{
+ if (!("createShadowRoot" in element))
+ return false;
+
+ // There are some elements (e.g. <textarea>), which don't
+ // support author created shadow roots and throw an exception.
+ var clone = element.cloneNode(false);
+ try
+ {
+ clone.createShadowRoot();
+ }
+ catch (e)
+ {
+ return false;
+ }
+
+ // There are some elements (e.g. <input>), which support
+ // author created shadow roots, but ignore insertion points.
+ var child = document.createTextNode("");
+ clone.appendChild(child);
+
+ var shadow = document.createElement("shadow");
+ clone.shadowRoot.appendChild(shadow);
+
+ return shadow.getDistributedNodes()[0] == child;
+}
+
+function highlightElement(element, shadowColor, backgroundColor)
+{
+ unhighlightElement(element);
+
+ var originalBoxShadowPriority = element.style.getPropertyPriority("box-shadow");
+ var originalBackgroundColorPriority = element.style.getPropertyPriority("background-color");
+ var boxShadow = "inset 0px 0px 5px " + shadowColor;
+
+ var highlightWithStyleAttribute = function()
+ {
+ var originalBoxShadow = element.style.getPropertyValue("box-shadow");
+ var originalBackgroundColor = element.style.getPropertyValue("background-color");
+
+ element.style.setProperty("box-shadow", boxShadow, "important");
+ element.style.setProperty("background-color", backgroundColor, "important");
+
+ element._unhighlight = function()
+ {
+ this.style.removeProperty("box-shadow");
+ this.style.setProperty(
+ "box-shadow",
+ originalBoxShadow,
+ originalBoxShadowPriority
+ );
+
+ this.style.removeProperty("background-color");
+ this.style.setProperty(
+ "background-color",
+ originalBackgroundColor,
+ originalBackgroundColorPriority
+ );
+ };
+ };
+
+ var highlightWithShadowDOM = function()
+ {
+ var style = document.createElement("style");
+ style.textContent = ":host {" +
+ "box-shadow:" + boxShadow + " !important;" +
+ "background-color:" + backgroundColor + " !important;" +
+ "}";
+
+ var root = element.createShadowRoot();
+ root.appendChild(document.createElement("shadow"));
+ root.appendChild(style);
+
+ element._unhighlight = function()
+ {
+ root.removeChild(style);
+ };
+ };
+
+ // Use shadow DOM if posibble to avoid side effects when the
+ // web page updates style while highlighted. However, if the
+ // element has important styles we can't override them with shadow DOM.
+ if (supportsShadowRoot(element) && originalBoxShadowPriority != "important" &&
+ originalBackgroundColorPriority != "important")
+ highlightWithShadowDOM();
+ else
+ highlightWithStyleAttribute();
+}
+
+
+function unhighlightElement(element)
+{
+ if ("_unhighlight" in element)
+ {
+ element._unhighlight();
+ delete element._unhighlight;
+ }
+}
+
// Highlight elements according to selector string. This would include
// all elements that would be affected by proposed filters.
function highlightElements(selectorString) {
- if(highlightedElementsSelector)
- unhighlightElements();
+ unhighlightElements();
var highlightedElements = document.querySelectorAll(selectorString);
highlightedElementsSelector = selectorString;
- highlightedElementsBoxShadows = new Array();
- highlightedElementsBGColors = new Array();
- for(var i = 0; i < highlightedElements.length; i++) {
- highlightedElementsBoxShadows[i] = highlightedElements[i].style.getPropertyValue("-webkit-box-shadow");
- highlightedElementsBGColors[i] = highlightedElements[i].style.backgroundColor;
- highlightedElements[i].style.setProperty("-webkit-box-shadow", "inset 0px 0px 5px #fd6738");
- highlightedElements[i].style.backgroundColor = "#f6e1e5";
- }
+ for(var i = 0; i < highlightedElements.length; i++)
+ highlightElement(highlightedElements[i], "#fd6738", "#f6e1e5");
}
// Unhighlight all elements, including those that would be affected by
// the proposed filters
function unhighlightElements() {
- if(highlightedElementsSelector == null)
- return;
- var highlightedElements = document.querySelectorAll(highlightedElementsSelector);
- for(var i = 0; i < highlightedElements.length; i++) {
- highlightedElements[i].style.setProperty("-webkit-box-shadow", highlightedElementsBoxShadows[i]);
- highlightedElements[i].style.backgroundColor = highlightedElementsBGColors[i];
+ if (highlightedElementsSelector)
+ {
+ Array.prototype.forEach.call(
+ document.querySelectorAll(highlightedElementsSelector),
+ unhighlightElement
+ );
+
+ highlightedElementsSelector = null;
}
- highlightedElementsSelector = null;
}
// Gets the absolute position of an element by walking up the DOM tree,
@@ -183,8 +273,7 @@
if(currentElement) {
currentElement.removeEventListener("contextmenu", clickHide_elementClickHandler, false);
unhighlightElements();
- currentElement.style.setProperty("-webkit-box-shadow", currentElement_boxShadow);
- currentElement.style.backgroundColor = currentElement_backgroundColor;
+ unhighlightElement(currentElement);
currentElement = null;
clickHideFilters = null;
}
@@ -227,11 +316,8 @@
if (target && target instanceof HTMLElement)
{
currentElement = target;
- currentElement_boxShadow = target.style.getPropertyValue("-webkit-box-shadow");
- currentElement_backgroundColor = target.style.backgroundColor;
- target.style.setProperty("-webkit-box-shadow", "inset 0px 0px 5px #d6d84b");
- target.style.backgroundColor = "#f8fa47";
+ highlightElement(target, "#d6d84b", "#f8fa47");
target.addEventListener("contextmenu", clickHide_elementClickHandler, false);
}
}
@@ -242,9 +328,7 @@
if (!clickHide_activated || !currentElement)
return;
- currentElement.style.setProperty("-webkit-box-shadow", currentElement_boxShadow);
- currentElement.style.backgroundColor = currentElement_backgroundColor;
-
+ unhighlightElement(currentElement);
currentElement.removeEventListener("contextmenu", clickHide_elementClickHandler, false);
}
@@ -320,13 +404,11 @@
// Highlight the unlucky elements
// Restore currentElement's box-shadow and bgcolor so that highlightElements won't save those
- currentElement.style.setProperty("-webkit-box-shadow", currentElement_boxShadow);
- currentElement.style.backgroundColor = currentElement_backgroundColor;
+ unhighlightElement(currentElement);
// Highlight the elements specified by selector in yellow
highlightElements(selectorList.join(","));
// Now, actually highlight the element the user clicked on in red
- currentElement.style.setProperty("-webkit-box-shadow", "inset 0px 0px 5px #fd1708");
- currentElement.style.backgroundColor = "#f6a1b5";
+ highlightElement(currentElement, "#fd1708", "#f6a1b5");
// Make sure the browser doesn't handle this click
e.preventDefault();
@@ -526,7 +608,6 @@
// Coerce red highlighted overlay on top of element to remove.
// TODO: Wow, the design of the clickHide stuff is really dumb - gotta fix it sometime
currentElement = addElementOverlay(target);
- currentElement_backgroundColor = target.style.backgroundColor;
// clickHide_mouseOver(lastRightClickEvent);
clickHide_mouseClick(lastRightClickEvent);
}
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld