Commit 59dfe5a2 authored by lushnikov's avatar lushnikov Committed by Commit bot

DevTools: [SSP] render selectors effectively

Currently, the selectors in styles sidebar pane are rendered each in a
separate span, which makes them ctrl-clickable.

This is needed to help in SourceMap debugging, as different selectors
might be coming from different places in sources. (see crbug.com/266416)

However, as it generates a lot of DOM nodes, this patch stitches unmatched
selectors together in a single element. The selectors, however,
are rendered separately as the user hits Ctrl and hovers over the section.

BUG=628409
R=pfeldman, dgozman

Review-Url: https://codereview.chromium.org/2146233003
Cr-Commit-Position: refs/heads/master@{#405934}
parent d3e00ac3
......@@ -8,7 +8,7 @@ Running: addRule
element.style { ()
[expanded]
foo, [$#inspected$], .bar, [$#inspected$] { (inspector-stylesheet:1 -> inspector-stylesheet:1:6)
foo, [$#inspected, $].bar, [$#inspected$] { (inspector-stylesheet:1 -> inspector-stylesheet:1:6)
[expanded]
[$div$] { (user agent stylesheet)
......@@ -20,7 +20,7 @@ Running: changeSelector
element.style { ()
[expanded]
[$#inspected$], a, hr { (inspector-stylesheet:1 -> inspector-stylesheet:1:1)
[$#inspected, $]a, hr { (inspector-stylesheet:1 -> inspector-stylesheet:1:1)
[expanded]
[$div$] { (user agent stylesheet)
......
......@@ -25,7 +25,7 @@ element.style { ()
======== Pseudo ::before element ========
[expanded]
[$#inspected:before$], .some-other-selector { (pseudo-elements.html:4 -> pseudo-elements.html:4:1)
[$#inspected:before, $].some-other-selector { (pseudo-elements.html:4 -> pseudo-elements.html:4:1)
content: "BEFORE";
======== Pseudo ::after element ========
......@@ -36,7 +36,7 @@ element.style { ()
Running: dumpBeforeStyles
[expanded]
[$#inspected:before$], .some-other-selector { (pseudo-elements.html:4 -> pseudo-elements.html:4:1)
[$#inspected:before, $].some-other-selector { (pseudo-elements.html:4 -> pseudo-elements.html:4:1)
content: "BEFORE";
......
......@@ -7,7 +7,7 @@ element.style { ()
font-size: 12px;
[expanded]
foo, [$div#inspected$], bar { (inspector-stylesheet:1 -> inspector-stylesheet:1:6)
foo, [$div#inspected, $]bar { (inspector-stylesheet:1 -> inspector-stylesheet:1:6)
color: maroon;
[expanded]
......
......@@ -7,7 +7,7 @@ element.style { ()
font-size: 12px;
[expanded]
foo, [$div#inspected$], bar { (inspector-stylesheet:1 -> inspector-stylesheet:1:6)
foo, [$div#inspected, $]bar { (inspector-stylesheet:1 -> inspector-stylesheet:1:6)
color: maroon;
[expanded]
......
......@@ -7,7 +7,7 @@ element.style { ()
font-size: 12px;
[expanded]
foo, [$div#inspected$], bar { (inspector-stylesheet:1 -> inspector-stylesheet:1:6)
foo, [$div#inspected, $]bar { (inspector-stylesheet:1 -> inspector-stylesheet:1:6)
color: maroon;
[expanded]
......
......@@ -510,8 +510,13 @@ WebInspector.StylesSidebarPane.prototype = {
if (this._elementUnderMouse && event.target !== this._elementUnderMouse)
this._discardElementUnderMouse();
this._elementUnderMouse = event.target;
if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */(event)))
if (WebInspector.KeyboardShortcut.eventHasCtrlOrMeta(/** @type {!MouseEvent} */(event))) {
this._elementUnderMouse.classList.add("styles-panel-hovered");
var selectorElement = this._elementUnderMouse.enclosingNodeOrSelfWithClass("selector");
var sectionElement = selectorElement ? selectorElement.enclosingNodeOrSelfWithClass("styles-section") : null;
if (sectionElement)
sectionElement._section.makeHoverableSelectorsMode();
}
},
/**
......@@ -1129,6 +1134,14 @@ WebInspector.StylePropertiesSection.prototype = {
return !hideRule;
},
makeHoverableSelectorsMode: function()
{
if (this._hoverableSelectorsMode)
return;
this._hoverableSelectorsMode = true;
this._markSelectorMatches();
},
_markSelectorMatches: function()
{
var rule = this._style.parentRule;
......@@ -1140,29 +1153,72 @@ WebInspector.StylePropertiesSection.prototype = {
if (!this._matchedStyles.hasMatchingSelectors(/** @type {!WebInspector.CSSStyleRule} */(rule)))
return;
var selectors = rule.selectors;
var selectorTexts = rule.selectors.map(selector => selector.text);
var matchingSelectorIndexes = this._matchedStyles.matchingSelectors(/** @type {!WebInspector.CSSStyleRule} */(rule));
var matchingSelectors = new Array(selectorTexts.length).fill(false);
for (var matchingIndex of matchingSelectorIndexes)
matchingSelectors[matchingIndex] = true;
var fragment = this._hoverableSelectorsMode ? this._renderHoverableSelectors(selectorTexts, matchingSelectors) : this._renderSimplifiedSelectors(selectorTexts, matchingSelectors);
this._selectorElement.removeChildren();
this._selectorElement.appendChild(fragment);
this._markSelectorHighlights();
},
/**
* @param {!Array<string>} selectors
* @param {!Array<boolean>} matchingSelectors
* @return {!DocumentFragment}
*/
_renderHoverableSelectors: function(selectors, matchingSelectors)
{
var fragment = createDocumentFragment();
var currentMatch = 0;
var matchingSelectors = this._matchedStyles.matchingSelectors(/** @type {!WebInspector.CSSStyleRule} */(rule));
for (var i = 0; i < selectors.length ; ++i) {
if (i)
fragment.createTextChild(", ");
var isSelectorMatching = matchingSelectors[currentMatch] === i;
if (isSelectorMatching)
++currentMatch;
var matchingSelectorClass = isSelectorMatching ? " selector-matches" : "";
var selectorElement = createElement("span");
selectorElement.className = "simple-selector" + matchingSelectorClass;
if (rule.styleSheetId)
selectorElement._selectorIndex = i;
selectorElement.textContent = selectors[i].text;
fragment.appendChild(selectorElement);
fragment.appendChild(this._createSelectorElement(selectors[i], matchingSelectors[i], i));
}
return fragment;
},
this._selectorElement.removeChildren();
this._selectorElement.appendChild(fragment);
this._markSelectorHighlights();
/**
* @param {string} text
* @param {boolean} isMatching
* @param {number=} navigationIndex
* @return {!Element}
*/
_createSelectorElement: function(text, isMatching, navigationIndex)
{
var element = createElementWithClass("span", "simple-selector");
element.classList.toggle("selector-matches", isMatching);
if (typeof navigationIndex === "number")
element._selectorIndex = navigationIndex;
element.textContent = text;
return element;
},
/**
* @param {!Array<string>} selectors
* @param {!Array<boolean>} matchingSelectors
* @return {!DocumentFragment}
*/
_renderSimplifiedSelectors: function(selectors, matchingSelectors)
{
var fragment = createDocumentFragment();
var currentMatching = false;
var text = "";
for (var i = 0; i < selectors.length; ++i) {
if (currentMatching !== matchingSelectors[i] && text) {
fragment.appendChild(this._createSelectorElement(text, currentMatching));
text = "";
}
currentMatching = matchingSelectors[i];
text += selectors[i] + (i === selectors.length - 1 ? "" : ", ");
}
if (text)
fragment.appendChild(this._createSelectorElement(text, currentMatching));
return fragment;
},
_markSelectorHighlights: function()
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment