| OLD | NEW |
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 /** | 5 /** |
| 6 * @unrestricted | 6 * @unrestricted |
| 7 */ | 7 */ |
| 8 Audits2.Audits2Panel = class extends UI.PanelWithSidebar { | 8 Audits2.Audits2Panel = class extends UI.PanelWithSidebar { |
| 9 constructor() { | 9 constructor() { |
| 10 super('audits2'); | 10 super('audits2'); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 | 38 |
| 39 this._dropTarget = new UI.DropTarget( | 39 this._dropTarget = new UI.DropTarget( |
| 40 this.contentElement, [UI.DropTarget.Types.Files], Common.UIString('Drop
audit file here'), | 40 this.contentElement, [UI.DropTarget.Types.Files], Common.UIString('Drop
audit file here'), |
| 41 this._handleDrop.bind(this)); | 41 this._handleDrop.bind(this)); |
| 42 | 42 |
| 43 this._showLandingPage(); | 43 this._showLandingPage(); |
| 44 } | 44 } |
| 45 | 45 |
| 46 _clearAll() { | 46 _clearAll() { |
| 47 this._treeOutline.removeChildren(); | 47 this._treeOutline.removeChildren(); |
| 48 if (!this._treeOutline.rootElement().childCount()) | 48 this._showLandingPage(); |
| 49 this._showLandingPage(); | |
| 50 } | 49 } |
| 51 | 50 |
| 52 _deleteSelected() { | 51 _deleteSelected() { |
| 53 var selection = this._treeOutline.selectedTreeElement; | 52 var selection = this._treeOutline.selectedTreeElement; |
| 54 if (selection) | 53 if (selection) |
| 55 this._treeOutline.removeChild(selection); | 54 selection._deleteItem(); |
| 56 if (!this._treeOutline.rootElement().childCount()) | |
| 57 this._showLandingPage(); | |
| 58 } | 55 } |
| 59 | 56 |
| 60 _showLandingPage() { | 57 _showLandingPage() { |
| 58 if (this._treeOutline.rootElement().childCount()) |
| 59 return; |
| 60 |
| 61 this.mainElement().removeChildren(); | 61 this.mainElement().removeChildren(); |
| 62 var landingPage = this.mainElement().createChild('div', 'vbox audits2-landin
g-page'); | 62 var landingPage = this.mainElement().createChild('div', 'vbox audits2-landin
g-page'); |
| 63 var landingCenter = landingPage.createChild('div', 'vbox audits2-landing-cen
ter'); | 63 var landingCenter = landingPage.createChild('div', 'vbox audits2-landing-cen
ter'); |
| 64 landingCenter.createChild('div', 'audits2-logo'); | 64 landingCenter.createChild('div', 'audits2-logo'); |
| 65 var text = landingCenter.createChild('div', 'audits2-landing-text'); | 65 var text = landingCenter.createChild('div', 'audits2-landing-text'); |
| 66 text.createChild('span', 'audits2-landing-bold-text').textContent = Common.U
IString('Audits'); | 66 text.createChild('span', 'audits2-landing-bold-text').textContent = Common.U
IString('Audits'); |
| 67 text.createChild('span').textContent = Common.UIString( | 67 text.createChild('span').textContent = Common.UIString( |
| 68 ' help you identify and fix common problems that affect' + | 68 ' help you identify and fix common problems that affect' + |
| 69 ' your site\'s performance, accessibility, and user experience. '); | 69 ' your site\'s performance, accessibility, and user experience. '); |
| 70 var link = text.createChild('span', 'link'); | 70 var link = text.createChild('span', 'link'); |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 197 if (!this._dialog) | 197 if (!this._dialog) |
| 198 return; | 198 return; |
| 199 this._statusElement.textContent = statusMessage; | 199 this._statusElement.textContent = statusMessage; |
| 200 } | 200 } |
| 201 | 201 |
| 202 /** | 202 /** |
| 203 * @return {!Promise<undefined>} | 203 * @return {!Promise<undefined>} |
| 204 */ | 204 */ |
| 205 _stop() { | 205 _stop() { |
| 206 return this._protocolService.detach().then(_ => { | 206 return this._protocolService.detach().then(_ => { |
| 207 Emulation.InspectedPagePlaceholder.instance().update(true); |
| 207 this._auditRunning = false; | 208 this._auditRunning = false; |
| 208 this._updateButton(); | 209 this._updateButton(); |
| 209 var resourceTreeModel = SDK.targetManager.mainTarget().model(SDK.ResourceT
reeModel); | 210 var resourceTreeModel = SDK.targetManager.mainTarget().model(SDK.ResourceT
reeModel); |
| 210 if (resourceTreeModel && this._inspectedURL !== SDK.targetManager.mainTarg
et().inspectedURL()) | 211 if (resourceTreeModel && this._inspectedURL !== SDK.targetManager.mainTarg
et().inspectedURL()) |
| 211 resourceTreeModel.navigate(this._inspectedURL).then(() => this._hideDial
og()); | 212 resourceTreeModel.navigate(this._inspectedURL).then(() => this._hideDial
og()); |
| 212 else | 213 else |
| 213 this._hideDialog(); | 214 this._hideDialog(); |
| 214 }); | 215 }); |
| 215 } | 216 } |
| 216 | 217 |
| 217 /** | 218 /** |
| 218 * @param {!ReportRenderer.ReportJSON} lighthouseResult | 219 * @param {!ReportRenderer.ReportJSON} lighthouseResult |
| 219 */ | 220 */ |
| 220 _finish(lighthouseResult) { | 221 _finish(lighthouseResult) { |
| 221 if (lighthouseResult === null) { | 222 if (lighthouseResult === null) { |
| 222 this._updateStatus(Common.UIString('Auditing failed.')); | 223 this._updateStatus(Common.UIString('Auditing failed.')); |
| 223 return; | 224 return; |
| 224 } | 225 } |
| 225 var treeElement = new Audits2.Audits2Panel.TreeElement(lighthouseResult, thi
s.mainElement()); | 226 var treeElement = |
| 227 new Audits2.Audits2Panel.TreeElement(lighthouseResult, this.mainElement(
), this._showLandingPage.bind(this)); |
| 226 this._treeOutline.appendChild(treeElement); | 228 this._treeOutline.appendChild(treeElement); |
| 227 treeElement._populate(); | 229 treeElement._populate(); |
| 228 treeElement.select(); | 230 treeElement.select(); |
| 229 this._hideDialog(); | 231 this._hideDialog(); |
| 230 } | 232 } |
| 231 | 233 |
| 232 /** | 234 /** |
| 233 * @param {!Error} err | 235 * @param {!Error} err |
| 234 */ | 236 */ |
| 235 _renderBugReport(err) { | 237 _renderBugReport(err) { |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 this._initWorker(); | 432 this._initWorker(); |
| 431 | 433 |
| 432 return this._backendPromise.then(_ => this._backend.send(method, params)); | 434 return this._backendPromise.then(_ => this._backend.send(method, params)); |
| 433 } | 435 } |
| 434 }; | 436 }; |
| 435 | 437 |
| 436 Audits2.Audits2Panel.TreeElement = class extends UI.TreeElement { | 438 Audits2.Audits2Panel.TreeElement = class extends UI.TreeElement { |
| 437 /** | 439 /** |
| 438 * @param {!ReportRenderer.ReportJSON} lighthouseResult | 440 * @param {!ReportRenderer.ReportJSON} lighthouseResult |
| 439 * @param {!Element} resultsView | 441 * @param {!Element} resultsView |
| 442 * @param {function()} showLandingCallback |
| 440 */ | 443 */ |
| 441 constructor(lighthouseResult, resultsView) { | 444 constructor(lighthouseResult, resultsView, showLandingCallback) { |
| 442 super('', false); | 445 super('', false); |
| 443 this._lighthouseResult = lighthouseResult; | 446 this._lighthouseResult = lighthouseResult; |
| 444 this._resultsView = resultsView; | 447 this._resultsView = resultsView; |
| 448 this._showLandingCallback = showLandingCallback; |
| 445 /** @type {?Element} */ | 449 /** @type {?Element} */ |
| 446 this._reportContainer = null; | 450 this._reportContainer = null; |
| 447 | 451 |
| 448 var url = new Common.ParsedURL(lighthouseResult.url); | 452 var url = new Common.ParsedURL(lighthouseResult.url); |
| 449 var timestamp = lighthouseResult.generatedTime; | 453 var timestamp = lighthouseResult.generatedTime; |
| 450 var titleElement = this.titleElement(); | 454 var titleElement = this.titleElement(); |
| 451 titleElement.classList.add('audits2-report-tree-item'); | 455 titleElement.classList.add('audits2-report-tree-item'); |
| 452 titleElement.createChild('div').textContent = url.domain(); | 456 titleElement.createChild('div').textContent = url.domain(); |
| 453 titleElement.createChild('span', 'dimmed').textContent = new Date(timestamp)
.toLocaleString(); | 457 titleElement.createChild('span', 'dimmed').textContent = new Date(timestamp)
.toLocaleString(); |
| 454 this.listItemElement.addEventListener('contextmenu', this._handleContextMenu
Event.bind(this), false); | 458 this.listItemElement.addEventListener('contextmenu', this._handleContextMenu
Event.bind(this), false); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 465 * @override | 469 * @override |
| 466 * @param {boolean=} selectedByUser | 470 * @param {boolean=} selectedByUser |
| 467 * @return {boolean} | 471 * @return {boolean} |
| 468 */ | 472 */ |
| 469 onselect(selectedByUser) { | 473 onselect(selectedByUser) { |
| 470 this._renderReport(); | 474 this._renderReport(); |
| 471 return true; | 475 return true; |
| 472 } | 476 } |
| 473 | 477 |
| 474 /** | 478 /** |
| 479 * @override |
| 480 */ |
| 481 ondelete() { |
| 482 this._deleteItem(); |
| 483 return true; |
| 484 } |
| 485 |
| 486 _deleteItem() { |
| 487 this.treeOutline.removeChild(this); |
| 488 this._showLandingCallback(); |
| 489 } |
| 490 |
| 491 /** |
| 475 * @param {!Event} event | 492 * @param {!Event} event |
| 476 */ | 493 */ |
| 477 _handleContextMenuEvent(event) { | 494 _handleContextMenuEvent(event) { |
| 478 var contextMenu = new UI.ContextMenu(event); | 495 var contextMenu = new UI.ContextMenu(event); |
| 479 contextMenu.appendItem(Common.UIString('Save as\u2026'), () => { | 496 contextMenu.appendItem(Common.UIString('Save as\u2026'), () => { |
| 480 var url = new Common.ParsedURL(this._lighthouseResult.url).domain(); | 497 var url = new Common.ParsedURL(this._lighthouseResult.url).domain(); |
| 481 var timestamp = this._lighthouseResult.generatedTime; | 498 var timestamp = this._lighthouseResult.generatedTime; |
| 482 var fileName = `${url}-${new Date(timestamp).toISO8601Compact()}.json`; | 499 var fileName = `${url}-${new Date(timestamp).toISO8601Compact()}.json`; |
| 483 Workspace.fileManager.save(fileName, JSON.stringify(this._lighthouseResult
), true); | 500 Workspace.fileManager.save(fileName, JSON.stringify(this._lighthouseResult
), true); |
| 484 }); | 501 }); |
| 502 contextMenu.appendItem(Common.UIString('Delete'), () => this._deleteItem()); |
| 485 contextMenu.show(); | 503 contextMenu.show(); |
| 486 } | 504 } |
| 487 | 505 |
| 488 /** | 506 /** |
| 489 * @override | 507 * @override |
| 490 */ | 508 */ |
| 491 onunbind() { | 509 onunbind() { |
| 492 if (this._reportContainer && this._reportContainer.parentElement) | 510 if (this._reportContainer && this._reportContainer.parentElement) |
| 493 this._reportContainer.remove(); | 511 this._reportContainer.remove(); |
| 494 } | 512 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 507 var categoryRenderer = new CategoryRenderer(dom, detailsRenderer); | 525 var categoryRenderer = new CategoryRenderer(dom, detailsRenderer); |
| 508 var renderer = new Audits2.Audits2Panel.ReportRenderer(dom, categoryRenderer
); | 526 var renderer = new Audits2.Audits2Panel.ReportRenderer(dom, categoryRenderer
); |
| 509 | 527 |
| 510 var templatesHTML = Runtime.cachedResources['audits2/lighthouse/templates.ht
ml']; | 528 var templatesHTML = Runtime.cachedResources['audits2/lighthouse/templates.ht
ml']; |
| 511 var templatesDOM = new DOMParser().parseFromString(templatesHTML, 'text/html
'); | 529 var templatesDOM = new DOMParser().parseFromString(templatesHTML, 'text/html
'); |
| 512 if (!templatesDOM) | 530 if (!templatesDOM) |
| 513 return; | 531 return; |
| 514 | 532 |
| 515 renderer.setTemplateContext(templatesDOM); | 533 renderer.setTemplateContext(templatesDOM); |
| 516 renderer.renderReport(this._lighthouseResult, this._reportContainer); | 534 renderer.renderReport(this._lighthouseResult, this._reportContainer); |
| 535 |
| 536 var performanceScoreElement = this._reportContainer.querySelector('.lh-categ
ory[id=performance] .lh-score'); |
| 537 var artifacts = this._lighthouseResult['artifacts']; |
| 538 if (!performanceScoreElement || !artifacts) |
| 539 return; |
| 540 var tracePass = artifacts['traces'] ? artifacts['traces']['defaultPass'] : n
ull; |
| 541 if (!tracePass) |
| 542 return; |
| 543 |
| 544 var fmp = this._lighthouseResult['audits']['first-meaningful-paint']; |
| 545 if (!fmp || !fmp['extendedInfo']) |
| 546 return; |
| 547 |
| 548 var tti = this._lighthouseResult['audits']['time-to-interactive']; |
| 549 if (!tti || !tti['extendedInfo']) |
| 550 return; |
| 551 |
| 552 var navStart = fmp['extendedInfo']['value']['timestamps']['navStart']; |
| 553 var markers = [ |
| 554 { |
| 555 title: Common.UIString('First contentful paint'), |
| 556 value: (fmp['extendedInfo']['value']['timestamps']['fCP'] - navStart) /
1000 |
| 557 }, |
| 558 { |
| 559 title: Common.UIString('First meaningful paint'), |
| 560 value: (fmp['extendedInfo']['value']['timestamps']['fMP'] - navStart) /
1000 |
| 561 }, |
| 562 { |
| 563 title: Common.UIString('Time to interactive'), |
| 564 value: (tti['extendedInfo']['value']['timestamps']['timeToInteractive']
- navStart) / 1000 |
| 565 }, |
| 566 { |
| 567 title: Common.UIString('Visually ready'), |
| 568 value: (tti['extendedInfo']['value']['timestamps']['visuallyReady'] - na
vStart) / 1000 |
| 569 } |
| 570 ]; |
| 571 |
| 572 var timeSpan = Math.max(...markers.map(marker => marker.value)); |
| 573 var screenshots = tracePass.traceEvents.filter(e => e.cat === 'disabled-by-d
efault-devtools.screenshot'); |
| 574 var timelineElement = createElementWithClass('div', 'audits2-timeline'); |
| 575 var filmStripElement = timelineElement.createChild('div', 'audits2-filmstrip
'); |
| 576 |
| 577 var numberOfFrames = 8; |
| 578 var roundToMs = 100; |
| 579 var timeStep = (Math.ceil(timeSpan / numberOfFrames / roundToMs)) * roundToM
s; |
| 580 |
| 581 for (var time = 0; time < timeSpan; time += timeStep) { |
| 582 var frameForTime = null; |
| 583 for (var e of screenshots) { |
| 584 if ((e.ts - navStart) / 1000 < time + timeStep) |
| 585 frameForTime = e.args.snapshot; |
| 586 } |
| 587 var frame = filmStripElement.createChild('div', 'frame'); |
| 588 frame.createChild('div', 'time').textContent = Number.millisToString(time
+ timeStep); |
| 589 |
| 590 var thumbnail = frame.createChild('div', 'thumbnail'); |
| 591 if (frameForTime) { |
| 592 var img = thumbnail.createChild('img'); |
| 593 img.src = 'data:image/jpg;base64,' + frameForTime; |
| 594 } |
| 595 } |
| 596 |
| 597 for (var marker of markers) { |
| 598 var markerElement = timelineElement.createChild('div', 'audits2-timeline-m
arker'); |
| 599 markerElement.createChild('div', 'audits2-timeline-bar').style.width = |
| 600 (100 * (marker.value / timeSpan) | 0) + '%'; |
| 601 markerElement.createChild('span').textContent = Common.UIString('%s: ', ma
rker.title); |
| 602 markerElement.createChild('span', 'audits2-timeline-subtitle').textContent
= Number.millisToString(marker.value); |
| 603 } |
| 604 |
| 605 performanceScoreElement.parentElement.insertBefore(timelineElement, performa
nceScoreElement.nextSibling); |
| 517 } | 606 } |
| 518 }; | 607 }; |
| 519 | 608 |
| 520 Audits2.Audits2Panel.TreeSubElement = class extends UI.TreeElement { | 609 Audits2.Audits2Panel.TreeSubElement = class extends UI.TreeElement { |
| 521 /** | 610 /** |
| 522 * @param {string} id | 611 * @param {string} id |
| 523 * @param {string} name | 612 * @param {string} name |
| 524 * @param {number} score | 613 * @param {number} score |
| 525 */ | 614 */ |
| 526 constructor(id, name, score) { | 615 constructor(id, name, score) { |
| (...skipping 12 matching lines...) Expand all Loading... |
| 539 onselect() { | 628 onselect() { |
| 540 this.parent._renderReport(); | 629 this.parent._renderReport(); |
| 541 var node = this.parent._resultsView.querySelector('.lh-category[id=' + this.
_id + ']'); | 630 var node = this.parent._resultsView.querySelector('.lh-category[id=' + this.
_id + ']'); |
| 542 if (node) { | 631 if (node) { |
| 543 node.scrollIntoView(true); | 632 node.scrollIntoView(true); |
| 544 return true; | 633 return true; |
| 545 } | 634 } |
| 546 return false; | 635 return false; |
| 547 } | 636 } |
| 548 }; | 637 }; |
| OLD | NEW |