Chromium Code Reviews| Index: third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js |
| diff --git a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js |
| index 603a5c5b2751378bf71057eaf1d8d22b234553e3..60dc2109982986acbf9af9bf25aacc7c8c934c90 100644 |
| --- a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js |
| +++ b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js |
| @@ -5,7 +5,7 @@ |
| /** |
| * @unrestricted |
| */ |
| -Audits2.Audits2Panel = class extends UI.Panel { |
| +Audits2.Audits2Panel = class extends UI.PanelWithSidebar { |
| constructor() { |
| super('audits2'); |
| this.setHideOnDetach(); |
| @@ -15,44 +15,96 @@ Audits2.Audits2Panel = class extends UI.Panel { |
| this._protocolService = new Audits2.ProtocolService(); |
| this._protocolService.registerStatusCallback(msg => this._updateStatus(Common.UIString(msg))); |
| - this._settings = Audits2.Audits2Panel.Presets.map(preset => { |
| - const setting = Common.settings.createSetting(preset.id, true); |
| - setting.setTitle(Common.UIString(preset.description)); |
| - return setting; |
| - }); |
| + var toolbar = new UI.Toolbar('', this.panelSidebarElement()); |
| + |
| + var newButton = new UI.ToolbarButton(Common.UIString('New audit\u2026'), 'largeicon-add'); |
| + toolbar.appendToolbarItem(newButton); |
| + newButton.addEventListener(UI.ToolbarButton.Events.Click, this._showLauncherUI.bind(this)); |
| + |
| + var deleteButton = new UI.ToolbarButton(Common.UIString('Delete audit'), 'largeicon-delete'); |
| + toolbar.appendToolbarItem(deleteButton); |
| + deleteButton.addEventListener(UI.ToolbarButton.Events.Click, this._deleteSelected.bind(this)); |
| + |
| + toolbar.appendSeparator(); |
| - var auditsViewElement = this.contentElement.createChild('div', 'hbox audits2-view'); |
| - this._resultsView = this.contentElement.createChild('div', 'vbox results-view'); |
| - this._createLauncherUI(auditsViewElement); |
| + var clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'largeicon-clear'); |
| + toolbar.appendToolbarItem(clearButton); |
| + clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._clearAll.bind(this)); |
| + |
| + this._treeOutline = new UI.TreeOutlineInShadow(); |
| + this._treeOutline.registerRequiredCSS('audits2/lighthouse/report-styles.css'); |
| + this._treeOutline.registerRequiredCSS('audits2/audits2Tree.css'); |
| + this.panelSidebarElement().appendChild(this._treeOutline.element); |
| + |
| + this._showLandingPage(); |
| } |
| - _reset() { |
| - this.contentElement.classList.remove('show-results'); |
| - this._resultsView.removeChildren(); |
| + _clearAll() { |
| + this._treeOutline.removeChildren(); |
| + if (!this._treeOutline.rootElement().childCount()) |
| + this._showLandingPage(); |
| } |
| - /** |
| - * @param {!Element} auditsViewElement |
| - */ |
| - _createLauncherUI(auditsViewElement) { |
| - auditsViewElement.createChild('div', 'audits2-logo'); |
| + _deleteSelected() { |
| + var selection = this._treeOutline.selectedTreeElement; |
| + if (selection) |
| + this._treeOutline.removeChild(selection); |
| + if (!this._treeOutline.rootElement().childCount()) |
| + this._showLandingPage(); |
| + } |
| + |
| + _showLandingPage() { |
| + this.mainElement().removeChildren(); |
| + var landingPage = this.mainElement().createChild('div', 'vbox audits2-landing-page'); |
| + var landingCenter = landingPage.createChild('div', 'vbox audits2-landing-center'); |
| + landingCenter.createChild('div', 'audits2-logo'); |
| + var text = landingCenter.createChild('div', 'audits2-landing-text'); |
| + text.createChild('span', 'audits2-landing-bold-text').textContent = Common.UIString('Audits'); |
| + text.createChild('span').textContent = Common.UIString(' help you identify and fix common problems that affect' + |
| + + 'your site\'s performance, accessibility, and user experience. '); |
| + var link = text.createChild('span', 'link'); |
| + link.textContent = Common.UIString('Learn more'); |
| + link.addEventListener( |
| + 'click', () => InspectorFrontendHost.openInNewTab('https://developers.google.com/web/tools/lighthouse/')); |
|
dgozman
2017/05/02 01:27:56
UI.createDocumentationLink('../lighthouse')
pfeldman
2017/05/02 17:54:46
What happens when our documentation moves?
|
| + |
| + var newButton = UI.createTextButton( |
| + Common.UIString('Perform an audit\u2026'), this._showLauncherUI.bind(this), 'material-button default'); |
| + landingCenter.appendChild(newButton); |
| + } |
| + |
| + _showLauncherUI() { |
| + this._dialog = new UI.Dialog(); |
|
dgozman
2017/05/02 01:27:56
Let's not recreate dialog (and settings) if there
pfeldman
2017/05/02 17:54:46
I actually think this is a good one. Let me brush
|
| + var root = UI.createShadowRootWithCoreStyles(this._dialog.contentElement, 'audits2/audits2Dialog.css'); |
| + var auditsViewElement = root.createChild('div', 'audits2-view'); |
| var uiElement = auditsViewElement.createChild('div'); |
| var headerElement = uiElement.createChild('header'); |
| - headerElement.createChild('p').textContent = Common.UIString( |
| - 'Audits will analyze the page against modern development best practices and collect useful performance metrics and diagnostics. Select audits to collect:'); |
| + headerElement.createChild('p').textContent = Common.UIString('Audits to perform'); |
| uiElement.appendChild(headerElement); |
| var auditSelectorForm = uiElement.createChild('form', 'audits2-form'); |
| - this._settings |
| - .map(setting => new UI.ToolbarSettingCheckbox(setting)) |
| - .forEach(checkbox => auditSelectorForm.appendChild(checkbox.element)); |
| + for (var preset of Audits2.Audits2Panel.Presets) { |
| + var setting = Common.settings.createSetting(preset.id, true); |
| + setting.setTitle(preset.title); |
| + var checkbox = new UI.ToolbarSettingCheckbox(setting); |
| + var row = auditSelectorForm.createChild('div', 'vbox audits2-launcher-row'); |
| + row.appendChild(checkbox.element); |
| + row.createChild('span', 'audits2-launcher-description dimmed').textContent = preset.description; |
| + } |
| - this._startButton = UI.createTextButton( |
| - Common.UIString('Audit this page'), this._startButtonClicked.bind(this), 'run-audit audit-btn'); |
| + this._startButton = |
| + UI.createTextButton(Common.UIString('Run audit'), this._start.bind(this), 'material-button default'); |
| auditSelectorForm.appendChild(this._startButton); |
| + this._cancelButton = UI.createTextButton(Common.UIString('Cancel'), this._cancel.bind(this), 'material-button'); |
| + auditSelectorForm.appendChild(this._cancelButton); |
| this._statusView = this._createStatusView(uiElement); |
| + |
| + this._dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHeight); |
| + this._dialog.setMaxContentSize(new UI.Size(600, 400)); |
| + this._dialog.show(this.mainElement()); |
| + auditsViewElement.tabIndex = 0; |
| + auditsViewElement.focus(); |
| } |
| /** |
| @@ -70,43 +122,39 @@ Audits2.Audits2Panel = class extends UI.Panel { |
| _start() { |
| this._inspectedURL = SDK.targetManager.mainTarget().inspectedURL(); |
| - const categoryIDs = this._settings.map(setting => { |
| - const preset = Audits2.Audits2Panel.Presets.find(preset => preset.id === setting.name); |
| - return {configID: preset.configID, value: setting.get()}; |
| - }).filter(agg => !!agg.value).map(agg => agg.configID); |
| + var categoryIDs = []; |
| + for (var preset of Audits2.Audits2Panel.Presets) { |
| + if (Common.settings.createSetting(preset.id, true).get()) |
| + categoryIDs.push(preset.configID); |
| + } |
| return Promise.resolve() |
| .then(_ => this._protocolService.attach()) |
| .then(_ => { |
| this._auditRunning = true; |
| this._updateButton(); |
| - this._updateStatus(Common.UIString('Loading...')); |
| + this._updateStatus(Common.UIString('Loading\u2026')); |
| }) |
| .then(_ => this._protocolService.startLighthouse(this._inspectedURL, categoryIDs)) |
| .then(lighthouseResult => { |
| this._finish(lighthouseResult); |
| return this._stop(); |
| - }).catch(err => { |
| - if (err instanceof Error) this._renderBugReport(err); |
| + }) |
| + .catch(err => { |
| + if (err instanceof Error) |
| + this._renderBugReport(err); |
| }); |
| } |
| - /** |
| - * @param {!Event} event |
| - */ |
| - _startButtonClicked(event) { |
| - if (this._auditRunning) { |
| - this._updateStatus(Common.UIString('Cancelling...')); |
| - this._stop(); |
| - return; |
| - } |
| - this._start(); |
| + _cancel() { |
| + this._updateStatus(Common.UIString('Cancelling\u2026')); |
| + this._stop(); |
| + this._dialog.hide(); |
| } |
| _updateButton() { |
| - this._startButton.textContent = |
| - this._auditRunning ? Common.UIString('Cancel audit') : Common.UIString('Audit this page'); |
| - this._startButton.classList.toggle('started', this._auditRunning); |
| + this._startButton.classList.toggle('default', !this._auditRunning); |
| + this._startButton.disabled = this._auditRunning; |
| this._statusView.classList.toggle('hidden', !this._auditRunning); |
| } |
| @@ -139,13 +187,11 @@ Audits2.Audits2Panel = class extends UI.Panel { |
| this._updateStatus(Common.UIString('Auditing failed.')); |
| return; |
| } |
| - this._resultsView.removeChildren(); |
| - |
| - var url = lighthouseResult.url; |
| - var timestamp = lighthouseResult.generatedTime; |
| - this._createResultsBar(this._resultsView, url, timestamp); |
| - this._renderReport(this._resultsView, lighthouseResult); |
| - this.contentElement.classList.add('show-results'); |
| + var treeElement = new Audits2.Audits2Panel.TreeElement(lighthouseResult, this.mainElement()); |
| + this._treeOutline.appendChild(treeElement); |
| + treeElement._populate(); |
| + treeElement.select(); |
| + this._dialog.hide(); |
| } |
| /** |
| @@ -177,57 +223,12 @@ Audits2.Audits2Panel = class extends UI.Panel { |
| reportErrorEl.textContent = Common.UIString('Report this bug'); |
| reportErrorEl.target = '_blank'; |
| } |
| - |
| - /** |
| - * @param {!Element} resultsView |
| - * @param {!ReportRenderer.ReportJSON} lighthouseResult |
| - * @suppressGlobalPropertiesCheck |
| - */ |
| - _renderReport(resultsView, lighthouseResult) { |
| - var reportContainer = resultsView.createChild('div', 'report-container lh-root'); |
| - |
| - var dom = new DOM(document); |
| - var detailsRenderer = new DetailsRenderer(dom); |
| - var categoryRenderer = new CategoryRenderer(dom, detailsRenderer); |
| - var renderer = new Audits2.ReportRenderer(dom, categoryRenderer); |
| - |
| - var templatesHTML = Runtime.cachedResources['audits2/lighthouse/templates.html']; |
| - var templatesDOM = new DOMParser().parseFromString(templatesHTML, 'text/html'); |
| - if (!templatesDOM) |
| - return; |
| - |
| - renderer.setTemplateContext(templatesDOM); |
| - renderer.renderReport(lighthouseResult, reportContainer); |
| - } |
| - |
| - /** |
| - * @param {!Element} resultsView |
| - * @param {string} url |
| - * @param {string} timestamp |
| - */ |
| - _createResultsBar(resultsView, url, timestamp) { |
| - var elem = resultsView.createChild('div', 'results-bar hbox'); |
| - elem.createChild('div', 'audits2-logo audits2-logo-small'); |
| - |
| - var summaryElem = elem.createChild('div', 'audits2-summary'); |
| - var reportFor = summaryElem.createChild('span'); |
| - reportFor.createTextChild('Report for '); |
| - var urlElem = reportFor.createChild('b'); |
| - urlElem.textContent = url; |
| - var timeElem = summaryElem.createChild('span'); |
| - timeElem.textContent = |
| - `Generated at ${new Date(timestamp).toLocaleDateString()} ${new Date(timestamp).toLocaleTimeString()}`; |
| - |
| - var newAuditButton = |
| - UI.createTextButton(Common.UIString('New Audit'), this._reset.bind(this), 'new-audit audit-btn'); |
| - elem.appendChild(newAuditButton); |
| - } |
| }; |
| /** |
| * @override |
| */ |
| -Audits2.ReportRenderer = class extends ReportRenderer { |
| +Audits2.Audits2Panel.ReportRenderer = class extends ReportRenderer { |
| /** |
| * Provides empty element for left nav |
| * @override |
| @@ -236,14 +237,23 @@ Audits2.ReportRenderer = class extends ReportRenderer { |
| _renderReportNav() { |
| return createDocumentFragment(); |
| } |
| -}; |
| + /** |
| + * @param {!ReportRenderer.ReportJSON} report |
| + * @override |
| + * @return {!DocumentFragment} |
| + */ |
| + _renderReportHeader(report) { |
| + return createDocumentFragment(); |
| + } |
| +}; |
| class ReportUIFeatures { |
| /** |
| * @param {!ReportRenderer.ReportJSON} report |
| */ |
| - initFeatures(report) {} |
| + initFeatures(report) { |
| + } |
| } |
| /** @typedef {{id: string, configID: string, description: string}} */ |
| @@ -252,10 +262,30 @@ Audits2.Audits2Panel.Preset; |
| /** @type {!Array.<!Audits2.Audits2Panel.Preset>} */ |
| Audits2.Audits2Panel.Presets = [ |
| // configID maps to Lighthouse's Object.keys(config.categories)[0] value |
| - {id: 'audits2_cat_pwa', configID: 'pwa', description: 'Progressive Web App'}, |
| - {id: 'audits2_cat_perf', configID: 'performance', description: 'Performance metrics and diagnostics'}, |
| - {id: 'audits2_cat_a11y', configID: 'accessibility', description: 'Accessibility'}, |
| - {id: 'audits2_cat_best_practices', configID: 'best-practices', description: 'Modern best practices'}, |
| + { |
| + id: 'audits2_cat_pwa', |
| + configID: 'pwa', |
| + title: 'Progressive Web App', |
| + description: 'Does this page meet the standard of a Progressive Web App' |
|
dgozman
2017/05/02 01:27:56
can just inline setting here:
setting: Common.set
pfeldman
2017/05/02 17:54:46
Done.
|
| + }, |
| + { |
| + id: 'audits2_cat_perf', |
| + configID: 'performance', |
| + title: 'Performance', |
| + description: 'How long does this app take to show content and become usable' |
| + }, |
| + { |
| + id: 'audits2_cat_best_practices', |
| + configID: 'best-practices', |
| + title: 'Best practices', |
| + description: 'Does this page follow best practices for modern web development' |
| + }, |
| + { |
| + id: 'audits2_cat_a11y', |
| + configID: 'accessibility', |
| + title: 'Accessibility', |
| + description: 'Is this page usable by people with disabilities or impairments' |
| + }, |
| ]; |
| Audits2.ProtocolService = class extends Common.Object { |
| @@ -337,3 +367,102 @@ Audits2.ProtocolService = class extends Common.Object { |
| return this._backendPromise.then(_ => this._backend.send(method, params)); |
| } |
| }; |
| + |
| +Audits2.Audits2Panel.TreeElement = class extends UI.TreeElement { |
| + /** |
| + * @param {!ReportRenderer.ReportJSON} lighthouseResult |
| + * @param {!Element} resultsView |
| + */ |
| + constructor(lighthouseResult, resultsView) { |
| + super('', false); |
| + this._lighthouseResult = lighthouseResult; |
| + this._resultsView = resultsView; |
| + /** @type {?Element} */ |
| + this._reportContainer = null; |
| + |
| + var url = new Common.ParsedURL(lighthouseResult.url); |
| + var timestamp = lighthouseResult.generatedTime; |
| + var titleElement = this.titleElement(); |
| + titleElement.classList.add('audits2-report-tree-item'); |
| + titleElement.createChild('div').textContent = url.domain(); |
| + titleElement.createChild('span', 'dimmed').textContent = new Date(timestamp).toLocaleString(); |
| + } |
| + |
| + _populate() { |
| + for (var category of this._lighthouseResult.reportCategories) { |
| + var treeElement = new Audits2.Audits2Panel.TreeSubElement(category.id, category.name, category.score); |
| + this.appendChild(treeElement); |
| + } |
| + } |
| + |
| + /** |
| + * @override |
| + * @param {boolean=} selectedByUser |
| + * @return {boolean} |
| + */ |
| + onselect(selectedByUser) { |
| + this._renderReport(); |
| + return true; |
| + } |
| + |
| + /** |
| + * @override |
| + */ |
| + onunbind() { |
| + if (this._reportContainer && this._reportContainer.parentElement) |
| + this._reportContainer.remove(); |
| + } |
| + |
| + _renderReport() { |
| + this._resultsView.removeChildren(); |
| + if (this._reportContainer) { |
| + this._resultsView.appendChild(this._reportContainer); |
| + return; |
| + } |
| + |
| + this._reportContainer = this._resultsView.createChild('div', 'report-container lh-root'); |
| + |
| + var dom = new DOM(/** @type {!Document} */(this._resultsView.ownerDocument)); |
| + var detailsRenderer = new DetailsRenderer(dom); |
| + var categoryRenderer = new CategoryRenderer(dom, detailsRenderer); |
| + var renderer = new Audits2.Audits2Panel.ReportRenderer(dom, categoryRenderer); |
| + |
| + var templatesHTML = Runtime.cachedResources['audits2/lighthouse/templates.html']; |
| + var templatesDOM = new DOMParser().parseFromString(templatesHTML, 'text/html'); |
| + if (!templatesDOM) |
| + return; |
| + |
| + renderer.setTemplateContext(templatesDOM); |
| + renderer.renderReport(this._lighthouseResult, this._reportContainer); |
| + } |
| +}; |
| + |
| +Audits2.Audits2Panel.TreeSubElement = class extends UI.TreeElement { |
| + /** |
| + * @param {string} id |
| + * @param {string} name |
| + * @param {number} score |
| + */ |
| + constructor(id, name, score) { |
| + super(''); |
| + this._id = id; |
| + this.listItemElement.textContent = name; |
| + var label = Util.calculateRating(score); |
| + var subtitleElement = this.listItemElement.createChild('span', 'lh-root audits2-tree-subtitle-' + label); |
| + subtitleElement.textContent = String(Math.round(score)); |
| + } |
| + |
| + /** |
| + * @override |
| + * @return {boolean} |
| + */ |
| + onselect() { |
| + this.parent._renderReport(); |
| + var node = this.parent._resultsView.querySelector('.lh-category[id=' + this._id + ']'); |
| + if (node) { |
| + node.scrollIntoView(true); |
| + return true; |
| + } |
| + return false; |
| + } |
| +}; |