AuditsPanel.js 9.9 KB

1234567891011121314151617181920212223242526272829303132333435
  1. export default class AuditsPanel extends UI.Panel{constructor(){super('audits');this.registerRequiredCSS('audits/lighthouse/report.css');this.registerRequiredCSS('audits/auditsPanel.css');this._protocolService=new Audits.ProtocolService();this._controller=new Audits.AuditController(this._protocolService);this._startView=new Audits.StartView(this._controller);this._statusView=new Audits.StatusView(this._controller);this._unauditableExplanation=null;this._cachedRenderedReports=new Map();this._dropTarget=new UI.DropTarget(this.contentElement,[UI.DropTarget.Type.File],Common.UIString('Drop audit file here'),this._handleDrop.bind(this));this._controller.addEventListener(Audits.Events.PageAuditabilityChanged,this._refreshStartAuditUI.bind(this));this._controller.addEventListener(Audits.Events.AuditProgressChanged,this._refreshStatusUI.bind(this));this._controller.addEventListener(Audits.Events.RequestAuditStart,this._startAudit.bind(this));this._controller.addEventListener(Audits.Events.RequestAuditCancel,this._cancelAudit.bind(this));this._renderToolbar();this._auditResultsElement=this.contentElement.createChild('div','audits-results-container');this._renderStartView();this._controller.recomputePageAuditability();}
  2. _refreshStartAuditUI(evt){if(this._isLHAttached){return;}
  3. this._unauditableExplanation=evt.data.helpText;this._startView.setUnauditableExplanation(evt.data.helpText);this._startView.setStartButtonEnabled(!evt.data.helpText);}
  4. _refreshStatusUI(evt){this._statusView.updateStatus(evt.data.message);}
  5. _refreshToolbarUI(){this._clearButton.setEnabled(this._reportSelector.hasItems());}
  6. _clearAll(){this._reportSelector.clearAll();this._renderStartView();this._refreshToolbarUI();}
  7. _renderToolbar(){const auditsToolbarContainer=this.element.createChild('div','audits-toolbar-container');const toolbar=new UI.Toolbar('',auditsToolbarContainer);this._newButton=new UI.ToolbarButton(Common.UIString('Perform an audit\u2026'),'largeicon-add');toolbar.appendToolbarItem(this._newButton);this._newButton.addEventListener(UI.ToolbarButton.Events.Click,this._renderStartView.bind(this));toolbar.appendSeparator();this._reportSelector=new Audits.ReportSelector(()=>this._renderStartView());toolbar.appendToolbarItem(this._reportSelector.comboBox());this._clearButton=new UI.ToolbarButton(Common.UIString('Clear all'),'largeicon-clear');toolbar.appendToolbarItem(this._clearButton);this._clearButton.addEventListener(UI.ToolbarButton.Events.Click,this._clearAll.bind(this));this._settingsPane=new UI.HBox();this._settingsPane.show(this.contentElement);this._settingsPane.element.classList.add('audits-settings-pane');this._settingsPane.element.appendChild(this._startView.settingsToolbar().element);this._showSettingsPaneSetting=Common.settings.createSetting('auditsShowSettingsToolbar',false);this._rightToolbar=new UI.Toolbar('',auditsToolbarContainer);this._rightToolbar.appendSeparator();this._rightToolbar.appendToolbarItem(new UI.ToolbarSettingToggle(this._showSettingsPaneSetting,'largeicon-settings-gear',ls`Audits settings`));this._showSettingsPaneSetting.addChangeListener(this._updateSettingsPaneVisibility.bind(this));this._updateSettingsPaneVisibility();this._refreshToolbarUI();}
  8. _updateSettingsPaneVisibility(){this._settingsPane.element.classList.toggle('hidden',!this._showSettingsPaneSetting.get());}
  9. _toggleSettingsDisplay(show){this._rightToolbar.element.classList.toggle('hidden',!show);this._settingsPane.element.classList.toggle('hidden',!show);this._updateSettingsPaneVisibility();}
  10. _renderStartView(){this._auditResultsElement.removeChildren();this._statusView.hide();this._reportSelector.selectNewAudit();this.contentElement.classList.toggle('in-progress',false);this._startView.show(this.contentElement);this._toggleSettingsDisplay(true);this._startView.setUnauditableExplanation(this._unauditableExplanation);this._startView.setStartButtonEnabled(!this._unauditableExplanation);if(!this._unauditableExplanation){this._startView.focusStartButton();}
  11. this._newButton.setEnabled(false);this._refreshToolbarUI();this.setDefaultFocusedChild(this._startView);}
  12. _renderStatusView(inspectedURL){this.contentElement.classList.toggle('in-progress',true);this._statusView.setInspectedURL(inspectedURL);this._statusView.show(this.contentElement);}
  13. _beforePrint(){this._statusView.show(this.contentElement);this._statusView.toggleCancelButton(false);this._statusView.renderText(ls`Printing`,ls`The print popup window is open. Please close it to continue.`);}
  14. _afterPrint(){this._statusView.hide();this._statusView.toggleCancelButton(true);}
  15. _renderReport(lighthouseResult,artifacts){this._toggleSettingsDisplay(false);this.contentElement.classList.toggle('in-progress',false);this._startView.hideWidget();this._statusView.hide();this._auditResultsElement.removeChildren();this._newButton.setEnabled(true);this._refreshToolbarUI();const cachedRenderedReport=this._cachedRenderedReports.get(lighthouseResult);if(cachedRenderedReport){this._auditResultsElement.appendChild(cachedRenderedReport);return;}
  16. const reportContainer=this._auditResultsElement.createChild('div','lh-vars lh-root lh-devtools');const dom=new DOM((this._auditResultsElement.ownerDocument));const renderer=new Audits.ReportRenderer(dom);const templatesHTML=Root.Runtime.cachedResources['audits/lighthouse/templates.html'];const templatesDOM=new DOMParser().parseFromString(templatesHTML,'text/html');if(!templatesDOM){return;}
  17. renderer.setTemplateContext(templatesDOM);const el=renderer.renderReport(lighthouseResult,reportContainer);Audits.ReportRenderer.addViewTraceButton(el,artifacts);this._waitForMainTargetLoad().then(()=>{Audits.ReportRenderer.linkifyNodeDetails(el);Audits.ReportRenderer.linkifySourceLocationDetails(el);});Audits.ReportRenderer.handleDarkMode(el);const features=new Audits.ReportUIFeatures(dom);features.setBeforePrint(this._beforePrint.bind(this));features.setAfterPrint(this._afterPrint.bind(this));features.setTemplateContext(templatesDOM);features.initFeatures(lighthouseResult);this._cachedRenderedReports.set(lighthouseResult,reportContainer);}
  18. _waitForMainTargetLoad(){const mainTarget=SDK.targetManager.mainTarget();const resourceTreeModel=mainTarget.model(SDK.ResourceTreeModel);return resourceTreeModel.once(SDK.ResourceTreeModel.Events.Load);}
  19. _buildReportUI(lighthouseResult,artifacts){if(lighthouseResult===null){return;}
  20. const optionElement=new Audits.ReportSelector.Item(lighthouseResult,()=>this._renderReport(lighthouseResult,artifacts),this._renderStartView.bind(this));this._reportSelector.prepend(optionElement);this._refreshToolbarUI();this._renderReport(lighthouseResult);}
  21. _handleDrop(dataTransfer){const items=dataTransfer.items;if(!items.length){return;}
  22. const item=items[0];if(item.kind==='file'){const entry=items[0].webkitGetAsEntry();if(!entry.isFile){return;}
  23. entry.file(file=>{const reader=new FileReader();reader.onload=()=>this._loadedFromFile((reader.result));reader.readAsText(file);});}}
  24. _loadedFromFile(report){const data=JSON.parse(report);if(!data['lighthouseVersion']){return;}
  25. this._buildReportUI((data));}
  26. async _startAudit(){Host.userMetrics.actionTaken(Host.UserMetrics.Action.AuditsStarted);try{const inspectedURL=await this._controller.getInspectedURL({force:true});const categoryIDs=this._controller.getCategoryIDs();const flags=this._controller.getFlags();await this._setupEmulationAndProtocolConnection();this._renderStatusView(inspectedURL);const lighthouseResponse=await this._protocolService.startLighthouse(inspectedURL,categoryIDs,flags);if(lighthouseResponse&&lighthouseResponse.fatal){const error=new Error(lighthouseResponse.message);error.stack=lighthouseResponse.stack;throw error;}
  27. if(!lighthouseResponse){throw new Error('Auditing failed to produce a result');}
  28. Host.userMetrics.actionTaken(Host.UserMetrics.Action.AuditsFinished);await this._resetEmulationAndProtocolConnection();this._buildReportUI(lighthouseResponse.lhr,lighthouseResponse.artifacts);}catch(err){await this._resetEmulationAndProtocolConnection();if(err instanceof Error){this._statusView.renderBugReport(err);}}}
  29. async _cancelAudit(){this._statusView.updateStatus(ls`Cancelling`);await this._resetEmulationAndProtocolConnection();this._renderStartView();}
  30. async _setupEmulationAndProtocolConnection(){const flags=this._controller.getFlags();const emulationModel=self.singleton(Emulation.DeviceModeModel);this._stateBefore={emulation:{enabled:emulationModel.enabledSetting().get(),outlineEnabled:emulationModel.deviceOutlineSetting().get(),toolbarControlsEnabled:emulationModel.toolbarControlsEnabledSetting().get()},network:{conditions:SDK.multitargetNetworkManager.networkConditions()}};emulationModel.toolbarControlsEnabledSetting().set(false);if(flags.emulatedFormFactor==='desktop'){emulationModel.enabledSetting().set(false);emulationModel.emulate(Emulation.DeviceModeModel.Type.None,null,null);}else if(flags.emulatedFormFactor==='mobile'){emulationModel.enabledSetting().set(true);emulationModel.deviceOutlineSetting().set(true);for(const device of Emulation.EmulatedDevicesList.instance().standard()){if(device.title==='Nexus 5X'){emulationModel.emulate(Emulation.DeviceModeModel.Type.Device,device,device.modes[0],1);}}}
  31. await this._protocolService.attach();this._isLHAttached=true;}
  32. async _resetEmulationAndProtocolConnection(){if(!this._isLHAttached){return;}
  33. this._isLHAttached=false;await this._protocolService.detach();if(this._stateBefore){const emulationModel=self.singleton(Emulation.DeviceModeModel);emulationModel.enabledSetting().set(this._stateBefore.emulation.enabled);emulationModel.deviceOutlineSetting().set(this._stateBefore.emulation.outlineEnabled);emulationModel.toolbarControlsEnabledSetting().set(this._stateBefore.emulation.toolbarControlsEnabled);SDK.multitargetNetworkManager.setNetworkConditions(this._stateBefore.network.conditions);delete this._stateBefore;}
  34. Emulation.InspectedPagePlaceholder.instance().update(true);const resourceTreeModel=SDK.targetManager.mainTarget().model(SDK.ResourceTreeModel);const inspectedURL=await this._controller.getInspectedURL();await resourceTreeModel.navigate(inspectedURL);}}
  35. self.Audits=self.Audits||{};Audits=Audits||{};Audits.AuditsPanel=AuditsPanel;