chrome-devtools-frontend
Version:
Chrome DevTools UI
104 lines (87 loc) • 3.13 kB
text/typescript
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Platform from '../../../core/platform/platform.js';
import * as Lit from '../../lit/lit.js';
import * as RenderCoordinator from '../render_coordinator/render_coordinator.js';
import linkifierImplStylesRaw from './linkifierImpl.css.js';
import * as LinkifierUtils from './LinkifierUtils.js';
// TODO(crbug.com/391381439): Fully migrate off of constructed style sheets.
const linkifierImplStyles = new CSSStyleSheet();
linkifierImplStyles.replaceSync(linkifierImplStylesRaw.cssContent);
const {html} = Lit;
export interface LinkifierData {
url: Platform.DevToolsPath.UrlString;
lineNumber?: number;
columnNumber?: number;
linkText?: string;
title?: string;
}
export class LinkifierClick extends Event {
static readonly eventName = 'linkifieractivated';
constructor(public data: LinkifierData) {
super(LinkifierClick.eventName, {
bubbles: true,
composed: true,
});
this.data = data;
}
}
export class Linkifier extends HTMLElement {
readonly #shadow = this.attachShadow({mode: 'open'});
#url: Platform.DevToolsPath.UrlString = Platform.DevToolsPath.EmptyUrlString;
#lineNumber?: number;
#columnNumber?: number;
#linkText?: string;
#title?: string;
set data(data: LinkifierData) {
this.#url = data.url;
this.#lineNumber = data.lineNumber;
this.#columnNumber = data.columnNumber;
this.#linkText = data.linkText;
this.#title = data.title;
if (!this.#url) {
throw new Error('Cannot construct a Linkifier without providing a valid string URL.');
}
void this.#render();
}
override cloneNode(deep?: boolean): Node {
const node = super.cloneNode(deep) as Linkifier;
node.data = {
url: this.#url,
lineNumber: this.#lineNumber,
columnNumber: this.#columnNumber,
linkText: this.#linkText,
title: this.#title
};
return node;
}
connectedCallback(): void {
this.#shadow.adoptedStyleSheets = [linkifierImplStyles];
}
#onLinkActivation(event: Event): void {
event.preventDefault();
const linkifierClickEvent = new LinkifierClick({
url: this.#url,
lineNumber: this.#lineNumber,
columnNumber: this.#columnNumber,
});
this.dispatchEvent(linkifierClickEvent);
}
async #render(): Promise<void> {
const linkText = this.#linkText ?? LinkifierUtils.linkText(this.#url, this.#lineNumber);
// Disabled until https://crbug.com/1079231 is fixed.
await RenderCoordinator.write(() => {
// clang-format off
// eslint-disable-next-line rulesdir/no-a-tags-in-lit
Lit.render(html`<a class="link" href=${this.#url} =${this.#onLinkActivation} title=${Lit.Directives.ifDefined(this.#title) as string}><slot>${linkText}</slot></a>`, this.#shadow, { host: this});
// clang-format on
});
}
}
customElements.define('devtools-linkifier', Linkifier);
declare global {
interface HTMLElementTagNameMap {
'devtools-linkifier': Linkifier;
}
}