Commit 193ed603 authored by Paul Lewis's avatar Paul Lewis Committed by Commit Bot

[DevTools] Adds media queries to CSS Overview

Bug: 1007284
Change-Id: I8c24adddf91da3bd621b61db6eac49233b8a1db4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1849671
Commit-Queue: Paul Lewis <aerotwist@chromium.org>
Reviewed-by: default avatarTim van der Lippe <tvanderlippe@chromium.org>
Cr-Commit-Position: refs/heads/master@{#704192}
parent f46729a8
......@@ -6,7 +6,7 @@
* @unrestricted
*/
CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
constructor(controller) {
constructor(controller, target) {
super('css_overview_completed_view');
this.registerRequiredCSS('css_overview/cssOverviewCompletedView.css');
......@@ -18,8 +18,23 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
this.splitWidget().setSidebarWidget(this._sideBar);
this.splitWidget().setMainWidget(this._mainContainer);
this._cssModel = target.model(SDK.CSSModel);
this._linkifier = new Components.Linkifier(/* maxLinkLength */ 20, /* useLinkDecorator */ true);
this._columns = [
{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.element.classList.add('media-query-grid');
this._mediaQueryGrid.setStriped(true);
this._mediaQueryGrid.addEventListener(
DataGrid.DataGrid.Events.SortingChanged, this._sortMediaQueryDataGrid.bind(this));
this._sideBar.addItem(ls`Overview summary`, 'summary');
this._sideBar.addItem(ls`Colors`, 'colors');
this._sideBar.addItem(ls`Media queries`, 'media-queries');
this._sideBar.select('summary');
this._sideBar.addEventListener(CssOverview.SidebarEvents.ItemSelected, this._sideBarItemSelected, this);
......@@ -28,6 +43,16 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
this._render({});
}
_sortMediaQueryDataGrid() {
const sortColumnId = this._mediaQueryGrid.sortColumnId();
if (!sortColumnId) {
return;
}
const comparator = DataGrid.SortableDataGrid.StringComparator.bind(null, sortColumnId);
this._mediaQueryGrid.sortNodes(comparator, !this._mediaQueryGrid.isSortOrderAscending());
}
_sideBarItemSelected(event) {
const section = this._fragment.$(event.data);
if (!section) {
......@@ -43,6 +68,7 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
_reset() {
this._mainContainer.element.removeChildren();
this._mediaQueryGrid.rootNode().removeChildren();
}
_render(data) {
......@@ -50,7 +76,7 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
return;
}
const {elementStyleStats, elementCount, backgroundColors, textColors, globalStyleStats} = data;
const {elementStyleStats, elementCount, backgroundColors, textColors, globalStyleStats, mediaQueries} = data;
// Convert rgb values from the computed styles to either undefined or HEX(A) strings.
const nonTransparentBackgroundColors = this._getNonTransparentColorStrings(backgroundColors);
......@@ -79,8 +105,8 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
<div class="value">${this._formatter.format(globalStyleStats.styleRules)}</div>
</li>
<li>
<div class="label">${ls`Media rules`}</div>
<div class="value">${this._formatter.format(globalStyleStats.mediaRules)}</div>
<div class="label">${ls`Media queries`}</div>
<div class="value">${this._formatter.format(mediaQueries.length)}</div>
</li>
<li>
<div class="label">${ls`Type selectors`}</div>
......@@ -121,9 +147,24 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
${nonTransparentTextColors.map(this._colorsToFragment)}
</ul>
</div>
<div $="media-queries" class="results-section media-queries">
<h1>${ls`Media queries`}</h1>
${this._mediaQueryGrid.element}
</div>
</div>`;
// Media Queries.
for (const mediaQuery of mediaQueries) {
const mediaQueryNode = new CssOverview.CSSOverviewCompletedView.MediaQueryNode(
this._mediaQueryGrid, mediaQuery, this._cssModel, this._linkifier);
mediaQueryNode.selectable = false;
this._mediaQueryGrid.insertChild(mediaQueryNode);
}
this._mainContainer.element.appendChild(this._fragment.element());
this._mediaQueryGrid.renderInline();
this._mediaQueryGrid.wasShown();
}
_colorsToFragment(color) {
......@@ -168,3 +209,49 @@ CssOverview.CSSOverviewCompletedView = class extends UI.PanelWithSidebar {
this._render(data);
}
};
CssOverview.CSSOverviewCompletedView.MediaQueryNode = class extends DataGrid.SortableDataGridNode {
/**
* @param {!DataGrid.SortableDataGrid} dataGrid
* @param {!Object<string,*>} mediaQueryData
* @param {!SDK.CSSModel} cssModel
* @param {!Components.Linkifier} linkifier
*/
constructor(dataGrid, mediaQueryData, cssModel, linkifier) {
super(dataGrid, mediaQueryData.hasChildren);
this.data = mediaQueryData;
this._cssModel = cssModel;
this._linkifier = linkifier;
}
/**
* @override
* @param {string} columnId
* @return {!Element}
*/
createCell(columnId) {
if (this.data.range && columnId === 'sourceURL') {
const cell = this.createTD(columnId);
const link = this._linkifyRuleLocation(
this._cssModel, this._linkifier, this.data.styleSheetId, TextUtils.TextRange.fromObject(this.data.range));
if (link.textContent !== '') {
cell.appendChild(link);
} else {
cell.textContent = `${this.data.sourceURL} (not available)`;
}
return cell;
}
return super.createCell(columnId);
}
_linkifyRuleLocation(cssModel, linkifier, styleSheetId, ruleLocation) {
const styleSheetHeader = cssModel.styleSheetHeaderForId(styleSheetId);
const lineNumber = styleSheetHeader.lineNumberInSource(ruleLocation.startLine);
const columnNumber = styleSheetHeader.columnNumberInSource(ruleLocation.startLine, ruleLocation.startColumn);
const matchingSelectorLocation = new SDK.CSSLocation(styleSheetHeader, lineNumber, columnNumber);
return linkifier.linkifyCSSLocation(matchingSelectorLocation);
}
};
......@@ -25,12 +25,17 @@ CssOverview.CSSOverviewModel = class extends SDK.SDKModel {
return this._cssAgent.getComputedStyleForNode(nodeId);
}
async getMediaQueries() {
// Ignore media queries applied to stylesheets; instead only use declared media rules.
const queries = await this._cssAgent.getMediaQueries();
return queries.filter(query => query.source !== 'linkedSheet');
}
async getGlobalStylesheetStats() {
// There are no ways to pull CSSOM values directly today, due to its unserializable format,
// so instead we execute some JS within the page that extracts the relevant data and send that instead.
const expression = `(function() {
let styleRules = 0;
let mediaRules = 0;
let inlineStyles = 0;
let externalSheets = 0;
for (const { rules, href } of document.styleSheets) {
......@@ -43,15 +48,12 @@ CssOverview.CSSOverviewModel = class extends SDK.SDKModel {
for (const rule of rules) {
if ('selectorText' in rule) {
styleRules++;
} else if ('conditionText' in rule) {
mediaRules++;
}
}
}
return {
styleRules,
mediaRules,
inlineStyles,
externalSheets
}
......
......@@ -11,13 +11,14 @@ CssOverview.CSSOverviewPanel = class extends UI.Panel {
this.registerRequiredCSS('css_overview/cssOverview.css');
this.element.classList.add('css-overview-panel');
const [model] = SDK.targetManager.models(CssOverview.CSSOverviewModel);
this._model = model;
this._controller = new CssOverview.OverviewController();
this._startView = new CssOverview.CSSOverviewStartView(this._controller);
this._processingView = new CssOverview.CSSOverviewProcessingView(this._controller);
this._completedView = new CssOverview.CSSOverviewCompletedView(this._controller);
this._completedView = new CssOverview.CSSOverviewCompletedView(this._controller, model.target());
const [model] = SDK.targetManager.models(CssOverview.CSSOverviewModel);
this._model = model;
this._controller.addEventListener(CssOverview.Events.RequestOverviewStart, this._startOverview, this);
this._controller.addEventListener(CssOverview.Events.RequestOverviewCancel, this._cancelOverview, this);
this._controller.addEventListener(CssOverview.Events.OverviewCompleted, this._overviewCompleted, this);
......@@ -30,6 +31,7 @@ CssOverview.CSSOverviewPanel = class extends UI.Panel {
this._backgroundColors = new Set();
this._textColors = new Set();
this._fontSizes = new Map();
this._mediaQueries = [];
this._elementCount = 0;
this._elementStyleStats = {
// Simple.
......@@ -43,7 +45,7 @@ CssOverview.CSSOverviewPanel = class extends UI.Panel {
nonSimple: new Set()
};
this._cancelled = false;
this._globalStyleStats = {styleRules: 0, mediaRules: 0, inlineStyles: 0, externalSheets: 0};
this._globalStyleStats = {styleRules: 0, inlineStyles: 0, externalSheets: 0};
this._renderInitialView();
}
......@@ -73,7 +75,8 @@ CssOverview.CSSOverviewPanel = class extends UI.Panel {
globalStyleStats: this._globalStyleStats,
elementStyleStats: this._elementStyleStats,
fontSizes: this._fontSizes,
elementCount: this._elementCount
elementCount: this._elementCount,
mediaQueries: this._mediaQueries
});
}
......@@ -92,6 +95,11 @@ CssOverview.CSSOverviewPanel = class extends UI.Panel {
this._globalStyleStats = globalStyleStats;
}
const mediaQueries = await this._model.getMediaQueries();
if (mediaQueries) {
this._mediaQueries = mediaQueries;
}
// 2. Get the total element count.
this._elementCount = document.length;
......
......@@ -46,6 +46,17 @@
font-weight: bold;
}
.media-query-grid .header-container,
.media-query-grid .data-container,
.media-query-grid table.data {
position: relative;
}
.media-query-grid .data-container {
top: 0;
max-height: 400px;
}
.block {
width: 65px;
height: 25px;
......
......@@ -27,9 +27,6 @@
<message name="IDS_DEVTOOLS_5d50889672f6f860d14f502de3de1957" desc="Title of colors subsection in the CSS Overview Panel">
Colors
</message>
<message name="IDS_DEVTOOLS_62d79b9db9edfb64bd8c538cb9ed0190" desc="Label for the number of media rules in the CSS Overview report">
Media rules
</message>
<message name="IDS_DEVTOOLS_6ad170a0581c9c116ca254758bd0c5b9" desc="Label for the number of ID selectors in the CSS Overview report">
ID selectors
</message>
......@@ -57,6 +54,9 @@
<message name="IDS_DEVTOOLS_d4a993a4b0d13c2cc4ce9387af1604ce" desc="Label for the 'Clear overview' button in the CSS Overview report">
Clear overview
</message>
<message name="IDS_DEVTOOLS_daee0f0fc555c02342c4e00a1dbf642a" desc="Label for the number of media rules in the CSS Overview report">
Media queries
</message>
<message name="IDS_DEVTOOLS_e9c6934e961dad71d311f68c679dfd3b" desc="Label for the capture button in the CSS Overview Panel">
Capture overview
</message>
......
......@@ -13,7 +13,8 @@
"dependencies": [
"elements",
"ui",
"sdk"
"sdk",
"data_grid"
],
"scripts": [
"CSSOverviewController.js",
......
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