123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- 'use strict';const ELLIPSIS='\u2026';const NBSP='\xa0';const PASS_THRESHOLD=0.9;const SCREENSHOT_PREFIX='data:image/jpeg;base64,';const RATINGS={PASS:{label:'pass',minScore:PASS_THRESHOLD},AVERAGE:{label:'average',minScore:0.5},FAIL:{label:'fail'},ERROR:{label:'error'},};const listOfTlds=['com','co','gov','edu','ac','org','go','gob','or','net','in','ne','nic','gouv','web','spb','blog','jus','kiev','mil','wi','qc','ca','bel','on',];class Util{static get PASS_THRESHOLD(){return PASS_THRESHOLD;}
- static get MS_DISPLAY_VALUE(){return`%10d${NBSP}ms`;}
- static prepareReportResult(result){const clone=(JSON.parse(JSON.stringify(result)));if(!clone.configSettings.locale){clone.configSettings.locale='en';}
- for(const audit of Object.values(clone.audits)){if(audit.scoreDisplayMode==='not_applicable'||audit.scoreDisplayMode==='not-applicable'){audit.scoreDisplayMode='notApplicable';}
- if(audit.details){if(audit.details.type===undefined||audit.details.type==='diagnostic'){audit.details.type='debugdata';}
- if(audit.details.type==='filmstrip'){for(const screenshot of audit.details.items){if(!screenshot.data.startsWith(SCREENSHOT_PREFIX)){screenshot.data=SCREENSHOT_PREFIX+screenshot.data;}}}}}
- Util.setNumberDateLocale(clone.configSettings.locale);if(clone.i18n&&clone.i18n.rendererFormattedStrings){Util.updateAllUIStrings(clone.i18n.rendererFormattedStrings);}
- if(typeof clone.categories!=='object')throw new Error('No categories provided.');for(const category of Object.values(clone.categories)){category.auditRefs.forEach(auditRef=>{const result=clone.audits[auditRef.id];auditRef.result=result;if(clone.stackPacks){clone.stackPacks.forEach(pack=>{if(pack.descriptions[auditRef.id]){auditRef.stackPacks=auditRef.stackPacks||[];auditRef.stackPacks.push({title:pack.title,iconDataURL:pack.iconDataURL,description:pack.descriptions[auditRef.id],});}});}});}
- return clone;}
- static updateAllUIStrings(rendererFormattedStrings){for(const[key,value]of Object.entries(rendererFormattedStrings)){Util.UIStrings[key]=value;}}
- static showAsPassed(audit){switch(audit.scoreDisplayMode){case'manual':case'notApplicable':return true;case'error':case'informative':return false;case'numeric':case'binary':default:return Number(audit.score)>=RATINGS.PASS.minScore;}}
- static calculateRating(score,scoreDisplayMode){if(scoreDisplayMode==='manual'||scoreDisplayMode==='notApplicable'){return RATINGS.PASS.label;}else if(scoreDisplayMode==='error'){return RATINGS.ERROR.label;}else if(score===null){return RATINGS.FAIL.label;}
- let rating=RATINGS.FAIL.label;if(score>=RATINGS.PASS.minScore){rating=RATINGS.PASS.label;}else if(score>=RATINGS.AVERAGE.minScore){rating=RATINGS.AVERAGE.label;}
- return rating;}
- static formatNumber(number,granularity=0.1){const coarseValue=Math.round(number/granularity)*granularity;return Util.numberFormatter.format(coarseValue);}
- static formatBytesToKB(size,granularity=0.1){const kbs=Util.numberFormatter.format(Math.round(size/1024/granularity)*granularity);return`${kbs}${NBSP}KB`;}
- static formatMilliseconds(ms,granularity=10){const coarseTime=Math.round(ms/granularity)*granularity;return`${Util.numberFormatter.format(coarseTime)}${NBSP}ms`;}
- static formatSeconds(ms,granularity=0.1){const coarseTime=Math.round(ms/1000/granularity)*granularity;return`${Util.numberFormatter.format(coarseTime)}${NBSP}s`;}
- static formatDateTime(date){const options={month:'short',day:'numeric',year:'numeric',hour:'numeric',minute:'numeric',timeZoneName:'short',};let formatter=new Intl.DateTimeFormat(Util.numberDateLocale,options);const tz=formatter.resolvedOptions().timeZone;if(!tz||tz.toLowerCase()==='etc/unknown'){options.timeZone='UTC';formatter=new Intl.DateTimeFormat(Util.numberDateLocale,options);}
- return formatter.format(new Date(date));}
- static formatDuration(timeInMilliseconds){let timeInSeconds=timeInMilliseconds/1000;if(Math.round(timeInSeconds)===0){return'None';}
- const parts=[];const unitLabels=({d:60*60*24,h:60*60,m:60,s:1,});Object.keys(unitLabels).forEach(label=>{const unit=unitLabels[label];const numberOfUnits=Math.floor(timeInSeconds/unit);if(numberOfUnits>0){timeInSeconds-=numberOfUnits*unit;parts.push(`${numberOfUnits}\xa0${label}`);}});return parts.join(' ');}
- static splitMarkdownCodeSpans(text){const segments=[];const parts=text.split(/`(.*?)`/g);for(let i=0;i<parts.length;i++){const text=parts[i];if(!text)continue;const isCode=i%2!==0;segments.push({isCode,text,});}
- return segments;}
- static splitMarkdownLink(text){const segments=[];const parts=text.split(/\[([^\]]+?)\]\((https?:\/\/.*?)\)/g);while(parts.length){const[preambleText,linkText,linkHref]=parts.splice(0,3);if(preambleText){segments.push({isLink:false,text:preambleText,});}
- if(linkText&&linkHref){segments.push({isLink:true,text:linkText,linkHref,});}}
- return segments;}
- static getURLDisplayName(parsedUrl,options){options=options||{numPathParts:undefined,preserveQuery:undefined,preserveHost:undefined};const numPathParts=options.numPathParts!==undefined?options.numPathParts:2;const preserveQuery=options.preserveQuery!==undefined?options.preserveQuery:true;const preserveHost=options.preserveHost||false;let name;if(parsedUrl.protocol==='about:'||parsedUrl.protocol==='data:'){name=parsedUrl.href;}else{name=parsedUrl.pathname;const parts=name.split('/').filter(part=>part.length);if(numPathParts&&parts.length>numPathParts){name=ELLIPSIS+parts.slice(-1*numPathParts).join('/');}
- if(preserveHost){name=`${parsedUrl.host}/${name.replace(/^\//, '')}`;}
- if(preserveQuery){name=`${name}${parsedUrl.search}`;}}
- const MAX_LENGTH=64;name=name.replace(/([a-f0-9]{7})[a-f0-9]{13}[a-f0-9]*/g,`$1${ELLIPSIS}`);name=name.replace(/([a-zA-Z0-9-_]{9})(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])[a-zA-Z0-9-_]{10,}/g,`$1${ELLIPSIS}`);name=name.replace(/(\d{3})\d{6,}/g,`$1${ELLIPSIS}`);name=name.replace(/\u2026+/g,ELLIPSIS);if(name.length>MAX_LENGTH&&name.includes('?')){name=name.replace(/\?([^=]*)(=)?.*/,`?$1$2${ELLIPSIS}`);if(name.length>MAX_LENGTH){name=name.replace(/\?.*/,`?${ELLIPSIS}`);}}
- if(name.length>MAX_LENGTH){const dotIndex=name.lastIndexOf('.');if(dotIndex>=0){name=name.slice(0,MAX_LENGTH-1-(name.length-dotIndex))+`${ELLIPSIS}${name.slice(dotIndex)}`;}else{name=name.slice(0,MAX_LENGTH-1)+ELLIPSIS;}}
- return name;}
- static parseURL(url){const parsedUrl=new URL(url);return{file:Util.getURLDisplayName(parsedUrl),hostname:parsedUrl.hostname,origin:parsedUrl.origin,};}
- static createOrReturnURL(value){if(value instanceof URL){return value;}
- return new URL(value);}
- static getTld(hostname){const tlds=hostname.split('.').slice(-2);if(!listOfTlds.includes(tlds[0])){return`.${tlds[tlds.length - 1]}`;}
- return`.${tlds.join('.')}`;}
- static getRootDomain(url){const hostname=Util.createOrReturnURL(url).hostname;const tld=Util.getTld(hostname);const splitTld=tld.split('.');return hostname.split('.').slice(-splitTld.length).join('.');}
- static getEnvironmentDisplayValues(settings){const emulationDesc=Util.getEmulationDescriptions(settings);return[{name:'Device',description:emulationDesc.deviceEmulation,},{name:'Network throttling',description:emulationDesc.networkThrottling,},{name:'CPU throttling',description:emulationDesc.cpuThrottling,},];}
- static getEmulationDescriptions(settings){let cpuThrottling;let networkThrottling;let summary;const throttling=settings.throttling;switch(settings.throttlingMethod){case'provided':cpuThrottling='Provided by environment';networkThrottling='Provided by environment';summary='No throttling applied';break;case'devtools':{const{cpuSlowdownMultiplier,requestLatencyMs}=throttling;cpuThrottling=`${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (DevTools)`;networkThrottling=`${Util.formatNumber(requestLatencyMs)}${NBSP}ms HTTP RTT, `+`${Util.formatNumber(throttling.downloadThroughputKbps)}${NBSP}Kbps down, `+`${Util.formatNumber(throttling.uploadThroughputKbps)}${NBSP}Kbps up (DevTools)`;summary='Throttled Slow 4G network';break;}
- case'simulate':{const{cpuSlowdownMultiplier,rttMs,throughputKbps}=throttling;cpuThrottling=`${Util.formatNumber(cpuSlowdownMultiplier)}x slowdown (Simulated)`;networkThrottling=`${Util.formatNumber(rttMs)}${NBSP}ms TCP RTT, `+`${Util.formatNumber(throughputKbps)}${NBSP}Kbps throughput (Simulated)`;summary='Simulated Slow 4G network';break;}
- default:cpuThrottling='Unknown';networkThrottling='Unknown';summary='Unknown';}
- let deviceEmulation='No emulation';if(settings.emulatedFormFactor==='mobile')deviceEmulation='Emulated Nexus 5X';if(settings.emulatedFormFactor==='desktop')deviceEmulation='Emulated Desktop';return{deviceEmulation,cpuThrottling,networkThrottling,summary:`${deviceEmulation}, ${summary}`,};}
- static setNumberDateLocale(locale){if(locale==='en-XA')locale='de';Util.numberDateLocale=locale;Util.numberFormatter=new Intl.NumberFormat(locale);}
- static filterRelevantLines(lines,lineMessages,surroundingLineCount){if(lineMessages.length===0){return lines.slice(0,surroundingLineCount*2+1);}
- const minGapSize=3;const lineNumbersToKeep=new Set();lineMessages=lineMessages.sort((a,b)=>(a.lineNumber||0)-(b.lineNumber||0));lineMessages.forEach(({lineNumber})=>{let firstSurroundingLineNumber=lineNumber-surroundingLineCount;let lastSurroundingLineNumber=lineNumber+surroundingLineCount;while(firstSurroundingLineNumber<1){firstSurroundingLineNumber++;lastSurroundingLineNumber++;}
- if(lineNumbersToKeep.has(firstSurroundingLineNumber-minGapSize-1)){firstSurroundingLineNumber-=minGapSize;}
- for(let i=firstSurroundingLineNumber;i<=lastSurroundingLineNumber;i++){const surroundingLineNumber=i;lineNumbersToKeep.add(surroundingLineNumber);}});return lines.filter(line=>lineNumbersToKeep.has(line.lineNumber));}
- static isPluginCategory(categoryId){return categoryId.startsWith('lighthouse-plugin-');}}
- Util.numberDateLocale='en';Util.numberFormatter=new Intl.NumberFormat(Util.numberDateLocale);Util.UIStrings={varianceDisclaimer:'Values are estimated and may vary. The performance score is [based only on these metrics](https://github.com/GoogleChrome/lighthouse/blob/d2ec9ffbb21de9ad1a0f86ed24575eda32c796f0/docs/scoring.md#how-are-the-scores-weighted).',opportunityResourceColumnLabel:'Opportunity',opportunitySavingsColumnLabel:'Estimated Savings',errorMissingAuditInfo:'Report error: no audit information',errorLabel:'Error!',warningHeader:'Warnings: ',auditGroupExpandTooltip:'Show audits',warningAuditsGroupTitle:'Passed audits but with warnings',passedAuditsGroupTitle:'Passed audits',notApplicableAuditsGroupTitle:'Not applicable',manualAuditsGroupTitle:'Additional items to manually check',toplevelWarningsMessage:'There were issues affecting this run of Lighthouse:',crcInitialNavigation:'Initial Navigation',crcLongestDurationLabel:'Maximum critical path latency:',snippetExpandButtonLabel:'Expand snippet',snippetCollapseButtonLabel:'Collapse snippet',lsPerformanceCategoryDescription:'[Lighthouse](https://developers.google.com/web/tools/lighthouse/) analysis of the current page on an emulated mobile network. Values are estimated and may vary.',labDataTitle:'Lab Data',thirdPartyResourcesLabel:'Show 3rd-party resources',};if(typeof module!=='undefined'&&module.exports){module.exports=Util;}else{self.Util=Util;};'use strict';class DOM{constructor(document){this._document=document;this._lighthouseChannel='unknown';}
- createElement(name,className,attrs={}){const element=this._document.createElement(name);if(className){element.className=className;}
- Object.keys(attrs).forEach(key=>{const value=attrs[key];if(typeof value!=='undefined'){element.setAttribute(key,value);}});return element;}
- createFragment(){return this._document.createDocumentFragment();}
- createChildOf(parentElem,elementName,className,attrs){const element=this.createElement(elementName,className,attrs);parentElem.appendChild(element);return element;}
- cloneTemplate(selector,context){const template=(context.querySelector(selector));if(!template){throw new Error(`Template not found: template${selector}`);}
- const clone=this._document.importNode(template.content,true);if(template.hasAttribute('data-stamped')){this.findAll('style',clone).forEach(style=>style.remove());}
- template.setAttribute('data-stamped','true');return clone;}
- resetTemplates(){this.findAll('template[data-stamped]',this._document).forEach(t=>{t.removeAttribute('data-stamped');});}
- convertMarkdownLinkSnippets(text){const element=this.createElement('span');for(const segment of Util.splitMarkdownLink(text)){if(!segment.isLink){element.appendChild(this._document.createTextNode(segment.text));continue;}
- const url=new URL(segment.linkHref);const DOCS_ORIGINS=['https://developers.google.com','https://web.dev'];if(DOCS_ORIGINS.includes(url.origin)){url.searchParams.set('utm_source','lighthouse');url.searchParams.set('utm_medium',this._lighthouseChannel);}
- const a=this.createElement('a');a.rel='noopener';a.target='_blank';a.textContent=segment.text;a.href=url.href;element.appendChild(a);}
- return element;}
- convertMarkdownCodeSnippets(markdownText){const element=this.createElement('span');for(const segment of Util.splitMarkdownCodeSpans(markdownText)){if(segment.isCode){const pre=this.createElement('code');pre.textContent=segment.text;element.appendChild(pre);}else{element.appendChild(this._document.createTextNode(segment.text));}}
- return element;}
- setLighthouseChannel(lighthouseChannel){this._lighthouseChannel=lighthouseChannel;}
- document(){return this._document;}
- isDevTools(){return!!this._document.querySelector('.lh-devtools');}
- find(query,context){const result=context.querySelector(query);if(result===null){throw new Error(`query ${query} not found`);}
- return result;}
- findAll(query,context){return Array.from(context.querySelectorAll(query));}}
- if(typeof module!=='undefined'&&module.exports){module.exports=DOM;}else{self.DOM=DOM;};(function(){"use strict";var element=document.createElement("details");var elementIsNative=typeof HTMLDetailsElement!="undefined"&&element instanceof HTMLDetailsElement;var support={open:"open"in element||elementIsNative,toggle:"ontoggle"in element};var styles='\ndetails, summary {\n display: block;\n}\ndetails:not([open]) > *:not(summary) {\n display: none;\n}\nsummary::before {\n content: "►";\n padding-right: 0.3rem;\n font-size: 0.6rem;\n cursor: default;\n}\n[open] > summary::before {\n content: "▼";\n}\n';var _ref=[],forEach=_ref.forEach,slice=_ref.slice;if(!support.open){polyfillStyles();polyfillProperties();polyfillToggle();polyfillAccessibility();}
- if(support.open&&!support.toggle){polyfillToggleEvent();}
- function polyfillStyles(){document.head.insertAdjacentHTML("afterbegin","<style>"+styles+"</style>");}
- function polyfillProperties(){var prototype=document.createElement("details").constructor.prototype;var setAttribute=prototype.setAttribute,removeAttribute=prototype.removeAttribute;var open=Object.getOwnPropertyDescriptor(prototype,"open");Object.defineProperties(prototype,{open:{get:function get(){if(this.tagName=="DETAILS"){return this.hasAttribute("open");}else{if(open&&open.get){return open.get.call(this);}}},set:function set(value){if(this.tagName=="DETAILS"){return value?this.setAttribute("open",""):this.removeAttribute("open");}else{if(open&&open.set){return open.set.call(this,value);}}}},setAttribute:{value:function value(name,_value){var _this=this;var call=function call(){return setAttribute.call(_this,name,_value);};if(name=="open"&&this.tagName=="DETAILS"){var wasOpen=this.hasAttribute("open");var result=call();if(!wasOpen){var summary=this.querySelector("summary");if(summary)summary.setAttribute("aria-expanded",true);triggerToggle(this);}
- return result;}
- return call();}},removeAttribute:{value:function value(name){var _this2=this;var call=function call(){return removeAttribute.call(_this2,name);};if(name=="open"&&this.tagName=="DETAILS"){var wasOpen=this.hasAttribute("open");var result=call();if(wasOpen){var summary=this.querySelector("summary");if(summary)summary.setAttribute("aria-expanded",false);triggerToggle(this);}
- return result;}
- return call();}}});}
- function polyfillToggle(){onTogglingTrigger(function(element){element.hasAttribute("open")?element.removeAttribute("open"):element.setAttribute("open","");});}
- function polyfillToggleEvent(){if(window.MutationObserver){new MutationObserver(function(mutations){forEach.call(mutations,function(mutation){var target=mutation.target,attributeName=mutation.attributeName;if(target.tagName=="DETAILS"&&attributeName=="open"){triggerToggle(target);}});}).observe(document.documentElement,{attributes:true,subtree:true});}else{onTogglingTrigger(function(element){var wasOpen=element.getAttribute("open");setTimeout(function(){var isOpen=element.getAttribute("open");if(wasOpen!=isOpen){triggerToggle(element);}},1);});}}
- function polyfillAccessibility(){setAccessibilityAttributes(document);if(window.MutationObserver){new MutationObserver(function(mutations){forEach.call(mutations,function(mutation){forEach.call(mutation.addedNodes,setAccessibilityAttributes);});}).observe(document.documentElement,{subtree:true,childList:true});}else{document.addEventListener("DOMNodeInserted",function(event){setAccessibilityAttributes(event.target);});}}
- function setAccessibilityAttributes(root){findElementsWithTagName(root,"SUMMARY").forEach(function(summary){var details=findClosestElementWithTagName(summary,"DETAILS");summary.setAttribute("aria-expanded",details.hasAttribute("open"));if(!summary.hasAttribute("tabindex"))summary.setAttribute("tabindex","0");if(!summary.hasAttribute("role"))summary.setAttribute("role","button");});}
- function eventIsSignificant(event){return!(event.defaultPrevented||event.ctrlKey||event.metaKey||event.shiftKey||event.target.isContentEditable);}
- function onTogglingTrigger(callback){addEventListener("click",function(event){if(eventIsSignificant(event)){if(event.which<=1){var element=findClosestElementWithTagName(event.target,"SUMMARY");if(element&&element.parentNode&&element.parentNode.tagName=="DETAILS"){callback(element.parentNode);}}}},false);addEventListener("keydown",function(event){if(eventIsSignificant(event)){if(event.keyCode==13||event.keyCode==32){var element=findClosestElementWithTagName(event.target,"SUMMARY");if(element&&element.parentNode&&element.parentNode.tagName=="DETAILS"){callback(element.parentNode);event.preventDefault();}}}},false);}
- function triggerToggle(element){var event=document.createEvent("Event");event.initEvent("toggle",false,false);element.dispatchEvent(event);}
- function findElementsWithTagName(root,tagName){return(root.tagName==tagName?[root]:[]).concat(typeof root.getElementsByTagName=="function"?slice.call(root.getElementsByTagName(tagName)):[]);}
- function findClosestElementWithTagName(element,tagName){if(typeof element.closest=="function"){return element.closest(tagName);}else{while(element){if(element.tagName==tagName){return element;}else{element=element.parentNode;}}}}})();;'use strict';const URL_PREFIXES=['http://','https://','data:'];class DetailsRenderer{constructor(dom){this._dom=dom;this._templateContext;}
- setTemplateContext(context){this._templateContext=context;}
- render(details){switch(details.type){case'filmstrip':return this._renderFilmstrip(details);case'list':return this._renderList(details);case'table':return this._renderTable(details);case'criticalrequestchain':return CriticalRequestChainRenderer.render(this._dom,this._templateContext,details,this);case'opportunity':return this._renderTable(details);case'screenshot':case'debugdata':return null;default:{return this._renderUnknown(details.type,details);}}}
- _renderBytes(details){const value=Util.formatBytesToKB(details.value,details.granularity);return this._renderText(value);}
- _renderMilliseconds(details){let value=Util.formatMilliseconds(details.value,details.granularity);if(details.displayUnit==='duration'){value=Util.formatDuration(details.value);}
- return this._renderText(value);}
- renderTextURL(text){const url=text;let displayedPath;let displayedHost;let title;try{const parsed=Util.parseURL(url);displayedPath=parsed.file==='/'?parsed.origin:parsed.file;displayedHost=parsed.file==='/'?'':`(${parsed.hostname})`;title=url;}catch(e){displayedPath=url;}
- const element=this._dom.createElement('div','lh-text__url');element.appendChild(this._renderLink({text:displayedPath,url}));if(displayedHost){const hostElem=this._renderText(displayedHost);hostElem.classList.add('lh-text__url-host');element.appendChild(hostElem);}
- if(title){element.title=url;element.dataset.url=url;}
- return element;}
- _renderLink(details){const allowedProtocols=['https:','http:'];let url;try{url=new URL(details.url);}catch(_){}
- if(!url||!allowedProtocols.includes(url.protocol)){return this._renderText(details.text);}
- const a=this._dom.createElement('a');a.rel='noopener';a.target='_blank';a.textContent=details.text;a.href=url.href;return a;}
- _renderText(text){const element=this._dom.createElement('div','lh-text');element.textContent=text;return element;}
- _renderNumeric(text){const element=this._dom.createElement('div','lh-numeric');element.textContent=text;return element;}
- _renderThumbnail(details){const element=this._dom.createElement('img','lh-thumbnail');const strValue=details;element.src=strValue;element.title=strValue;element.alt='';return element;}
- _renderUnknown(type,value){console.error(`Unknown details type: ${type}`,value);const element=this._dom.createElement('details','lh-unknown');this._dom.createChildOf(element,'summary').textContent=`We don't know how to render audit details of type \`${type}\`. `+'The Lighthouse version that collected this data is likely newer than the Lighthouse '+'version of the report renderer. Expand for the raw JSON.';this._dom.createChildOf(element,'pre').textContent=JSON.stringify(value,null,2);return element;}
- _renderTableValue(value,heading){if(typeof value==='undefined'||value===null){return null;}
- if(typeof value==='object'){switch(value.type){case'code':{return this._renderCode(value.value);}
- case'link':{return this._renderLink(value);}
- case'node':{return this.renderNode(value);}
- case'url':{return this.renderTextURL(value.value);}
- default:{return this._renderUnknown(value.type,value);}}}
- switch(heading.valueType){case'bytes':{const numValue=Number(value);return this._renderBytes({value:numValue,granularity:1});}
- case'code':{const strValue=String(value);return this._renderCode(strValue);}
- case'ms':{const msValue={value:Number(value),granularity:heading.granularity,displayUnit:heading.displayUnit,};return this._renderMilliseconds(msValue);}
- case'numeric':{const strValue=String(value);return this._renderNumeric(strValue);}
- case'text':{const strValue=String(value);return this._renderText(strValue);}
- case'thumbnail':{const strValue=String(value);return this._renderThumbnail(strValue);}
- case'timespanMs':{const numValue=Number(value);return this._renderMilliseconds({value:numValue});}
- case'url':{const strValue=String(value);if(URL_PREFIXES.some(prefix=>strValue.startsWith(prefix))){return this.renderTextURL(strValue);}else{return this._renderCode(strValue);}}
- default:{return this._renderUnknown(heading.valueType,value);}}}
- _getCanonicalizedTableHeadings(tableLike){if(tableLike.type==='opportunity'){return tableLike.headings;}
- return tableLike.headings.map(heading=>{return{key:heading.key,label:heading.text,valueType:heading.itemType,displayUnit:heading.displayUnit,granularity:heading.granularity,};});}
- _renderTable(details){if(!details.items.length)return this._dom.createElement('span');const tableElem=this._dom.createElement('table','lh-table');const theadElem=this._dom.createChildOf(tableElem,'thead');const theadTrElem=this._dom.createChildOf(theadElem,'tr');const headings=this._getCanonicalizedTableHeadings(details);for(const heading of headings){const valueType=heading.valueType||'text';const classes=`lh-table-column--${valueType}`;const labelEl=this._dom.createElement('div','lh-text');labelEl.textContent=heading.label;this._dom.createChildOf(theadTrElem,'th',classes).appendChild(labelEl);}
- const tbodyElem=this._dom.createChildOf(tableElem,'tbody');for(const row of details.items){const rowElem=this._dom.createChildOf(tbodyElem,'tr');for(const heading of headings){const value=row[heading.key];const valueElement=this._renderTableValue(value,heading);if(valueElement){const classes=`lh-table-column--${heading.valueType}`;this._dom.createChildOf(rowElem,'td',classes).appendChild(valueElement);}else{this._dom.createChildOf(rowElem,'td','lh-table-column--empty');}}}
- return tableElem;}
- _renderList(details){const listContainer=this._dom.createElement('div','lh-list');details.items.forEach(item=>{const snippetEl=SnippetRenderer.render(this._dom,this._templateContext,item,this);listContainer.appendChild(snippetEl);});return listContainer;}
- renderNode(item){const element=this._dom.createElement('span','lh-node');if(item.nodeLabel){const nodeLabelEl=this._dom.createElement('div');nodeLabelEl.textContent=item.nodeLabel;element.appendChild(nodeLabelEl);}
- if(item.snippet){const snippetEl=this._dom.createElement('div');snippetEl.classList.add('lh-node__snippet');snippetEl.textContent=item.snippet;element.appendChild(snippetEl);}
- if(item.selector){element.title=item.selector;}
- if(item.path)element.setAttribute('data-path',item.path);if(item.selector)element.setAttribute('data-selector',item.selector);if(item.snippet)element.setAttribute('data-snippet',item.snippet);return element;}
- _renderFilmstrip(details){const filmstripEl=this._dom.createElement('div','lh-filmstrip');for(const thumbnail of details.items){const frameEl=this._dom.createChildOf(filmstripEl,'div','lh-filmstrip__frame');this._dom.createChildOf(frameEl,'img','lh-filmstrip__thumbnail',{src:thumbnail.data,alt:`Screenshot`,});}
- return filmstripEl;}
- _renderCode(text){const pre=this._dom.createElement('pre','lh-code');pre.textContent=text;return pre;}}
- if(typeof module!=='undefined'&&module.exports){module.exports=DetailsRenderer;}else{self.DetailsRenderer=DetailsRenderer;};'use strict';class CriticalRequestChainRenderer{static initTree(tree){let startTime=0;const rootNodes=Object.keys(tree);if(rootNodes.length>0){const node=tree[rootNodes[0]];startTime=node.request.startTime;}
- return{tree,startTime,transferSize:0};}
- static createSegment(parent,id,startTime,transferSize,treeMarkers,parentIsLastChild){const node=parent[id];const siblings=Object.keys(parent);const isLastChild=siblings.indexOf(id)===(siblings.length-1);const hasChildren=!!node.children&&Object.keys(node.children).length>0;const newTreeMarkers=Array.isArray(treeMarkers)?treeMarkers.slice(0):[];if(typeof parentIsLastChild!=='undefined'){newTreeMarkers.push(!parentIsLastChild);}
- return{node,isLastChild,hasChildren,startTime,transferSize:transferSize+node.request.transferSize,treeMarkers:newTreeMarkers,};}
- static createChainNode(dom,tmpl,segment,detailsRenderer){const chainsEl=dom.cloneTemplate('#tmpl-lh-crc__chains',tmpl);dom.find('.crc-node',chainsEl).setAttribute('title',segment.node.request.url);const treeMarkeEl=dom.find('.crc-node__tree-marker',chainsEl);segment.treeMarkers.forEach(separator=>{if(separator){treeMarkeEl.appendChild(dom.createElement('span','tree-marker vert'));treeMarkeEl.appendChild(dom.createElement('span','tree-marker'));}else{treeMarkeEl.appendChild(dom.createElement('span','tree-marker'));treeMarkeEl.appendChild(dom.createElement('span','tree-marker'));}});if(segment.isLastChild){treeMarkeEl.appendChild(dom.createElement('span','tree-marker up-right'));treeMarkeEl.appendChild(dom.createElement('span','tree-marker right'));}else{treeMarkeEl.appendChild(dom.createElement('span','tree-marker vert-right'));treeMarkeEl.appendChild(dom.createElement('span','tree-marker right'));}
- if(segment.hasChildren){treeMarkeEl.appendChild(dom.createElement('span','tree-marker horiz-down'));}else{treeMarkeEl.appendChild(dom.createElement('span','tree-marker right'));}
- const url=segment.node.request.url;const linkEl=detailsRenderer.renderTextURL(url);const treevalEl=dom.find('.crc-node__tree-value',chainsEl);treevalEl.appendChild(linkEl);if(!segment.hasChildren){const{startTime,endTime,transferSize}=segment.node.request;const span=dom.createElement('span','crc-node__chain-duration');span.textContent=' - '+Util.formatMilliseconds((endTime-startTime)*1000)+', ';const span2=dom.createElement('span','crc-node__chain-duration');span2.textContent=Util.formatBytesToKB(transferSize,0.01);treevalEl.appendChild(span);treevalEl.appendChild(span2);}
- return chainsEl;}
- static buildTree(dom,tmpl,segment,elem,details,detailsRenderer){elem.appendChild(CRCRenderer.createChainNode(dom,tmpl,segment,detailsRenderer));if(segment.node.children){for(const key of Object.keys(segment.node.children)){const childSegment=CRCRenderer.createSegment(segment.node.children,key,segment.startTime,segment.transferSize,segment.treeMarkers,segment.isLastChild);CRCRenderer.buildTree(dom,tmpl,childSegment,elem,details,detailsRenderer);}}}
- static render(dom,templateContext,details,detailsRenderer){const tmpl=dom.cloneTemplate('#tmpl-lh-crc',templateContext);const containerEl=dom.find('.lh-crc',tmpl);dom.find('.crc-initial-nav',tmpl).textContent=Util.UIStrings.crcInitialNavigation;dom.find('.lh-crc__longest_duration_label',tmpl).textContent=Util.UIStrings.crcLongestDurationLabel;dom.find('.lh-crc__longest_duration',tmpl).textContent=Util.formatMilliseconds(details.longestChain.duration);const root=CRCRenderer.initTree(details.chains);for(const key of Object.keys(root.tree)){const segment=CRCRenderer.createSegment(root.tree,key,root.startTime,root.transferSize);CRCRenderer.buildTree(dom,tmpl,segment,containerEl,details,detailsRenderer);}
- return dom.find('.lh-crc-container',tmpl);}}
- const CRCRenderer=CriticalRequestChainRenderer;if(typeof module!=='undefined'&&module.exports){module.exports=CriticalRequestChainRenderer;}else{self.CriticalRequestChainRenderer=CriticalRequestChainRenderer;};'use strict';const LineVisibility={ALWAYS:0,WHEN_COLLAPSED:1,WHEN_EXPANDED:2,};const LineContentType={CONTENT_NORMAL:0,CONTENT_HIGHLIGHTED:1,PLACEHOLDER:2,MESSAGE:3,};const classNamesByContentType={[LineContentType.CONTENT_NORMAL]:['lh-snippet__line--content'],[LineContentType.CONTENT_HIGHLIGHTED]:['lh-snippet__line--content','lh-snippet__line--content-highlighted',],[LineContentType.PLACEHOLDER]:['lh-snippet__line--placeholder'],[LineContentType.MESSAGE]:['lh-snippet__line--message'],};function getLineAndPreviousLine(lines,lineNumber){return{line:lines.find(l=>l.lineNumber===lineNumber),previousLine:lines.find(l=>l.lineNumber===lineNumber-1),};}
- function getMessagesForLineNumber(messages,lineNumber){return messages.filter(h=>h.lineNumber===lineNumber);}
- function getLinesWhenCollapsed(details){const SURROUNDING_LINES_TO_SHOW_WHEN_COLLAPSED=2;return Util.filterRelevantLines(details.lines,details.lineMessages,SURROUNDING_LINES_TO_SHOW_WHEN_COLLAPSED);}
- class SnippetRenderer{static renderHeader(dom,tmpl,details,detailsRenderer,toggleExpandedFn){const linesWhenCollapsed=getLinesWhenCollapsed(details);const canExpand=linesWhenCollapsed.length<details.lines.length;const header=dom.cloneTemplate('#tmpl-lh-snippet__header',tmpl);dom.find('.lh-snippet__title',header).textContent=details.title;const{snippetCollapseButtonLabel,snippetExpandButtonLabel,}=Util.UIStrings;dom.find('.lh-snippet__btn-label-collapse',header).textContent=snippetCollapseButtonLabel;dom.find('.lh-snippet__btn-label-expand',header).textContent=snippetExpandButtonLabel;const toggleExpandButton=dom.find('.lh-snippet__toggle-expand',header);if(!canExpand){toggleExpandButton.remove();}else{toggleExpandButton.addEventListener('click',()=>toggleExpandedFn());}
- if(details.node&&dom.isDevTools()){const nodeContainer=dom.find('.lh-snippet__node',header);nodeContainer.appendChild(detailsRenderer.renderNode(details.node));}
- return header;}
- static renderSnippetLine(dom,tmpl,{content,lineNumber,truncated,contentType,visibility}){const clonedTemplate=dom.cloneTemplate('#tmpl-lh-snippet__line',tmpl);const contentLine=dom.find('.lh-snippet__line',clonedTemplate);const{classList}=contentLine;classNamesByContentType[contentType].forEach(typeClass=>classList.add(typeClass));if(visibility===LineVisibility.WHEN_COLLAPSED){classList.add('lh-snippet__show-if-collapsed');}else if(visibility===LineVisibility.WHEN_EXPANDED){classList.add('lh-snippet__show-if-expanded');}
- const lineContent=content+(truncated?'…':'');const lineContentEl=dom.find('.lh-snippet__line code',contentLine);if(contentType===LineContentType.MESSAGE){lineContentEl.appendChild(dom.convertMarkdownLinkSnippets(lineContent));}else{lineContentEl.textContent=lineContent;}
- dom.find('.lh-snippet__line-number',contentLine).textContent=lineNumber.toString();return contentLine;}
- static renderMessage(dom,tmpl,message){return SnippetRenderer.renderSnippetLine(dom,tmpl,{lineNumber:' ',content:message.message,contentType:LineContentType.MESSAGE,});}
- static renderOmittedLinesPlaceholder(dom,tmpl,visibility){return SnippetRenderer.renderSnippetLine(dom,tmpl,{lineNumber:'…',content:'',visibility,contentType:LineContentType.PLACEHOLDER,});}
- static renderSnippetContent(dom,tmpl,details){const template=dom.cloneTemplate('#tmpl-lh-snippet__content',tmpl);const snippetEl=dom.find('.lh-snippet__snippet-inner',template);details.generalMessages.forEach(m=>snippetEl.append(SnippetRenderer.renderMessage(dom,tmpl,m)));snippetEl.append(SnippetRenderer.renderSnippetLines(dom,tmpl,details));return template;}
- static renderSnippetLines(dom,tmpl,details){const{lineMessages,generalMessages,lineCount,lines}=details;const linesWhenCollapsed=getLinesWhenCollapsed(details);const hasOnlyGeneralMessages=generalMessages.length>0&&lineMessages.length===0;const lineContainer=dom.createFragment();let hasPendingOmittedLinesPlaceholderForCollapsedState=false;for(let lineNumber=1;lineNumber<=lineCount;lineNumber++){const{line,previousLine}=getLineAndPreviousLine(lines,lineNumber);const{line:lineWhenCollapsed,previousLine:previousLineWhenCollapsed,}=getLineAndPreviousLine(linesWhenCollapsed,lineNumber);const showLineWhenCollapsed=!!lineWhenCollapsed;const showPreviousLineWhenCollapsed=!!previousLineWhenCollapsed;if(showPreviousLineWhenCollapsed&&!showLineWhenCollapsed){hasPendingOmittedLinesPlaceholderForCollapsedState=true;}
- if(showLineWhenCollapsed&&hasPendingOmittedLinesPlaceholderForCollapsedState){lineContainer.append(SnippetRenderer.renderOmittedLinesPlaceholder(dom,tmpl,LineVisibility.WHEN_COLLAPSED));hasPendingOmittedLinesPlaceholderForCollapsedState=false;}
- const isFirstOmittedLineWhenExpanded=!line&&!!previousLine;const isFirstLineOverallAndIsOmittedWhenExpanded=!line&&lineNumber===1;if(isFirstOmittedLineWhenExpanded||isFirstLineOverallAndIsOmittedWhenExpanded){const hasRenderedAllLinesVisibleWhenCollapsed=!linesWhenCollapsed.some(l=>l.lineNumber>lineNumber);const onlyShowWhenExpanded=hasRenderedAllLinesVisibleWhenCollapsed||lineNumber===1;lineContainer.append(SnippetRenderer.renderOmittedLinesPlaceholder(dom,tmpl,onlyShowWhenExpanded?LineVisibility.WHEN_EXPANDED:LineVisibility.ALWAYS));hasPendingOmittedLinesPlaceholderForCollapsedState=false;}
- if(!line){continue;}
- const messages=getMessagesForLineNumber(lineMessages,lineNumber);const highlightLine=messages.length>0||hasOnlyGeneralMessages;const contentLineDetails=Object.assign({},line,{contentType:highlightLine?LineContentType.CONTENT_HIGHLIGHTED:LineContentType.CONTENT_NORMAL,visibility:lineWhenCollapsed?LineVisibility.ALWAYS:LineVisibility.WHEN_EXPANDED,});lineContainer.append(SnippetRenderer.renderSnippetLine(dom,tmpl,contentLineDetails));messages.forEach(message=>{lineContainer.append(SnippetRenderer.renderMessage(dom,tmpl,message));});}
- return lineContainer;}
- static render(dom,templateContext,details,detailsRenderer){const tmpl=dom.cloneTemplate('#tmpl-lh-snippet',templateContext);const snippetEl=dom.find('.lh-snippet',tmpl);const header=SnippetRenderer.renderHeader(dom,tmpl,details,detailsRenderer,()=>snippetEl.classList.toggle('lh-snippet--expanded'));const content=SnippetRenderer.renderSnippetContent(dom,tmpl,details);snippetEl.append(header,content);return snippetEl;}}
- if(typeof module!=='undefined'&&module.exports){module.exports=SnippetRenderer;}else{self.SnippetRenderer=SnippetRenderer;};'use strict';function getFilenamePrefix(lhr){const hostname=new URL(lhr.finalUrl).hostname;const date=(lhr.fetchTime&&new Date(lhr.fetchTime))||new Date();const timeStr=date.toLocaleTimeString('en-US',{hour12:false});const dateParts=date.toLocaleDateString('en-US',{year:'numeric',month:'2-digit',day:'2-digit',}).split('/');dateParts.unshift(dateParts.pop());const dateStr=dateParts.join('-');const filenamePrefix=`${hostname}_${dateStr}_${timeStr}`;return filenamePrefix.replace(/[/?<>\\:*|"]/g,'-');}
- if(typeof module!=='undefined'&&module.exports){module.exports={getFilenamePrefix};};'use strict';class Logger{constructor(element){this.el=element;this._id=undefined;}
- log(msg,autoHide=true){this._id&&clearTimeout(this._id);this.el.textContent=msg;this.el.classList.add('show');if(autoHide){this._id=setTimeout(_=>{this.el.classList.remove('show');},7000);}}
- warn(msg){this.log('Warning: '+msg);}
- error(msg){this.log(msg);setTimeout(_=>{throw new Error(msg);},0);}
- hide(){this._id&&clearTimeout(this._id);this.el.classList.remove('show');}}
- if(typeof module!=='undefined'&&module.exports){module.exports=Logger;};'use strict';function getTableRows(tableEl){return Array.from(tableEl.tBodies[0].rows);}
- class ReportUIFeatures{constructor(dom){this.json;this._dom=dom;this._document=this._dom.document();this._templateContext=this._dom.document();this._dropDown=new DropDown(this._dom);this._copyAttempt=false;this.topbarEl;this.scoreScaleEl;this.stickyHeaderEl;this.highlightEl;this.onMediaQueryChange=this.onMediaQueryChange.bind(this);this.onCopy=this.onCopy.bind(this);this.onDropDownMenuClick=this.onDropDownMenuClick.bind(this);this.onKeyUp=this.onKeyUp.bind(this);this.collapseAllDetails=this.collapseAllDetails.bind(this);this.expandAllDetails=this.expandAllDetails.bind(this);this._toggleDarkTheme=this._toggleDarkTheme.bind(this);this._updateStickyHeaderOnScroll=this._updateStickyHeaderOnScroll.bind(this);}
- initFeatures(report){this.json=report;this._setupMediaQueryListeners();this._dropDown.setup(this.onDropDownMenuClick);this._setupThirdPartyFilter();this._setUpCollapseDetailsAfterPrinting();this._resetUIState();this._document.addEventListener('keyup',this.onKeyUp);this._document.addEventListener('copy',this.onCopy);const topbarLogo=this._dom.find('.lh-topbar__logo',this._document);topbarLogo.addEventListener('click',()=>this._toggleDarkTheme());let turnOffTheLights=false;if(!this._dom.isDevTools()&&window.matchMedia('(prefers-color-scheme: dark)').matches){turnOffTheLights=true;}
- const scoresAll100=Object.values(report.categories).every(cat=>cat.score===1);const hasAllCoreCategories=Object.keys(report.categories).filter(id=>!Util.isPluginCategory(id)).length>=5;if(scoresAll100&&hasAllCoreCategories){turnOffTheLights=true;this._enableFireworks();}
- if(turnOffTheLights){this._toggleDarkTheme(true);}
- if(Object.keys(this.json.categories).length>=2){this._setupStickyHeaderElements();const containerEl=this._dom.find('.lh-container',this._document);const elToAddScrollListener=this._getScrollParent(containerEl);elToAddScrollListener.addEventListener('scroll',this._updateStickyHeaderOnScroll);if(this._dom.isDevTools()){const resizeObserver=new window.ResizeObserver(this._updateStickyHeaderOnScroll);resizeObserver.observe(containerEl);}else{window.addEventListener('resize',this._updateStickyHeaderOnScroll);}}
- const hasMetricError=report.categories.performance&&report.categories.performance.auditRefs.some(audit=>Boolean(audit.group==='metrics'&&report.audits[audit.id].errorMessage));if(hasMetricError){const toggleInputEl=(this._dom.find('.lh-metrics-toggle__input',this._document));toggleInputEl.checked=true;}}
- setTemplateContext(context){this._templateContext=context;}
- _getScrollParent(element){const{overflowY}=window.getComputedStyle(element);const isScrollable=overflowY!=='visible'&&overflowY!=='hidden';if(isScrollable){return element;}
- if(element.parentElement){return this._getScrollParent(element.parentElement);}
- return document;}
- _enableFireworks(){const scoresContainer=this._dom.find('.lh-scores-container',this._document);scoresContainer.classList.add('score100');scoresContainer.addEventListener('click',_=>{scoresContainer.classList.toggle('fireworks-paused');});}
- _fireEventOn(name,target=this._document,detail){const event=new CustomEvent(name,detail?{detail}:undefined);target.dispatchEvent(event);}
- _setupMediaQueryListeners(){const mediaQuery=self.matchMedia('(max-width: 500px)');mediaQuery.addListener(this.onMediaQueryChange);this.onMediaQueryChange(mediaQuery);}
- onMediaQueryChange(mql){const root=this._dom.find('.lh-root',this._document);root.classList.toggle('lh-narrow',mql.matches);}
- _setupThirdPartyFilter(){const thirdPartyFilterAuditExclusions=['uses-rel-preconnect',];const tables=Array.from(this._document.querySelectorAll('.lh-table'));const tablesWithUrls=tables.filter(el=>el.querySelector('td.lh-table-column--url')).filter(el=>{const containingAudit=el.closest('.lh-audit');if(!containingAudit)throw new Error('.lh-table not within audit');return!thirdPartyFilterAuditExclusions.includes(containingAudit.id);});tablesWithUrls.forEach((tableEl,index)=>{const urlItems=this._getUrlItems(tableEl);const thirdPartyRows=this._getThirdPartyRows(tableEl,urlItems,this.json.finalUrl);const filterTemplate=this._dom.cloneTemplate('#tmpl-lh-3p-filter',this._templateContext);const filterInput=(this._dom.find('input',filterTemplate));const id=`lh-3p-filter-label--${index}`;filterInput.id=id;filterInput.addEventListener('change',e=>{if(e.target instanceof HTMLInputElement&&!e.target.checked){for(const row of thirdPartyRows.values()){row.remove();}}else{for(const[position,row]of thirdPartyRows.entries()){const childrenArr=getTableRows(tableEl);tableEl.tBodies[0].insertBefore(row,childrenArr[position]);}}});this._dom.find('label',filterTemplate).setAttribute('for',id);this._dom.find('.lh-3p-filter-count',filterTemplate).textContent=`${thirdPartyRows.size}`;this._dom.find('.lh-3p-ui-string',filterTemplate).textContent=Util.UIStrings.thirdPartyResourcesLabel;if(thirdPartyRows.size===urlItems.length||!thirdPartyRows.size){filterInput.disabled=true;filterInput.checked=thirdPartyRows.size===urlItems.length;}
- if(!tableEl.parentNode)return;tableEl.parentNode.insertBefore(filterTemplate,tableEl);});}
- _getThirdPartyRows(el,urlItems,finalUrl){const finalUrlRootDomain=Util.getRootDomain(finalUrl);const thirdPartyRows=new Map();for(const urlItem of urlItems){const datasetUrl=urlItem.dataset.url;if(!datasetUrl)continue;const isThirdParty=Util.getRootDomain(datasetUrl)!==finalUrlRootDomain;if(!isThirdParty)continue;const urlRowEl=urlItem.closest('tr');if(urlRowEl){const rowPosition=getTableRows(el).indexOf(urlRowEl);thirdPartyRows.set(rowPosition,urlRowEl);}}
- return thirdPartyRows;}
- _getUrlItems(tableEl){return this._dom.findAll('.lh-text__url',tableEl);}
- _setupStickyHeaderElements(){this.topbarEl=this._dom.find('.lh-topbar',this._document);this.scoreScaleEl=this._dom.find('.lh-scorescale',this._document);this.stickyHeaderEl=this._dom.find('.lh-sticky-header',this._document);this.highlightEl=this._dom.createChildOf(this.stickyHeaderEl,'div','lh-highlighter');}
- onCopy(e){if(this._copyAttempt&&e.clipboardData){e.preventDefault();e.clipboardData.setData('text/plain',JSON.stringify(this.json,null,2));this._fireEventOn('lh-log',this._document,{cmd:'log',msg:'Report JSON copied to clipboard',});}
- this._copyAttempt=false;}
- onCopyButtonClick(){this._fireEventOn('lh-analytics',this._document,{cmd:'send',fields:{hitType:'event',eventCategory:'report',eventAction:'copy'},});try{if(this._document.queryCommandSupported('copy')){this._copyAttempt=true;if(!this._document.execCommand('copy')){this._copyAttempt=false;this._fireEventOn('lh-log',this._document,{cmd:'warn',msg:'Your browser does not support copy to clipboard.',});}}}catch(e){this._copyAttempt=false;this._fireEventOn('lh-log',this._document,{cmd:'log',msg:e.message});}}
- _resetUIState(){this._dropDown.close();this._dom.resetTemplates();}
- onDropDownMenuClick(e){e.preventDefault();const el=(e.target);if(!el||!el.hasAttribute('data-action')){return;}
- switch(el.getAttribute('data-action')){case'copy':this.onCopyButtonClick();break;case'print-summary':this.collapseAllDetails();this._print();break;case'print-expanded':this.expandAllDetails();this._print();break;case'save-json':{const jsonStr=JSON.stringify(this.json,null,2);this._saveFile(new Blob([jsonStr],{type:'application/json'}));break;}
- case'save-html':{const htmlStr=this.getReportHtml();try{this._saveFile(new Blob([htmlStr],{type:'text/html'}));}catch(e){this._fireEventOn('lh-log',this._document,{cmd:'error',msg:'Could not export as HTML. '+e.message,});}
- break;}
- case'open-viewer':{const viewerPath='/lighthouse/viewer/';ReportUIFeatures.openTabAndSendJsonReport(this.json,viewerPath);break;}
- case'save-gist':{this.saveAsGist();break;}
- case'toggle-dark':{this._toggleDarkTheme();break;}}
- this._dropDown.close();}
- _print(){self.print();}
- onKeyUp(e){if((e.ctrlKey||e.metaKey)&&e.keyCode===80){this._dropDown.close();}}
- static openTabAndSendJsonReport(reportJson,viewerPath){const VIEWER_ORIGIN='https://googlechrome.github.io';const json=reportJson;window.addEventListener('message',function msgHandler(messageEvent){if(messageEvent.origin!==VIEWER_ORIGIN){return;}
- if(popup&&messageEvent.data.opened){popup.postMessage({lhresults:json},VIEWER_ORIGIN);window.removeEventListener('message',msgHandler);}});const fallbackFetchTime=(json.generatedTime);const fetchTime=json.fetchTime||fallbackFetchTime;const windowName=`${json.lighthouseVersion}-${json.requestedUrl}-${fetchTime}`;const popup=window.open(`${VIEWER_ORIGIN}${viewerPath}`,windowName);}
- expandAllDetails(){const details=(this._dom.findAll('.lh-categories details',this._document));details.map(detail=>detail.open=true);}
- collapseAllDetails(){const details=(this._dom.findAll('.lh-categories details',this._document));details.map(detail=>detail.open=false);}
- _setUpCollapseDetailsAfterPrinting(){if('onbeforeprint'in self){self.addEventListener('afterprint',this.collapseAllDetails);}else{const win=(self);win.matchMedia('print').addListener(mql=>{if(mql.matches){this.expandAllDetails();}else{this.collapseAllDetails();}});}}
- getReportHtml(){this._resetUIState();return this._document.documentElement.outerHTML;}
- saveAsGist(){throw new Error('Cannot save as gist from base report');}
- _saveFile(blob){const filename=getFilenamePrefix({finalUrl:this.json.finalUrl,fetchTime:this.json.fetchTime,});const ext=blob.type.match('json')?'.json':'.html';const href=URL.createObjectURL(blob);const a=this._dom.createElement('a');a.download=`${filename}${ext}`;a.href=href;this._document.body.appendChild(a);a.click();this._document.body.removeChild(a);setTimeout(_=>URL.revokeObjectURL(href),500);}
- _toggleDarkTheme(force){const el=this._dom.find('.lh-vars',this._document);if(typeof force==='undefined'){el.classList.toggle('dark');}else{el.classList.toggle('dark',force);}}
- _updateStickyHeaderOnScroll(){const topbarBottom=this.topbarEl.getBoundingClientRect().bottom;const scoreScaleTop=this.scoreScaleEl.getBoundingClientRect().top;const showStickyHeader=topbarBottom>=scoreScaleTop;const categoryEls=Array.from(this._document.querySelectorAll('.lh-category'));const categoriesAboveTheMiddle=categoryEls.filter(el=>el.getBoundingClientRect().top-window.innerHeight/2<0);const highlightIndex=categoriesAboveTheMiddle.length>0?categoriesAboveTheMiddle.length-1:0;const gaugeWrapperEls=this.stickyHeaderEl.querySelectorAll('.lh-gauge__wrapper');const gaugeToHighlight=gaugeWrapperEls[highlightIndex];const origin=gaugeWrapperEls[0].getBoundingClientRect().left;const offset=gaugeToHighlight.getBoundingClientRect().left-origin;this.highlightEl.style.transform=`translate(${offset}px)`;this.stickyHeaderEl.classList.toggle('lh-sticky-header--visible',showStickyHeader);}}
- class DropDown{constructor(dom){this._dom=dom;this._toggleEl;this._menuEl;this.onDocumentKeyDown=this.onDocumentKeyDown.bind(this);this.onToggleClick=this.onToggleClick.bind(this);this.onToggleKeydown=this.onToggleKeydown.bind(this);this.onMenuKeydown=this.onMenuKeydown.bind(this);this._getNextMenuItem=this._getNextMenuItem.bind(this);this._getNextSelectableNode=this._getNextSelectableNode.bind(this);this._getPreviousMenuItem=this._getPreviousMenuItem.bind(this);}
- setup(menuClickHandler){this._toggleEl=this._dom.find('.lh-tools__button',this._dom.document());this._toggleEl.addEventListener('click',this.onToggleClick);this._toggleEl.addEventListener('keydown',this.onToggleKeydown);this._menuEl=this._dom.find('.lh-tools__dropdown',this._dom.document());this._menuEl.addEventListener('keydown',this.onMenuKeydown);this._menuEl.addEventListener('click',menuClickHandler);}
- close(){this._toggleEl.classList.remove('active');this._toggleEl.setAttribute('aria-expanded','false');if(this._menuEl.contains(this._dom.document().activeElement)){this._toggleEl.focus();}
- this._dom.document().removeEventListener('keydown',this.onDocumentKeyDown);}
- open(firstFocusElement){if(this._toggleEl.classList.contains('active')){firstFocusElement.focus();}else{this._menuEl.addEventListener('transitionend',()=>{firstFocusElement.focus();},{once:true});}
- this._toggleEl.classList.add('active');this._toggleEl.setAttribute('aria-expanded','true');this._dom.document().addEventListener('keydown',this.onDocumentKeyDown);}
- onToggleClick(e){e.preventDefault();e.stopImmediatePropagation();if(this._toggleEl.classList.contains('active')){this.close();}else{this.open(this._getNextMenuItem());}}
- onToggleKeydown(e){switch(e.code){case'ArrowUp':e.preventDefault();this.open(this._getPreviousMenuItem());break;case'ArrowDown':case'Enter':case' ':e.preventDefault();this.open(this._getNextMenuItem());break;default:}}
- onMenuKeydown(e){const el=(e.target);switch(e.code){case'ArrowUp':e.preventDefault();this._getPreviousMenuItem(el).focus();break;case'ArrowDown':e.preventDefault();this._getNextMenuItem(el).focus();break;case'Home':e.preventDefault();this._getNextMenuItem().focus();break;case'End':e.preventDefault();this._getPreviousMenuItem().focus();break;default:}}
- onDocumentKeyDown(e){if(e.keyCode===27){this.close();}}
- _getNextSelectableNode(allNodes,startNode){const nodes=allNodes.filter((node)=>{if(!(node instanceof HTMLElement)){return false;}
- if(node.hasAttribute('disabled')){return false;}
- if(window.getComputedStyle(node).display==='none'){return false;}
- return true;});let nextIndex=startNode?(nodes.indexOf(startNode)+1):0;if(nextIndex>=nodes.length){nextIndex=0;}
- return nodes[nextIndex];}
- _getNextMenuItem(startEl){const nodes=Array.from(this._menuEl.childNodes);return(this._getNextSelectableNode(nodes,startEl));}
- _getPreviousMenuItem(startEl){const nodes=Array.from(this._menuEl.childNodes).reverse();return(this._getNextSelectableNode(nodes,startEl));}}
- if(typeof module!=='undefined'&&module.exports){module.exports=ReportUIFeatures;}else{self.ReportUIFeatures=ReportUIFeatures;};'use strict';class CategoryRenderer{constructor(dom,detailsRenderer){this.dom=dom;this.detailsRenderer=detailsRenderer;this.templateContext=this.dom.document();this.detailsRenderer.setTemplateContext(this.templateContext);}
- get _clumpTitles(){return{warning:Util.UIStrings.warningAuditsGroupTitle,manual:Util.UIStrings.manualAuditsGroupTitle,passed:Util.UIStrings.passedAuditsGroupTitle,notApplicable:Util.UIStrings.notApplicableAuditsGroupTitle,};}
- renderAudit(audit){const tmpl=this.dom.cloneTemplate('#tmpl-lh-audit',this.templateContext);return this.populateAuditValues(audit,tmpl);}
- populateAuditValues(audit,tmpl){const auditEl=this.dom.find('.lh-audit',tmpl);auditEl.id=audit.result.id;const scoreDisplayMode=audit.result.scoreDisplayMode;if(audit.result.displayValue){this.dom.find('.lh-audit__display-text',auditEl).textContent=audit.result.displayValue;}
- const titleEl=this.dom.find('.lh-audit__title',auditEl);titleEl.appendChild(this.dom.convertMarkdownCodeSnippets(audit.result.title));this.dom.find('.lh-audit__description',auditEl).appendChild(this.dom.convertMarkdownLinkSnippets(audit.result.description));if(audit.stackPacks){audit.stackPacks.forEach(pack=>{const packElm=this.dom.createElement('div');packElm.classList.add('lh-audit__stackpack');const packElmImg=this.dom.createElement('img');packElmImg.classList.add('lh-audit__stackpack__img');packElmImg.src=pack.iconDataURL;packElmImg.alt=pack.title;packElm.appendChild(packElmImg);packElm.appendChild(this.dom.convertMarkdownLinkSnippets(pack.description));this.dom.find('.lh-audit__stackpacks',auditEl).appendChild(packElm);});}
- const header=(this.dom.find('details',auditEl));if(audit.result.details){const elem=this.detailsRenderer.render(audit.result.details);if(elem){elem.classList.add('lh-details');header.appendChild(elem);}}
- this.dom.find('.lh-chevron-container',auditEl).appendChild(this._createChevron());this._setRatingClass(auditEl,audit.result.score,scoreDisplayMode);if(audit.result.scoreDisplayMode==='error'){auditEl.classList.add(`lh-audit--error`);const textEl=this.dom.find('.lh-audit__display-text',auditEl);textEl.textContent=Util.UIStrings.errorLabel;textEl.classList.add('tooltip-boundary');const tooltip=this.dom.createChildOf(textEl,'div','tooltip tooltip--error');tooltip.textContent=audit.result.errorMessage||Util.UIStrings.errorMissingAuditInfo;}else if(audit.result.explanation){const explEl=this.dom.createChildOf(titleEl,'div','lh-audit-explanation');explEl.textContent=audit.result.explanation;}
- const warnings=audit.result.warnings;if(!warnings||warnings.length===0)return auditEl;const warningsEl=this.dom.createChildOf(titleEl,'div','lh-warnings');this.dom.createChildOf(warningsEl,'span').textContent=Util.UIStrings.warningHeader;if(warnings.length===1){warningsEl.appendChild(this.dom.document().createTextNode(warnings.join('')));}else{const warningsUl=this.dom.createChildOf(warningsEl,'ul');for(const warning of warnings){const item=this.dom.createChildOf(warningsUl,'li');item.textContent=warning;}}
- return auditEl;}
- _createChevron(){const chevronTmpl=this.dom.cloneTemplate('#tmpl-lh-chevron',this.templateContext);const chevronEl=this.dom.find('.lh-chevron',chevronTmpl);return chevronEl;}
- _setRatingClass(element,score,scoreDisplayMode){const rating=Util.calculateRating(score,scoreDisplayMode);element.classList.add(`lh-audit--${scoreDisplayMode.toLowerCase()}`);if(scoreDisplayMode!=='informative'){element.classList.add(`lh-audit--${rating}`);}
- return element;}
- renderCategoryHeader(category,groupDefinitions){const tmpl=this.dom.cloneTemplate('#tmpl-lh-category-header',this.templateContext);const gaugeContainerEl=this.dom.find('.lh-score__gauge',tmpl);const gaugeEl=this.renderScoreGauge(category,groupDefinitions);gaugeContainerEl.appendChild(gaugeEl);if(category.description){const descEl=this.dom.convertMarkdownLinkSnippets(category.description);this.dom.find('.lh-category-header__description',tmpl).appendChild(descEl);}
- return(tmpl.firstElementChild);}
- renderAuditGroup(group){const groupEl=this.dom.createElement('div','lh-audit-group');const auditGroupHeader=this.dom.createElement('div','lh-audit-group__header');this.dom.createChildOf(auditGroupHeader,'span','lh-audit-group__title').textContent=group.title;if(group.description){const descriptionEl=this.dom.convertMarkdownLinkSnippets(group.description);descriptionEl.classList.add('lh-audit-group__description');auditGroupHeader.appendChild(descriptionEl);}
- groupEl.appendChild(auditGroupHeader);return groupEl;}
- _renderGroupedAudits(auditRefs,groupDefinitions){const grouped=new Map();const notAGroup='NotAGroup';grouped.set(notAGroup,[]);for(const auditRef of auditRefs){const groupId=auditRef.group||notAGroup;const groupAuditRefs=grouped.get(groupId)||[];groupAuditRefs.push(auditRef);grouped.set(groupId,groupAuditRefs);}
- const auditElements=[];for(const[groupId,groupAuditRefs]of grouped){if(groupId===notAGroup){for(const auditRef of groupAuditRefs){auditElements.push(this.renderAudit(auditRef));}
- continue;}
- const groupDef=groupDefinitions[groupId];const auditGroupElem=this.renderAuditGroup(groupDef);for(const auditRef of groupAuditRefs){auditGroupElem.appendChild(this.renderAudit(auditRef));}
- auditGroupElem.classList.add(`lh-audit-group--${groupId}`);auditElements.push(auditGroupElem);}
- return auditElements;}
- renderUnexpandableClump(auditRefs,groupDefinitions){const clumpElement=this.dom.createElement('div');const elements=this._renderGroupedAudits(auditRefs,groupDefinitions);elements.forEach(elem=>clumpElement.appendChild(elem));return clumpElement;}
- renderClump(clumpId,{auditRefs,description}){const clumpTmpl=this.dom.cloneTemplate('#tmpl-lh-clump',this.templateContext);const clumpElement=this.dom.find('.lh-clump',clumpTmpl);if(clumpId==='warning'){clumpElement.setAttribute('open','');}
- const summaryInnerEl=this.dom.find('.lh-audit-group__summary',clumpElement);const chevronEl=summaryInnerEl.appendChild(this._createChevron());chevronEl.title=Util.UIStrings.auditGroupExpandTooltip;const headerEl=this.dom.find('.lh-audit-group__header',clumpElement);const title=this._clumpTitles[clumpId];this.dom.find('.lh-audit-group__title',headerEl).textContent=title;if(description){const descriptionEl=this.dom.convertMarkdownLinkSnippets(description);descriptionEl.classList.add('lh-audit-group__description');headerEl.appendChild(descriptionEl);}
- const itemCountEl=this.dom.find('.lh-audit-group__itemcount',clumpElement);itemCountEl.textContent=`(${auditRefs.length})`;const auditElements=auditRefs.map(this.renderAudit.bind(this));clumpElement.append(...auditElements);clumpElement.classList.add(`lh-clump--${clumpId.toLowerCase()}`);return clumpElement;}
- setTemplateContext(context){this.templateContext=context;this.detailsRenderer.setTemplateContext(context);}
- renderScoreGauge(category,groupDefinitions){const tmpl=this.dom.cloneTemplate('#tmpl-lh-gauge',this.templateContext);const wrapper=(this.dom.find('.lh-gauge__wrapper',tmpl));wrapper.href=`#${category.id}`;wrapper.classList.add(`lh-gauge__wrapper--${Util.calculateRating(category.score)}`);if(Util.isPluginCategory(category.id)){wrapper.classList.add('lh-gauge__wrapper--plugin');}
- const numericScore=Number(category.score);const gauge=this.dom.find('.lh-gauge',tmpl);const gaugeArc=gauge.querySelector('.lh-gauge-arc');if(gaugeArc){gaugeArc.style.strokeDasharray=`${numericScore * 352} 352`;}
- const scoreOutOf100=Math.round(numericScore*100);const percentageEl=this.dom.find('.lh-gauge__percentage',tmpl);percentageEl.textContent=scoreOutOf100.toString();if(category.score===null){percentageEl.textContent='?';percentageEl.title=Util.UIStrings.errorLabel;}
- this.dom.find('.lh-gauge__label',tmpl).textContent=category.title;return tmpl;}
- _auditHasWarning(audit){return Boolean(audit.result.warnings&&audit.result.warnings.length);}
- _getClumpIdForAuditRef(auditRef){const scoreDisplayMode=auditRef.result.scoreDisplayMode;if(scoreDisplayMode==='manual'||scoreDisplayMode==='notApplicable'){return scoreDisplayMode;}
- if(Util.showAsPassed(auditRef.result)){if(this._auditHasWarning(auditRef)){return'warning';}else{return'passed';}}else{return'failed';}}
- render(category,groupDefinitions={}){const element=this.dom.createElement('div','lh-category');this.createPermalinkSpan(element,category.id);element.appendChild(this.renderCategoryHeader(category,groupDefinitions));const clumps=new Map();clumps.set('failed',[]);clumps.set('warning',[]);clumps.set('manual',[]);clumps.set('passed',[]);clumps.set('notApplicable',[]);for(const auditRef of category.auditRefs){const clumpId=this._getClumpIdForAuditRef(auditRef);const clump=(clumps.get(clumpId));clump.push(auditRef);clumps.set(clumpId,clump);}
- for(const[clumpId,auditRefs]of clumps){if(auditRefs.length===0)continue;if(clumpId==='failed'){const clumpElem=this.renderUnexpandableClump(auditRefs,groupDefinitions);clumpElem.classList.add(`lh-clump--failed`);element.appendChild(clumpElem);continue;}
- const description=clumpId==='manual'?category.manualDescription:undefined;const clumpElem=this.renderClump(clumpId,{auditRefs,description});element.appendChild(clumpElem);}
- return element;}
- createPermalinkSpan(element,id){const permalinkEl=this.dom.createChildOf(element,'span','lh-permalink');permalinkEl.id=id;}}
- if(typeof module!=='undefined'&&module.exports){module.exports=CategoryRenderer;}else{self.CategoryRenderer=CategoryRenderer;};'use strict';class PerformanceCategoryRenderer extends CategoryRenderer{_renderMetric(audit){const tmpl=this.dom.cloneTemplate('#tmpl-lh-metric',this.templateContext);const element=this.dom.find('.lh-metric',tmpl);element.id=audit.result.id;const rating=Util.calculateRating(audit.result.score,audit.result.scoreDisplayMode);element.classList.add(`lh-metric--${rating}`);const titleEl=this.dom.find('.lh-metric__title',tmpl);titleEl.textContent=audit.result.title;const valueEl=this.dom.find('.lh-metric__value',tmpl);valueEl.textContent=audit.result.displayValue||'';const descriptionEl=this.dom.find('.lh-metric__description',tmpl);descriptionEl.appendChild(this.dom.convertMarkdownLinkSnippets(audit.result.description));if(audit.result.scoreDisplayMode==='error'){descriptionEl.textContent='';valueEl.textContent='Error!';const tooltip=this.dom.createChildOf(descriptionEl,'span');tooltip.textContent=audit.result.errorMessage||'Report error: no metric information';}
- return element;}
- _renderOpportunity(audit,scale){const oppTmpl=this.dom.cloneTemplate('#tmpl-lh-opportunity',this.templateContext);const element=this.populateAuditValues(audit,oppTmpl);element.id=audit.result.id;if(!audit.result.details||audit.result.scoreDisplayMode==='error'){return element;}
- const details=audit.result.details;if(details.type!=='opportunity'){return element;}
- const displayEl=this.dom.find('.lh-audit__display-text',element);const sparklineWidthPct=`${details.overallSavingsMs / scale * 100}%`;this.dom.find('.lh-sparkline__bar',element).style.width=sparklineWidthPct;displayEl.textContent=Util.formatSeconds(details.overallSavingsMs,0.01);if(audit.result.displayValue){const displayValue=audit.result.displayValue;this.dom.find('.lh-load-opportunity__sparkline',element).title=displayValue;displayEl.title=displayValue;}
- return element;}
- _getWastedMs(audit){if(audit.result.details&&audit.result.details.type==='opportunity'){const details=audit.result.details;if(typeof details.overallSavingsMs!=='number'){throw new Error('non-opportunity details passed to _getWastedMs');}
- return details.overallSavingsMs;}else{return Number.MIN_VALUE;}}
- render(category,groups,environment){const element=this.dom.createElement('div','lh-category');if(environment==='PSI'){const gaugeEl=this.dom.createElement('div','lh-score__gauge');gaugeEl.appendChild(this.renderScoreGauge(category,groups));element.appendChild(gaugeEl);}else{this.createPermalinkSpan(element,category.id);element.appendChild(this.renderCategoryHeader(category,groups));}
- const metricAuditsEl=this.renderAuditGroup(groups.metrics);const toggleTmpl=this.dom.cloneTemplate('#tmpl-lh-metrics-toggle',this.templateContext);const _toggleEl=this.dom.find('.lh-metrics-toggle',toggleTmpl);metricAuditsEl.append(..._toggleEl.childNodes);const metricAudits=category.auditRefs.filter(audit=>audit.group==='metrics');const keyMetrics=metricAudits.filter(a=>a.weight>=3);const otherMetrics=metricAudits.filter(a=>a.weight<3);const metricsBoxesEl=this.dom.createChildOf(metricAuditsEl,'div','lh-columns');const metricsColumn1El=this.dom.createChildOf(metricsBoxesEl,'div','lh-column');const metricsColumn2El=this.dom.createChildOf(metricsBoxesEl,'div','lh-column');keyMetrics.forEach(item=>{metricsColumn1El.appendChild(this._renderMetric(item));});otherMetrics.forEach(item=>{metricsColumn2El.appendChild(this._renderMetric(item));});if(environment!=='PSI'){const estValuesEl=this.dom.createChildOf(metricAuditsEl,'div','lh-metrics__disclaimer');const disclaimerEl=this.dom.convertMarkdownLinkSnippets(Util.UIStrings.varianceDisclaimer);estValuesEl.appendChild(disclaimerEl);}
- metricAuditsEl.classList.add('lh-audit-group--metrics');element.appendChild(metricAuditsEl);const timelineEl=this.dom.createChildOf(element,'div','lh-filmstrip-container');const thumbnailAudit=category.auditRefs.find(audit=>audit.id==='screenshot-thumbnails');const thumbnailResult=thumbnailAudit&&thumbnailAudit.result;if(thumbnailResult&&thumbnailResult.details){timelineEl.id=thumbnailResult.id;const filmstripEl=this.detailsRenderer.render(thumbnailResult.details);filmstripEl&&timelineEl.appendChild(filmstripEl);}
- const budgetAudit=category.auditRefs.find(audit=>audit.id==='performance-budget');if(budgetAudit&&budgetAudit.result.details){const table=this.detailsRenderer.render(budgetAudit.result.details);if(table){table.id=budgetAudit.id;table.classList.add('lh-audit');const budgetsGroupEl=this.renderAuditGroup(groups.budgets);budgetsGroupEl.appendChild(table);budgetsGroupEl.classList.add('lh-audit-group--budgets');element.appendChild(budgetsGroupEl);}}
- const opportunityAudits=category.auditRefs.filter(audit=>audit.group==='load-opportunities'&&!Util.showAsPassed(audit.result)).sort((auditA,auditB)=>this._getWastedMs(auditB)-this._getWastedMs(auditA));if(opportunityAudits.length){const minimumScale=2000;const wastedMsValues=opportunityAudits.map(audit=>this._getWastedMs(audit));const maxWaste=Math.max(...wastedMsValues);const scale=Math.max(Math.ceil(maxWaste/1000)*1000,minimumScale);const groupEl=this.renderAuditGroup(groups['load-opportunities']);const tmpl=this.dom.cloneTemplate('#tmpl-lh-opportunity-header',this.templateContext);this.dom.find('.lh-load-opportunity__col--one',tmpl).textContent=Util.UIStrings.opportunityResourceColumnLabel;this.dom.find('.lh-load-opportunity__col--two',tmpl).textContent=Util.UIStrings.opportunitySavingsColumnLabel;const headerEl=this.dom.find('.lh-load-opportunity__header',tmpl);groupEl.appendChild(headerEl);opportunityAudits.forEach(item=>groupEl.appendChild(this._renderOpportunity(item,scale)));groupEl.classList.add('lh-audit-group--load-opportunities');element.appendChild(groupEl);}
- const diagnosticAudits=category.auditRefs.filter(audit=>audit.group==='diagnostics'&&!Util.showAsPassed(audit.result)).sort((a,b)=>{const scoreA=a.result.scoreDisplayMode==='informative'?100:Number(a.result.score);const scoreB=b.result.scoreDisplayMode==='informative'?100:Number(b.result.score);return scoreA-scoreB;});if(diagnosticAudits.length){const groupEl=this.renderAuditGroup(groups['diagnostics']);diagnosticAudits.forEach(item=>groupEl.appendChild(this.renderAudit(item)));groupEl.classList.add('lh-audit-group--diagnostics');element.appendChild(groupEl);}
- const passedAudits=category.auditRefs.filter(audit=>(audit.group==='load-opportunities'||audit.group==='diagnostics')&&Util.showAsPassed(audit.result));if(!passedAudits.length)return element;const clumpOpts={auditRefs:passedAudits,groupDefinitions:groups,};const passedElem=this.renderClump('passed',clumpOpts);element.appendChild(passedElem);return element;}}
- if(typeof module!=='undefined'&&module.exports){module.exports=PerformanceCategoryRenderer;}else{self.PerformanceCategoryRenderer=PerformanceCategoryRenderer;};'use strict';const getUniqueSuffix=(()=>{let svgSuffix=0;return function(){return svgSuffix++;};})();class PwaCategoryRenderer extends CategoryRenderer{render(category,groupDefinitions={}){const categoryElem=this.dom.createElement('div','lh-category');this.createPermalinkSpan(categoryElem,category.id);categoryElem.appendChild(this.renderCategoryHeader(category,groupDefinitions));const auditRefs=category.auditRefs;const regularAuditRefs=auditRefs.filter(ref=>ref.result.scoreDisplayMode!=='manual');const auditsElem=this._renderAudits(regularAuditRefs,groupDefinitions);categoryElem.appendChild(auditsElem);const manualAuditRefs=auditRefs.filter(ref=>ref.result.scoreDisplayMode==='manual');const manualElem=this.renderClump('manual',{auditRefs:manualAuditRefs,description:category.manualDescription});categoryElem.appendChild(manualElem);return categoryElem;}
- renderScoreGauge(category,groupDefinitions){if(category.score===null){return super.renderScoreGauge(category,groupDefinitions);}
- const tmpl=this.dom.cloneTemplate('#tmpl-lh-gauge--pwa',this.templateContext);const wrapper=(this.dom.find('.lh-gauge--pwa__wrapper',tmpl));wrapper.href=`#${category.id}`;const svgRoot=tmpl.querySelector('svg');if(!svgRoot)throw new Error('no SVG element found in PWA score gauge template');PwaCategoryRenderer._makeSvgReferencesUnique(svgRoot);const allGroups=this._getGroupIds(category.auditRefs);const passingGroupIds=this._getPassingGroupIds(category.auditRefs);if(passingGroupIds.size===allGroups.size){wrapper.classList.add('lh-badged--all');}else{for(const passingGroupId of passingGroupIds){wrapper.classList.add(`lh-badged--${passingGroupId}`);}}
- this.dom.find('.lh-gauge__label',tmpl).textContent=category.title;wrapper.title=this._getGaugeTooltip(category.auditRefs,groupDefinitions);return tmpl;}
- _getGroupIds(auditRefs){const groupIds=auditRefs.map(ref=>ref.group).filter(g=>!!g);return new Set(groupIds);}
- _getPassingGroupIds(auditRefs){const uniqueGroupIds=this._getGroupIds(auditRefs);for(const auditRef of auditRefs){if(!Util.showAsPassed(auditRef.result)&&auditRef.group){uniqueGroupIds.delete(auditRef.group);}}
- return uniqueGroupIds;}
- _getGaugeTooltip(auditRefs,groupDefinitions){const groupIds=this._getGroupIds(auditRefs);const tips=[];for(const groupId of groupIds){const groupAuditRefs=auditRefs.filter(ref=>ref.group===groupId);const auditCount=groupAuditRefs.length;const passedCount=groupAuditRefs.filter(ref=>Util.showAsPassed(ref.result)).length;const title=groupDefinitions[groupId].title;tips.push(`${title}: ${passedCount}/${auditCount}`);}
- return tips.join(', ');}
- _renderAudits(auditRefs,groupDefinitions){const auditsElem=this.renderUnexpandableClump(auditRefs,groupDefinitions);const passsingGroupIds=this._getPassingGroupIds(auditRefs);for(const groupId of passsingGroupIds){const groupElem=this.dom.find(`.lh-audit-group--${groupId}`,auditsElem);groupElem.classList.add('lh-badged');}
- return auditsElem;}
- static _makeSvgReferencesUnique(svgRoot){const defsEl=svgRoot.querySelector('defs');if(!defsEl)return;const idSuffix=getUniqueSuffix();const elementsToUpdate=defsEl.querySelectorAll('[id]');for(const el of elementsToUpdate){const oldId=el.id;const newId=`${oldId}-${idSuffix}`;el.id=newId;const useEls=svgRoot.querySelectorAll(`use[href="#${oldId}"]`);for(const useEl of useEls){useEl.setAttribute('href',`#${newId}`);}
- const fillEls=svgRoot.querySelectorAll(`[fill="url(#${oldId})"]`);for(const fillEl of fillEls){fillEl.setAttribute('fill',`url(#${newId})`);}}}}
- if(typeof module!=='undefined'&&module.exports){module.exports=PwaCategoryRenderer;}else{self.PwaCategoryRenderer=PwaCategoryRenderer;};'use strict';class ReportRenderer{constructor(dom){this._dom=dom;this._templateContext=this._dom.document();}
- renderReport(result,container){const originalUIStrings=JSON.parse(JSON.stringify(Util.UIStrings));this._dom.setLighthouseChannel(result.configSettings.channel||'unknown');const report=Util.prepareReportResult(result);container.textContent='';container.appendChild(this._renderReport(report));Util.updateAllUIStrings(originalUIStrings);return container;}
- setTemplateContext(context){this._templateContext=context;}
- _renderReportTopbar(report){const el=this._dom.cloneTemplate('#tmpl-lh-topbar',this._templateContext);const metadataUrl=(this._dom.find('.lh-topbar__url',el));metadataUrl.href=metadataUrl.textContent=report.finalUrl;metadataUrl.title=report.finalUrl;return el;}
- _renderReportHeader(){const el=this._dom.cloneTemplate('#tmpl-lh-heading',this._templateContext);const domFragment=this._dom.cloneTemplate('#tmpl-lh-scores-wrapper',this._templateContext);const placeholder=this._dom.find('.lh-scores-wrapper-placeholder',el);(placeholder.parentNode).replaceChild(domFragment,placeholder);return el;}
- _renderReportFooter(report){const footer=this._dom.cloneTemplate('#tmpl-lh-footer',this._templateContext);const env=this._dom.find('.lh-env__items',footer);env.id='runtime-settings';const envValues=Util.getEnvironmentDisplayValues(report.configSettings||{});[{name:'URL',description:report.finalUrl},{name:'Fetch time',description:Util.formatDateTime(report.fetchTime)},...envValues,{name:'User agent (host)',description:report.userAgent},{name:'User agent (network)',description:report.environment&&report.environment.networkUserAgent},{name:'CPU/Memory Power',description:report.environment&&report.environment.benchmarkIndex.toFixed(0)},].forEach(runtime=>{if(!runtime.description)return;const item=this._dom.cloneTemplate('#tmpl-lh-env__items',env);this._dom.find('.lh-env__name',item).textContent=runtime.name;this._dom.find('.lh-env__description',item).textContent=runtime.description;env.appendChild(item);});this._dom.find('.lh-footer__version',footer).textContent=report.lighthouseVersion;return footer;}
- _renderReportWarnings(report){if(!report.runWarnings||report.runWarnings.length===0){return this._dom.createElement('div');}
- const container=this._dom.cloneTemplate('#tmpl-lh-warnings--toplevel',this._templateContext);const message=this._dom.find('.lh-warnings__msg',container);message.textContent=Util.UIStrings.toplevelWarningsMessage;const warnings=this._dom.find('ul',container);for(const warningString of report.runWarnings){const warning=warnings.appendChild(this._dom.createElement('li'));warning.textContent=warningString;}
- return container;}
- _renderScoreGauges(report,categoryRenderer,specificCategoryRenderers){const defaultGauges=[];const customGauges=[];const pluginGauges=[];for(const category of Object.values(report.categories)){const renderer=specificCategoryRenderers[category.id]||categoryRenderer;const categoryGauge=renderer.renderScoreGauge(category,report.categoryGroups||{});if(Util.isPluginCategory(category.id)){pluginGauges.push(categoryGauge);}else if(renderer.renderScoreGauge===categoryRenderer.renderScoreGauge){defaultGauges.push(categoryGauge);}else{customGauges.push(categoryGauge);}}
- return[...defaultGauges,...customGauges,...pluginGauges];}
- _renderReport(report){const detailsRenderer=new DetailsRenderer(this._dom);const categoryRenderer=new CategoryRenderer(this._dom,detailsRenderer);categoryRenderer.setTemplateContext(this._templateContext);const specificCategoryRenderers={performance:new PerformanceCategoryRenderer(this._dom,detailsRenderer),pwa:new PwaCategoryRenderer(this._dom,detailsRenderer),};Object.values(specificCategoryRenderers).forEach(renderer=>{renderer.setTemplateContext(this._templateContext);});const headerContainer=this._dom.createElement('div');headerContainer.appendChild(this._renderReportHeader());const reportContainer=this._dom.createElement('div','lh-container');const reportSection=this._dom.createElement('div','lh-report');reportSection.appendChild(this._renderReportWarnings(report));let scoreHeader;const isSoloCategory=Object.keys(report.categories).length===1;if(!isSoloCategory){scoreHeader=this._dom.createElement('div','lh-scores-header');}else{headerContainer.classList.add('lh-header--solo-category');}
- if(scoreHeader){const scoreScale=this._dom.cloneTemplate('#tmpl-lh-scorescale',this._templateContext);const scoresContainer=this._dom.find('.lh-scores-container',headerContainer);scoreHeader.append(...this._renderScoreGauges(report,categoryRenderer,specificCategoryRenderers));scoresContainer.appendChild(scoreHeader);scoresContainer.appendChild(scoreScale);const stickyHeader=this._dom.createElement('div','lh-sticky-header');stickyHeader.append(...this._renderScoreGauges(report,categoryRenderer,specificCategoryRenderers));reportContainer.appendChild(stickyHeader);}
- const categories=reportSection.appendChild(this._dom.createElement('div','lh-categories'));for(const category of Object.values(report.categories)){const renderer=specificCategoryRenderers[category.id]||categoryRenderer;const wrapper=renderer.dom.createChildOf(categories,'div','lh-category-wrapper');wrapper.appendChild(renderer.render(category,report.categoryGroups));}
- const reportFragment=this._dom.createFragment();const topbarDocumentFragment=this._renderReportTopbar(report);reportFragment.appendChild(topbarDocumentFragment);reportFragment.appendChild(reportContainer);reportContainer.appendChild(headerContainer);reportContainer.appendChild(reportSection);reportSection.appendChild(this._renderReportFooter(report));return reportFragment;}}
- ReportRenderer._UIStringsStash={};if(typeof module!=='undefined'&&module.exports){module.exports=ReportRenderer;}else{self.ReportRenderer=ReportRenderer;}
|