| /** Root element for all codesize.skia.org pages. */ |
| |
| import { html, TemplateResult } from 'lit-html'; |
| |
| import { define } from '../../../elements-sk/modules/define'; |
| import { SpinnerSk } from '../../../elements-sk/modules/spinner-sk/spinner-sk'; |
| import { errorMessage } from '../../../elements-sk/modules/errorMessage'; |
| import { ElementSk } from '../../../infra-sk/modules/ElementSk'; |
| |
| import '../../../infra-sk/modules/app-sk'; |
| import '../../../infra-sk/modules/theme-chooser-sk'; |
| import '../../../elements-sk/modules/error-toast-sk'; |
| import '../../../elements-sk/modules/spinner-sk'; |
| import { END_BUSY_EVENT } from './events'; |
| |
| /** Moves the elements in a NodeList or HTMLCollection as children of another element. */ |
| function move(from: HTMLCollection | NodeList, to: HTMLElement) { |
| Array.prototype.slice.call(from).forEach((ele) => to.appendChild(ele)); |
| } |
| |
| export class CodesizeScaffoldSk extends ElementSk { |
| private static template = (): TemplateResult => html` |
| <app-sk> |
| <header> |
| <h1>Skia Code Size</h1> |
| <spinner-sk></spinner-sk> |
| <div class="spacer"></div> |
| <theme-chooser-sk></theme-chooser-sk> |
| </header> |
| |
| <aside> |
| <ul> |
| <li><a href="/">Home</a></li> |
| </ul> |
| <ul> |
| <li><a href="https://chrome-supersize.firebaseapp.com/" |
| target="_blank" rel="noopener noreferrer" |
| title="View Chrome's codesize tool (called Super Size Tiger View) which has |
| input data from Chrome's apk for Android systems." |
| >Chrome's Tool</a></li> |
| </ul> |
| </aside> |
| |
| <main></main> |
| |
| <error-toast-sk></error-toast-sk> |
| </app-sk> |
| `; |
| |
| private main: HTMLElement | null = null; |
| |
| private busyTaskCount = 0; |
| |
| private spinner: SpinnerSk | null = null; |
| |
| constructor() { |
| super(CodesizeScaffoldSk.template); |
| } |
| |
| connectedCallback(): void { |
| super.connectedCallback(); |
| // Don't call more than once. |
| if (this.main) { |
| return; |
| } |
| |
| // We aren't using shadow dom so we need to manually move the children of codesize-scaffold-sk |
| // to be children of 'main'. We have to do this for the existing elements and for all future |
| // mutations. |
| |
| // Create a temporary holding spot for the elements we're moving. |
| const div = document.createElement('div'); |
| move(this.children, div); |
| |
| // Now that we've moved all the old children out of the way we can render the template. |
| this._render(); |
| |
| // Move the old children back under main. |
| this.main = this.querySelector('main'); |
| move(div.children, this.main!); |
| |
| // Move all future children under main also. |
| const observer = new MutationObserver((mutList) => { |
| mutList.forEach((mut) => { |
| move(mut.addedNodes, this.main!); |
| }); |
| }); |
| observer.observe(this, { childList: true }); |
| |
| this.spinner = this.querySelector<SpinnerSk>('spinner-sk'); |
| |
| // Any unhandled errors will be reported in the UI via an error toast. |
| window.addEventListener('error', this.onUnhandledError); |
| } |
| |
| disconnectedCallback(): void { |
| super.disconnectedCallback(); |
| window.removeEventListener('error', this.onUnhandledError); |
| } |
| |
| private onUnhandledError(e: ErrorEvent): void { |
| errorMessage(e.error.message); |
| } |
| |
| /** |
| * Shows a loading indicator while awaiting the given promise and returns its fulfilled value. If |
| * the promise is rejected, the rejection reason will be displayed in the UI as an error toast. |
| * |
| * This function can be called multiple times concurrently. |
| */ |
| static waitFor<T>(promise: Promise<T>): Promise<T> { |
| const scaffold = document.querySelector<CodesizeScaffoldSk>('codesize-scaffold-sk')!; |
| return scaffold.waitFor(promise); |
| } |
| |
| private async waitFor<T>(promise: Promise<T>): Promise<T> { |
| this.busyTaskCount++; |
| this.spinner!.active = true; |
| try { |
| return await promise; |
| } catch (e) { |
| await errorMessage(e as Error); |
| throw e; |
| } finally { |
| this.busyTaskCount--; |
| if (this.busyTaskCount === 0) { |
| this.spinner!.active = false; |
| // Puppeteer tests can wait for this event before taking screenshots to ensure that the |
| // page's contents are fully loaded. |
| this.dispatchEvent(new CustomEvent(END_BUSY_EVENT, { bubbles: true })); |
| } |
| } |
| } |
| } |
| |
| define('codesize-scaffold-sk', CodesizeScaffoldSk); |