blob: bde4e076a76459daa401e8a03644b811c6878ea5 [file] [log] [blame]
Patrick Hulcea087f622018-05-18 00:37:53 +00001// Copyright 2018 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/**
6 * @override
7 */
cjamcl@google.comaa1532c2019-05-31 03:01:24 +00008Audits.ReportRenderer = class extends ReportRenderer {
Patrick Hulcea087f622018-05-18 00:37:53 +00009 /**
Paul Irish8f1e33d2018-05-31 02:29:50 +000010 * @param {!Element} el Parent element to render the report into.
11 * @param {!ReportRenderer.RunnerResultArtifacts=} artifacts
Patrick Hulcea087f622018-05-18 00:37:53 +000012 */
Paul Irish8f1e33d2018-05-31 02:29:50 +000013 static addViewTraceButton(el, artifacts) {
14 if (!artifacts || !artifacts.traces || !artifacts.traces.defaultPass)
15 return;
Patrick Hulcea087f622018-05-18 00:37:53 +000016
Paul Irish8f1e33d2018-05-31 02:29:50 +000017 const defaultPassTrace = artifacts.traces.defaultPass;
18 const timelineButton = UI.createTextButton(Common.UIString('View Trace'), onViewTraceClick, 'view-trace');
John Emau8f7221e2019-07-18 19:40:34 +000019 const container = el.querySelector('.lh-audit-group');
20 container.insertBefore(timelineButton, container.querySelector('.lh-columns').nextSibling);
Paul Irish8f1e33d2018-05-31 02:29:50 +000021 return el;
22
23 async function onViewTraceClick() {
cjamcl@google.comaa1532c2019-05-31 03:01:24 +000024 Host.userMetrics.actionTaken(Host.UserMetrics.Action.AuditsViewTrace);
Paul Irish8f1e33d2018-05-31 02:29:50 +000025 await UI.inspectorView.showPanel('timeline');
26 Timeline.TimelinePanel.instance().loadFromEvents(defaultPassTrace.traceEvents);
27 }
Patrick Hulcea087f622018-05-18 00:37:53 +000028 }
cjamcl@google.comda0e4c62018-11-27 23:52:10 +000029
30 /**
31 * @param {!Element} el
32 */
33 static async linkifyNodeDetails(el) {
34 const mainTarget = SDK.targetManager.mainTarget();
cjamcl@google.comda0e4c62018-11-27 23:52:10 +000035 const domModel = mainTarget.model(SDK.DOMModel);
36
37 for (const origElement of el.getElementsByClassName('lh-node')) {
38 /** @type {!DetailsRenderer.NodeDetailsJSON} */
39 const detailsItem = origElement.dataset;
40 if (!detailsItem.path)
cjamcl@google.com5c46b7e2018-12-04 14:44:47 +000041 continue;
cjamcl@google.comda0e4c62018-11-27 23:52:10 +000042
43 const nodeId = await domModel.pushNodeByPathToFrontend(detailsItem.path);
44
45 if (!nodeId)
cjamcl@google.com5c46b7e2018-12-04 14:44:47 +000046 continue;
cjamcl@google.comda0e4c62018-11-27 23:52:10 +000047 const node = domModel.nodeForId(nodeId);
48 if (!node)
cjamcl@google.com5c46b7e2018-12-04 14:44:47 +000049 continue;
cjamcl@google.comda0e4c62018-11-27 23:52:10 +000050
51 const element =
52 await Common.Linkifier.linkify(node, /** @type {!Common.Linkifier.Options} */ ({title: detailsItem.snippet}));
53 origElement.title = '';
54 origElement.textContent = '';
55 origElement.appendChild(element);
56 }
57 }
cjamcl@google.comf2f8c092019-05-30 22:01:56 +000058
59 /**
60 * @param {!Element} el
61 */
62 static handleDarkMode(el) {
63 if (UI.themeSupport.themeName() === 'dark')
64 el.classList.add('dark');
65 }
Patrick Hulcea087f622018-05-18 00:37:53 +000066};
cjamcl@google.comc5214af2019-06-25 20:31:21 +000067
68/**
69 * @override
70 */
71Audits.ReportUIFeatures = class extends ReportUIFeatures {
72 /**
73 * Returns the html that recreates this report.
74 * @return {string}
75 * @protected
76 */
77 getReportHtml() {
78 this.resetUIState();
79 return Lighthouse.ReportGenerator.generateReportHtml(this.json);
80 }
81
82 /**
83 * Downloads a file (blob) using the system dialog prompt.
84 * @param {!Blob|!File} blob The file to save.
85 */
86 async _saveFile(blob) {
87 const domain = new Common.ParsedURL(this.json.finalUrl).domain();
88 const sanitizedDomain = domain.replace(/[^a-z0-9.-]+/gi, '_');
89 const timestamp = new Date(this.json.fetchTime).toISO8601Compact();
90 const ext = blob.type.match('json') ? '.json' : '.html';
91 const basename = `${sanitizedDomain}-${timestamp}${ext}`;
92 const text = await blob.text();
93 Workspace.fileManager.save(basename, text, true /* forceSaveAs */);
94 }
95
96 async _print() {
97 const document = this.getDocument();
98 const clonedReport = document.querySelector('.lh-root').cloneNode(true /* deep */);
99 const printWindow = window.open('', '_blank', 'channelmode=1,status=1,resizable=1');
100 const style = printWindow.document.createElement('style');
101 style.textContent = Runtime.cachedResources['audits/lighthouse/report.css'];
102 printWindow.document.head.appendChild(style);
103 printWindow.document.body.replaceWith(clonedReport);
104 // Linkified nodes are shadow elements, which aren't exposed via `cloneNode`.
105 await Audits.ReportRenderer.linkifyNodeDetails(clonedReport);
106 printWindow.focus();
107 printWindow.print();
108 printWindow.close();
109 }
110
111 /**
112 * @suppress {visibility}
113 * @return {!Document}
114 */
115 getDocument() {
116 return this._document;
117 }
118
119 /**
120 * @suppress {visibility}
121 */
122 resetUIState() {
123 this._resetUIState();
124 }
125};