diff --git a/front_end/css_overview/CSSOverviewCompletedView.js b/front_end/css_overview/CSSOverviewCompletedView.js
index 4665b54e18..ab21c79c2a 100644
--- a/front_end/css_overview/CSSOverviewCompletedView.js
+++ b/front_end/css_overview/CSSOverviewCompletedView.js
@@ -12,21 +12,36 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
this._controller = controller;
this._formatter = new Intl.NumberFormat('en-US');
- this._mainContainer = new UI.VBox();
+
+ this._mainContainer = new UI.SplitWidget(true, true);
+ this._resultsContainer = new UI.VBox();
+ this._elementContainer = new UI.VBox();
+
+ // Dupe the styles into the main container because of the shadow root will prevent outer styles.
+ this._mainContainer.registerRequiredCSS('css_overview/cssOverviewCompletedView.css');
+
+ this._mainContainer.setMainWidget(this._resultsContainer);
+ this._mainContainer.setSidebarWidget(this._elementContainer);
+ this._mainContainer.setVertical(false);
+ this._mainContainer.setSecondIsSidebar(true);
+ this._mainContainer.setSidebarMinimized(true);
this._sideBar = new CssOverview.CSSOverviewSidebarPanel();
this.splitWidget().setSidebarWidget(this._sideBar);
this.splitWidget().setMainWidget(this._mainContainer);
this._cssModel = target.model(SDK.CSSModel);
+ this._domModel = target.model(SDK.DOMModel);
+ this._domAgent = target.domAgent();
this._linkifier = new Components.Linkifier(/* maxLinkLength */ 20, /* useLinkDecorator */ true);
+ this._relatedNodesMap = new Map();
- this._columns = [
+ this._mediaQueryColumns = [
{id: 'text', title: ls`Text`, visible: true, sortable: true, weight: 60},
{id: 'sourceURL', title: ls`Source`, visible: true, sortable: true, weight: 40}
];
- this._mediaQueryGrid = new DataGrid.SortableDataGrid(this._columns);
+ this._mediaQueryGrid = new DataGrid.SortableDataGrid(this._mediaQueryColumns);
this._mediaQueryGrid.element.classList.add('media-query-grid');
this._mediaQueryGrid.setStriped(true);
this._mediaQueryGrid.addEventListener(
@@ -37,10 +52,20 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
this._sideBar.addItem(ls`Media queries`, 'media-queries');
this._sideBar.select('summary');
+ this._elementGridColumns = [{id: 'nodeId', title: ls`Element`, visible: true, sortable: true, weight: 100}];
+
+ this._elementGrid = new DataGrid.SortableDataGrid(this._elementGridColumns);
+ this._elementGrid.element.classList.add('element-grid');
+ this._elementGrid.element.addEventListener('mouseover', this._onMouseOver.bind(this));
+ this._elementGrid.setStriped(true);
+
this._sideBar.addEventListener(CssOverview.SidebarEvents.ItemSelected, this._sideBarItemSelected, this);
this._sideBar.addEventListener(CssOverview.SidebarEvents.Reset, this._sideBarReset, this);
this._controller.addEventListener(CssOverview.Events.Reset, this._reset, this);
- this._render({});
+ this._controller.addEventListener(CssOverview.Events.PopulateNodes, this._populateNodes, this);
+ this._resultsContainer.element.addEventListener('click', this._onClick.bind(this));
+
+ this._data = null;
}
_sortMediaQueryDataGrid() {
@@ -67,20 +92,53 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
}
_reset() {
- this._mainContainer.element.removeChildren();
+ this._resultsContainer.element.removeChildren();
this._mediaQueryGrid.rootNode().removeChildren();
+ this._elementGrid.rootNode().removeChildren();
+ this._relatedNodesMap = new Map();
+ this._mainContainer.setSidebarMinimized(true);
}
- _render(data) {
- if (!(data && ('textColors' in data) && ('backgroundColors' in data))) {
+ _onClick(evt) {
+ const color = evt.target.dataset.color;
+ const section = evt.target.dataset.section;
+ if (!color) {
return;
}
- const {elementStyleStats, elementCount, backgroundColors, textColors, globalStyleStats, mediaQueries} = data;
+ const colorNodes =
+ section === 'background' ? this._data.backgroundColors.get(color) : this._data.textColors.get(color);
+ if (!colorNodes) {
+ return;
+ }
+
+ evt.consume();
+ this._controller.dispatchEventToListeners(CssOverview.Events.PopulateNodes, {color, colorNodes});
+ }
+
+ _onMouseOver(evt) {
+ // Traverse the event path on the grid to find the nearest element with a backend node ID attached. Use
+ // that for the highlighting.
+ const node = evt.path.find(el => el.dataset && el.dataset.backendNodeId);
+ if (!node) {
+ return;
+ }
+
+ const backendNodeId = Number(node.dataset.backendNodeId);
+ this._controller.dispatchEventToListeners(CssOverview.Events.RequestNodeHighlight, backendNodeId);
+ }
+
+ _render(data) {
+ if (!data || !('backgroundColors' in data) || !('textColors' in data)) {
+ return;
+ }
+
+ this._data = data;
+ const {elementCount, backgroundColors, textColors, globalStyleStats, mediaQueries} = this._data;
// Convert rgb values from the computed styles to either undefined or HEX(A) strings.
- const nonTransparentBackgroundColors = this._getNonTransparentColorStrings(backgroundColors);
- const nonTransparentTextColors = this._getNonTransparentColorStrings(textColors);
+ const sortedBackgroundColors = this._sortColorsByLuminance(backgroundColors);
+ const sortedTextColors = this._sortColorsByLuminance(textColors);
this._fragment = UI.Fragment.build`
@@ -110,47 +168,49 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
${ls`Type selectors`}
- ${this._formatter.format(elementStyleStats.type.size)}
+ ${this._formatter.format(globalStyleStats.stats.type)}
${ls`ID selectors`}
- ${this._formatter.format(elementStyleStats.id.size)}
+ ${this._formatter.format(globalStyleStats.stats.id)}
${ls`Class selectors`}
- ${this._formatter.format(elementStyleStats.class.size)}
+ ${this._formatter.format(globalStyleStats.stats.class)}
${ls`Universal selectors`}
- ${this._formatter.format(elementStyleStats.universal.size)}
+ ${this._formatter.format(globalStyleStats.stats.universal)}
${ls`Attribute selectors`}
- ${this._formatter.format(elementStyleStats.attribute.size)}
+ ${this._formatter.format(globalStyleStats.stats.attribute)}
${ls`Non-simple selectors`}
- ${this._formatter.format(elementStyleStats.nonSimple.size)}
+ ${this._formatter.format(globalStyleStats.stats.nonSimple)}
${ls`Colors`}
-
${ls`Unique background colors: ${nonTransparentBackgroundColors.length}`}
+
${ls`Unique background colors: ${sortedBackgroundColors.length}`}
- ${nonTransparentBackgroundColors.map(this._colorsToFragment)}
+ ${sortedBackgroundColors.map(this._colorsToFragment.bind(this, 'background'))}
-
${ls`Unique text colors: ${nonTransparentTextColors.length}`}
+
${ls`Unique text colors: ${sortedTextColors.length}`}
- ${nonTransparentTextColors.map(this._colorsToFragment)}
+ ${sortedTextColors.map(this._colorsToFragment.bind(this, 'text'))}
+
+
${ls`Media queries`}
- ${this._mediaQueryGrid.element}
+ ${mediaQueries.length > 0 ? this._mediaQueryGrid.element : `There are no media queries.`}
`;
@@ -162,23 +222,47 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
this._mediaQueryGrid.insertChild(mediaQueryNode);
}
- this._mainContainer.element.appendChild(this._fragment.element());
+ this._resultsContainer.element.appendChild(this._fragment.element());
+ this._elementContainer.element.appendChild(this._elementGrid.element);
+
this._mediaQueryGrid.renderInline();
this._mediaQueryGrid.wasShown();
}
- _colorsToFragment(color) {
- const colorFormatted =
- color.hasAlpha() ? color.asString(Common.Color.Format.HEXA) : color.asString(Common.Color.Format.HEX);
+ async _populateNodes(evt) {
+ this._elementGrid.rootNode().removeChildren();
+
+ const {color, colorNodes} = evt.data;
+ let relatedNodesMap = this._relatedNodesMap.get(color);
+ if (!relatedNodesMap) {
+ // This process can't be repeated so we need to now capture the Nodes and hold them in case we need to revisit
+ // the same set again.
+ relatedNodesMap = await this._domModel.pushNodesByBackendIdsToFrontend(colorNodes);
+ this._relatedNodesMap.set(color, relatedNodesMap);
+ }
+
+ for (const domNode of relatedNodesMap.values()) {
+ const colorNode = new CssOverview.CSSOverviewCompletedView.ColorNode(this._elementGrid, domNode, this._linkifier);
+ colorNode.selectable = false;
+ this._elementGrid.insertChild(colorNode);
+ }
+
+ this._mainContainer.setSidebarMinimized(false);
+ this._elementGrid.renderInline();
+ this._elementGrid.wasShown();
+ }
+
+ _colorsToFragment(section, color) {
const blockFragment = UI.Fragment.build`
-
- ${colorFormatted}
+
+ ${color}
`;
const block = blockFragment.$('color');
- block.style.backgroundColor = colorFormatted;
+ block.style.backgroundColor = color;
- let [h, s, l] = color.hsla();
+ const borderColor = Common.Color.parse(color);
+ let [h, s, l] = borderColor.hsla();
h = Math.round(h * 360);
s = Math.round(s * 100);
l = Math.round(l * 100);
@@ -192,18 +276,10 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
return blockFragment;
}
- _getNonTransparentColorStrings(srcColors) {
- const colors = [];
- for (const colorText of Array.from(srcColors)) {
- const color = Common.Color.parse(colorText);
- if (color.rgba()[3] === 0) {
- continue;
- }
-
- colors.push(color);
- }
-
- return colors.sort((colorA, colorB) => {
+ _sortColorsByLuminance(srcColors) {
+ return Array.from(srcColors.keys()).sort((colA, colB) => {
+ const colorA = Common.Color.parse(colA);
+ const colorB = Common.Color.parse(colB);
return Common.Color.luminance(colorB.rgba()) - Common.Color.luminance(colorA.rgba());
});
}
@@ -242,7 +318,7 @@ CssOverview.CSSOverviewCompletedView.MediaQueryNode = class extends DataGrid.Sor
if (link.textContent !== '') {
cell.appendChild(link);
} else {
- cell.textContent = `${this.data.sourceURL} (not available)`;
+ cell.textContent = `(unable to link)`;
}
return cell;
}
@@ -258,3 +334,37 @@ CssOverview.CSSOverviewCompletedView.MediaQueryNode = class extends DataGrid.Sor
return linkifier.linkifyCSSLocation(matchingSelectorLocation);
}
};
+
+CssOverview.CSSOverviewCompletedView.ColorNode = class extends DataGrid.SortableDataGridNode {
+ /**
+ * @param {!DataGrid.SortableDataGrid} dataGrid
+ * @param {!Object} colorData
+ * @param {!Components.Linkifier} linkifier
+ */
+ constructor(dataGrid, colorData, linkifier) {
+ super(dataGrid, colorData.hasChildren);
+
+ this.data = colorData;
+ this._linkifier = linkifier;
+ }
+
+ /**
+ * @override
+ * @param {string} columnId
+ * @return {!Element}
+ */
+ createCell(columnId) {
+ if (columnId === 'nodeId') {
+ const cell = this.createTD(columnId);
+ cell.textContent = '...';
+ Common.Linkifier.linkify(this.data).then(link => {
+ cell.textContent = '';
+ link.dataset.backendNodeId = this.data.backendNodeId();
+ cell.appendChild(link);
+ });
+ return cell;
+ }
+
+ return super.createCell(columnId);
+ }
+};
diff --git a/front_end/css_overview/CSSOverviewController.js b/front_end/css_overview/CSSOverviewController.js
index 3ff6f293b2..eaaf529495 100644
--- a/front_end/css_overview/CSSOverviewController.js
+++ b/front_end/css_overview/CSSOverviewController.js
@@ -19,6 +19,8 @@ CssOverview.OverviewController = class extends Common.Object {
CssOverview.Events = {
RequestOverviewStart: Symbol('RequestOverviewStart'),
+ RequestNodeHighlight: Symbol('RequestNodeHighlight'),
+ PopulateNodes: Symbol('PopulateNodes'),
RequestOverviewCancel: Symbol('RequestOverviewCancel'),
OverviewCompleted: Symbol('OverviewCompleted'),
Reset: Symbol('Reset'),
diff --git a/front_end/css_overview/CSSOverviewModel.js b/front_end/css_overview/CSSOverviewModel.js
index 7881c0b365..d4a5480326 100644
--- a/front_end/css_overview/CSSOverviewModel.js
+++ b/front_end/css_overview/CSSOverviewModel.js
@@ -15,12 +15,87 @@ CssOverview.CSSOverviewModel = class extends SDK.SDKModel {
this._runtimeAgent = target.runtimeAgent();
this._cssAgent = target.cssAgent();
this._domAgent = target.domAgent();
+ this._domSnapshotAgent = target.domsnapshotAgent();
+ this._overlayAgent = target.overlayAgent();
}
getFlattenedDocument() {
return this._domAgent.getFlattenedDocument(-1, true);
}
+ highlightNode(node) {
+ const highlightConfig = {contentColor: Common.Color.PageHighlight.Content.toProtocolRGBA(), showInfo: true};
+
+ this._overlayAgent.invoke_hideHighlight({});
+ this._overlayAgent.invoke_highlightNode({backendNodeId: node, highlightConfig});
+ }
+
+ async getNodeStyleStats() {
+ const backgroundColors = new Map();
+ const textColors = new Map();
+ const fontSizes = new Map();
+ const fontWeights = new Map();
+ const snapshotConfig = {computedStyles: ['background-color', 'color', 'font-size', 'font-weight']};
+
+ const storeColor = (id, nodeId, target) => {
+ if (id === -1) {
+ return;
+ }
+
+ // Parse the color, discard transparent ones.
+ const colorText = strings[id];
+ const color = Common.Color.parse(colorText);
+ if (color.rgba()[3] === 0) {
+ return;
+ }
+
+ // Format the color and use as the key.
+ const colorFormatted =
+ color.hasAlpha() ? color.asString(Common.Color.Format.HEXA) : color.asString(Common.Color.Format.HEX);
+
+ // Get the existing set of nodes with the color, or create a new set.
+ const colorValues = target.get(colorFormatted) || new Set();
+ colorValues.add(nodeId);
+
+ // Store.
+ target.set(colorFormatted, colorValues);
+ };
+
+ const {documents, strings} = await this._domSnapshotAgent.invoke_captureSnapshot(snapshotConfig);
+ for (const {nodes, layout} of documents) {
+ for (let idx = 0; idx < layout.styles.length; idx++) {
+ const styles = layout.styles[idx];
+ const nodeIdx = layout.nodeIndex[idx];
+ const nodeId = nodes.backendNodeId[nodeIdx];
+
+ // Skip text nodes.
+ const nodeType = nodes.nodeType[idx];
+ if (nodeType === Node.TEXT_NODE) {
+ continue;
+ }
+
+ const [backgroundColorIdx, textColorIdx, fontSizeIdx, fontWeightIdx] = styles;
+
+ storeColor(backgroundColorIdx, nodeId, backgroundColors);
+ storeColor(textColorIdx, nodeId, textColors);
+
+ if (fontSizeIdx !== -1) {
+ const fontSize = strings[fontSizeIdx];
+ const fontSizeInstances = (fontSizes.get(fontSize) || 0) + 1;
+ fontSizes.set(fontSize, fontSizeInstances);
+ }
+
+ if (fontWeightIdx !== -1) {
+ const fontWeight = strings[fontWeightIdx];
+ const fontWeightInstances = (fontWeights.get(fontWeight) || 0) + 1;
+ fontWeights.set(fontWeight, fontWeightInstances);
+ }
+ }
+ }
+
+ return {backgroundColors, textColors, fontSizes, fontWeights};
+ }
+
getComputedStyleForNode(nodeId) {
return this._cssAgent.getComputedStyleForNode(nodeId);
}
@@ -38,16 +113,65 @@ CssOverview.CSSOverviewModel = class extends SDK.SDKModel {
let styleRules = 0;
let inlineStyles = 0;
let externalSheets = 0;
- for (const { rules, href } of document.styleSheets) {
- if (href) {
+ const stats = {
+ // Simple.
+ type: new Set(),
+ class: new Set(),
+ id: new Set(),
+ universal: new Set(),
+ attribute: new Set(),
+
+ // Non-simple.
+ nonSimple: new Set()
+ };
+
+ for (const styleSheet of document.styleSheets) {
+ if (styleSheet.href) {
externalSheets++;
} else {
inlineStyles++;
}
+ // Attempting to grab rules can trigger a DOMException.
+ // Try it and if it fails skip to the next stylesheet.
+ let rules;
+ try {
+ rules = styleSheet.rules;
+ } catch (err) {
+ continue;
+ }
+
for (const rule of rules) {
if ('selectorText' in rule) {
styleRules++;
+
+ // Each group that was used.
+ for (const selectorGroup of rule.selectorText.split(',')) {
+ // Each selector in the group.
+ for (const selector of selectorGroup.split(\/[\\t\\n\\f\\r ]+\/g)) {
+ if (selector.startsWith('.')) {
+ // Class.
+ stats.class.add(selector);
+ } else if (selector.startsWith('#')) {
+ // Id.
+ stats.id.add(selector);
+ } else if (selector.startsWith('*')) {
+ // Universal.
+ stats.universal.add(selector);
+ } else if (selector.startsWith('[')) {
+ // Attribute.
+ stats.attribute.add(selector);
+ } else {
+ // Type or non-simple selector.
+ const specialChars = \/[#\.:\\[\\]|\\+>~]\/;
+ if (specialChars.test(selector)) {
+ stats.nonSimple.add(selector);
+ } else {
+ stats.type.add(selector);
+ }
+ }
+ }
+ }
}
}
}
@@ -55,7 +179,18 @@ CssOverview.CSSOverviewModel = class extends SDK.SDKModel {
return {
styleRules,
inlineStyles,
- externalSheets
+ externalSheets,
+ stats: {
+ // Simple.
+ type: stats.type.size,
+ class: stats.class.size,
+ id: stats.id.size,
+ universal: stats.universal.size,
+ attribute: stats.attribute.size,
+
+ // Non-simple.
+ nonSimple: stats.nonSimple.size
+ }
}
})()`;
const {result} = await this._runtimeAgent.invoke_evaluate({expression, returnByValue: true});
@@ -67,70 +202,6 @@ CssOverview.CSSOverviewModel = class extends SDK.SDKModel {
return result.value;
}
-
- async getStylesStatsForNode(nodeId) {
- const stats = {
- // Simple.
- type: new Set(),
- class: new Set(),
- id: new Set(),
- universal: new Set(),
- attribute: new Set(),
-
- // Non-simple.
- nonSimple: new Set()
- };
-
- const matches = await this._cssAgent.invoke_getMatchedStylesForNode({nodeId});
- if (!matches || !matches.matchedCSSRules || !matches.matchedCSSRules.length) {
- return;
- }
-
- matches.matchedCSSRules.forEach(cssRule => {
- const {matchingSelectors} = cssRule;
- const {origin, selectorList} = cssRule.rule;
- const isExternalSheet = origin === 'regular';
- if (!isExternalSheet || !selectorList) {
- return;
- }
-
-
- const selectors = matchingSelectors.map(idx => selectorList.selectors[idx]);
-
- // Each group of selectors, e.g. foo.baz, foo .bar, foo { ... }
- for (const {text} of selectors) {
- // Each group that was used.
- for (const selectorGroup of text.split(',')) {
- // Each selector in the group.
- for (const selector of selectorGroup.split(/[\t\n\f\r ]+/g)) {
- if (selector.startsWith('.')) {
- // Class.
- stats.class.add(selector);
- } else if (selector.startsWith('#')) {
- // Id.
- stats.id.add(selector);
- } else if (selector.startsWith('*')) {
- // Universal.
- stats.universal.add(selector);
- } else if (selector.startsWith('[')) {
- // Attribute.
- stats.attribute.add(selector);
- } else {
- // Type or non-simple selector.
- const specialChars = /[#\.:\[\]|\+>~]/;
- if (specialChars.test(selector)) {
- stats.nonSimple.add(selector);
- } else {
- stats.type.add(selector);
- }
- }
- }
- }
- }
- });
-
- return stats;
- }
};
SDK.SDKModel.register(CssOverview.CSSOverviewModel, SDK.Target.Capability.DOM, false);
diff --git a/front_end/css_overview/CSSOverviewPanel.js b/front_end/css_overview/CSSOverviewPanel.js
index e69d43bc93..a4b6f6699a 100644
--- a/front_end/css_overview/CSSOverviewPanel.js
+++ b/front_end/css_overview/CSSOverviewPanel.js
@@ -23,32 +23,42 @@ CssOverview.CSSOverviewPanel = class extends UI.Panel {
this._controller.addEventListener(CssOverview.Events.RequestOverviewCancel, this._cancelOverview, this);
this._controller.addEventListener(CssOverview.Events.OverviewCompleted, this._overviewCompleted, this);
this._controller.addEventListener(CssOverview.Events.Reset, this._reset, this);
+ this._controller.addEventListener(CssOverview.Events.RequestNodeHighlight, this._requestNodeHighlight, this);
this._reset();
}
_reset() {
- this._backgroundColors = new Set();
- this._textColors = new Set();
+ this._backgroundColors = new Map();
+ this._textColors = new Map();
this._fontSizes = new Map();
+ this._fontWeights = new Map();
this._mediaQueries = [];
this._elementCount = 0;
- this._elementStyleStats = {
- // Simple.
- type: new Set(),
- class: new Set(),
- id: new Set(),
- universal: new Set(),
- attribute: new Set(),
-
- // Non-simple.
- nonSimple: new Set()
- };
this._cancelled = false;
- this._globalStyleStats = {styleRules: 0, inlineStyles: 0, externalSheets: 0};
+ this._globalStyleStats = {
+ styleRules: 0,
+ inlineStyles: 0,
+ externalSheets: 0,
+ stats: {
+ // Simple.
+ type: 0,
+ class: 0,
+ id: 0,
+ universal: 0,
+ attribute: 0,
+
+ // Non-simple.
+ nonSimple: 0
+ }
+ };
this._renderInitialView();
}
+ _requestNodeHighlight(evt) {
+ this._model.highlightNode(evt.data);
+ }
+
_renderInitialView() {
this._processingView.hideWidget();
this._completedView.hideWidget();
@@ -56,12 +66,11 @@ CssOverview.CSSOverviewPanel = class extends UI.Panel {
this._startView.show(this.contentElement);
}
- _renderOverviewStartedView(elementsHandled = 0, total = 0) {
+ _renderOverviewStartedView() {
this._startView.hideWidget();
this._completedView.hideWidget();
this._processingView.show(this.contentElement);
- this._processingView.setElementsHandled(elementsHandled, total);
}
_renderOverviewCompletedView() {
@@ -73,8 +82,8 @@ CssOverview.CSSOverviewPanel = class extends UI.Panel {
backgroundColors: this._backgroundColors,
textColors: this._textColors,
globalStyleStats: this._globalStyleStats,
- elementStyleStats: this._elementStyleStats,
fontSizes: this._fontSizes,
+ fontWeights: this._fontWeights,
elementCount: this._elementCount,
mediaQueries: this._mediaQueries
});
@@ -83,74 +92,40 @@ CssOverview.CSSOverviewPanel = class extends UI.Panel {
async _startOverview() {
this._renderOverviewStartedView();
- const document = await this._model.getFlattenedDocument();
- if (this._cancelled) {
- this._reset();
- return;
+ const [nodes, globalStyleStats, {backgroundColors, textColors, fontSizes, fontWeights}, mediaQueries] =
+ await Promise.all([
+ this._model.getFlattenedDocument(), this._model.getGlobalStylesheetStats(), this._model.getNodeStyleStats(),
+ this._model.getMediaQueries()
+ ]);
+
+ if (nodes) {
+ this._elementCount = nodes.length;
}
- // 1. Get the global style stats.
- const globalStyleStats = await this._model.getGlobalStylesheetStats();
if (globalStyleStats) {
this._globalStyleStats = globalStyleStats;
}
- const mediaQueries = await this._model.getMediaQueries();
if (mediaQueries) {
this._mediaQueries = mediaQueries;
}
- // 2. Get the total element count.
- this._elementCount = document.length;
-
- // 3. Process every element in the doc.
- for (let idx = 0; idx < document.length; idx++) {
- if (this._cancelled) {
- this._reset();
- return;
- }
-
- const node = document[idx];
- const [computedStyles, styleStats] = await Promise.all(
- [this._model.getComputedStyleForNode(node.nodeId), this._model.getStylesStatsForNode(node.nodeId)]);
-
- // 3a. Capture any colors from the computed styles.
- if (computedStyles) {
- const backgroundColor = this._getStyleValue(computedStyles, 'background-color');
- if (backgroundColor) {
- this._backgroundColors.add(backgroundColor);
- }
-
- if (node.nodeType === Node.TEXT_NODE) {
- const textColor = this._getStyleValue(computedStyles, 'color');
- this._textColors.add(textColor);
-
- const fontSize = this._getStyleValue(computedStyles, 'font-size');
- if (!this._fontSizes.has(fontSize)) {
- this._fontSizes.set(fontSize, 0);
- }
-
- this._fontSizes.set(fontSize, this._fontSizes.get(fontSize) + 1);
- }
- }
-
- // 3b. Tally the selector stats.
- if (styleStats) {
- for (const section of Object.keys(this._elementStyleStats)) {
- if (!styleStats[section]) {
- continue;
- }
-
- for (const value of styleStats[section]) {
- this._elementStyleStats[section].add(value);
- }
- }
- }
-
- this._renderOverviewStartedView(idx + 1, document.length);
+ if (backgroundColors) {
+ this._backgroundColors = backgroundColors;
+ }
+
+ if (textColors) {
+ this._textColors = textColors;
+ }
+
+ if (fontSizes) {
+ this._fontSizes = fontSizes;
+ }
+
+ if (fontWeights) {
+ this._fontWeights = fontWeights;
}
- // 4. Finish.
this._controller.dispatchEventToListeners(CssOverview.Events.OverviewCompleted);
}
diff --git a/front_end/css_overview/CSSOverviewProcessingView.js b/front_end/css_overview/CSSOverviewProcessingView.js
index 169c363bcd..92820be0ef 100644
--- a/front_end/css_overview/CSSOverviewProcessingView.js
+++ b/front_end/css_overview/CSSOverviewProcessingView.js
@@ -25,20 +25,10 @@ CssOverview.CSSOverviewProcessingView = class extends UI.Widget {
Processing page
${cancelButton}
-
-
`;
this.contentElement.appendChild(this.fragment.element());
this.contentElement.style.overflow = 'auto';
}
-
- setElementsHandled(handled = 0, total = 0) {
- // TODO(aerotwist): We might want to switch this to using Intl.PluralRules in the future
- // @see https://v8.dev/features/intl-pluralrules
- const elementsTotal = total > 0 ? ls`document elements` : ls`document element`;
- this.fragment.$('processed').textContent =
- ls`Processed ${this._formatter.format(handled)} of ${this._formatter.format(total)} ${elementsTotal}.`;
- }
};
diff --git a/front_end/css_overview/cssOverviewCompletedView.css b/front_end/css_overview/cssOverviewCompletedView.css
index 5967edfed0..52636c5be2 100644
--- a/front_end/css_overview/cssOverviewCompletedView.css
+++ b/front_end/css_overview/cssOverviewCompletedView.css
@@ -54,7 +54,14 @@
.media-query-grid .data-container {
top: 0;
- max-height: 400px;
+ max-height: 350px;
+}
+
+.element-grid {
+ flex: 1;
+ border-left: none;
+ border-right: none;
+ overflow: auto;
}
.block {
diff --git a/front_end/css_overview/css_overview_strings.grdp b/front_end/css_overview/css_overview_strings.grdp
index aa7d406222..d59a339305 100644
--- a/front_end/css_overview/css_overview_strings.grdp
+++ b/front_end/css_overview/css_overview_strings.grdp
@@ -12,18 +12,15 @@
Overview summary
+
+ Element
+
Universal selectors
-
- document element
-
Unique text colors: $1s32
-
- Processed $1s23 of $2s1,223 $3sdocument elements.
-
Colors
@@ -42,9 +39,6 @@
External stylesheets
-
- document elements
-
Type selectors
diff --git a/front_end/css_overview/module.json b/front_end/css_overview/module.json
index 7245192e07..bc9317d58f 100644
--- a/front_end/css_overview/module.json
+++ b/front_end/css_overview/module.json
@@ -1,35 +1,36 @@
{
- "extensions": [
- {
- "type": "view",
- "location": "panel",
- "id": "cssoverview",
- "title": "CSS Overview",
- "className": "CssOverview.CSSOverviewPanel",
- "order": 95,
- "experiment": "cssOverview"
- }
- ],
- "dependencies": [
- "elements",
- "ui",
- "sdk",
- "data_grid"
- ],
- "scripts": [
- "CSSOverviewController.js",
- "CSSOverviewModel.js",
- "CSSOverviewStartView.js",
- "CSSOverviewProcessingView.js",
- "CSSOverviewCompletedView.js",
- "CSSOverviewSidebarPanel.js",
- "CSSOverviewPanel.js"
+ "extensions": [
+ {
+ "type": "view",
+ "location": "panel",
+ "id": "cssoverview",
+ "title": "CSS Overview",
+ "className": "CssOverview.CSSOverviewPanel",
+ "order": 95,
+ "experiment": "cssOverview"
+ }
],
- "resources": [
- "cssOverview.css",
- "cssOverviewStartView.css",
- "cssOverviewProcessingView.css",
- "cssOverviewCompletedView.css",
- "cssOverviewSidebarPanel.css"
- ]
-}
+ "dependencies": [
+ "elements",
+ "ui",
+ "sdk",
+ "data_grid",
+ "extensions"
+ ],
+ "scripts": [
+ "CSSOverviewController.js",
+ "CSSOverviewModel.js",
+ "CSSOverviewStartView.js",
+ "CSSOverviewProcessingView.js",
+ "CSSOverviewCompletedView.js",
+ "CSSOverviewSidebarPanel.js",
+ "CSSOverviewPanel.js"
+ ],
+ "resources": [
+ "cssOverview.css",
+ "cssOverviewStartView.css",
+ "cssOverviewProcessingView.css",
+ "cssOverviewCompletedView.css",
+ "cssOverviewSidebarPanel.css"
+ ]
+ }