UNPKG

chrome-devtools-frontend

Version:
161 lines (137 loc) 4.03 kB
// Copyright 2012 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. import type * as Extensions from '../../models/extensions/extensions.js'; import * as UI from '../../ui/legacy/legacy.js'; import * as Lit from '../../ui/lit/lit.js'; import type {ExtensionServer} from './ExtensionServer.js'; const {render, html, Directives: {ref}} = Lit; interface ViewInput { src: string; className: string; onLoad: () => void; } interface ViewOutput { iframe?: HTMLIFrameElement; } const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement): void => { // clang-format off render(html`<iframe ${ref(element => {output.iframe = element as HTMLIFrameElement; })} src=${input.src} allow="language-model; summarizer; translator; language-detector; writer; rewriter; proofreader; clipboard-write; autoplay" class=${input.className} @load=${input.onLoad}></iframe>`, target); // clang-format on }; export class ExtensionView extends UI.Widget.Widget { #server: ExtensionServer; #id: string; #src: string; #className: string; #iframe?: HTMLIFrameElement; #frameIndex?: number; #view: typeof DEFAULT_VIEW; constructor(server: ExtensionServer, id: string, src: string, className: string, view = DEFAULT_VIEW) { super(); this.#view = view; this.#server = server; this.#src = src; this.#className = className; this.#id = id; this.setHideOnDetach(); // Override void this.performUpdate(); } override performUpdate(): Promise<void>|void { const output: ViewOutput = {}; this.#view( { src: this.#src, className: this.#className, onLoad: this.onLoad.bind(this), }, output, this.element); if (output.iframe) { this.#iframe = output.iframe; } } override wasShown(): void { super.wasShown(); if (typeof this.#frameIndex === 'number') { this.#server.notifyViewShown(this.#id, this.#frameIndex); } } override willHide(): void { super.willHide(); if (typeof this.#frameIndex === 'number') { this.#server.notifyViewHidden(this.#id); } } private onLoad(): void { if (!this.#iframe) { return; } const frames = window.frames; this.#frameIndex = Array.prototype.indexOf.call(frames, this.#iframe.contentWindow); if (this.isShowing()) { this.#server.notifyViewShown(this.#id, this.#frameIndex); } } } export class ExtensionNotifierView extends UI.Widget.VBox { private readonly server: ExtensionServer; private readonly id: string; constructor(server: ExtensionServer, id: string) { super(); this.server = server; this.id = id; } override wasShown(): void { super.wasShown(); this.server.notifyViewShown(this.id); } override willHide(): void { super.willHide(); this.server.notifyViewHidden(this.id); } } export class ExtensionIframe { #descriptor: Extensions.RecorderPluginManager.ViewDescriptor; #iframe: HTMLIFrameElement; #isShowing = false; #isLoaded = false; constructor(descriptor: Extensions.RecorderPluginManager.ViewDescriptor) { this.#descriptor = descriptor; // We are creating a single iframe here. /* eslint-disable-next-line @devtools/no-imperative-dom-api */ this.#iframe = document.createElement('iframe'); this.#iframe.src = descriptor.pagePath; this.#iframe.onload = this.#onIframeLoad; } #onIframeLoad = (): void => { this.#isLoaded = true; if (this.#isShowing) { this.#descriptor.onShown(); } }; show(): void { if (this.#isShowing) { return; } this.#isShowing = true; if (this.#isLoaded) { this.#descriptor.onShown(); } } hide(): void { if (!this.#isShowing) { return; } this.#isShowing = false; this.#isLoaded = false; this.#descriptor.onHidden(); } frame(): HTMLIFrameElement { return this.#iframe; } }