UNPKG

chrome-devtools-frontend

Version:
205 lines (181 loc) • 7.62 kB
// Copyright 2016 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 TextUtils from '../../models/text_utils/text_utils.js'; import * as Common from '../common/common.js'; import * as i18n from '../i18n/i18n.js'; import * as Platform from '../platform/platform.js'; import * as Root from '../root/root.js'; import type * as Protocol from '../../generated/protocol.js'; import {type CSSModel} from './CSSModel.js'; import {DeferredDOMNode} from './DOMModel.js'; import {type FrameAssociated} from './FrameAssociated.js'; import {type PageResourceLoadInitiator} from './PageResourceLoader.js'; import {ResourceTreeModel} from './ResourceTreeModel.js'; const UIStrings = { /** *@description Error message for when a CSS file can't be loaded */ couldNotFindTheOriginalStyle: 'Could not find the original style sheet.', /** *@description Error message to display when a source CSS file could not be retrieved. */ thereWasAnErrorRetrievingThe: 'There was an error retrieving the source styles.', }; const str_ = i18n.i18n.registerUIStrings('core/sdk/CSSStyleSheetHeader.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export class CSSStyleSheetHeader implements TextUtils.ContentProvider.ContentProvider, FrameAssociated { #cssModelInternal: CSSModel; id: Protocol.CSS.StyleSheetId; frameId: Protocol.Page.FrameId; sourceURL: Platform.DevToolsPath.UrlString; hasSourceURL: boolean; origin: Protocol.CSS.StyleSheetOrigin; title: string; disabled: boolean; isInline: boolean; isMutable: boolean; isConstructed: boolean; startLine: number; startColumn: number; endLine: number; endColumn: number; contentLength: number; ownerNode: DeferredDOMNode|undefined; sourceMapURL: Platform.DevToolsPath.UrlString|undefined; readonly loadingFailed: boolean; #originalContentProviderInternal: TextUtils.StaticContentProvider.StaticContentProvider|null; constructor(cssModel: CSSModel, payload: Protocol.CSS.CSSStyleSheetHeader) { this.#cssModelInternal = cssModel; this.id = payload.styleSheetId; this.frameId = payload.frameId; this.sourceURL = payload.sourceURL as Platform.DevToolsPath.UrlString; this.hasSourceURL = Boolean(payload.hasSourceURL); this.origin = payload.origin; this.title = payload.title; this.disabled = payload.disabled; this.isInline = payload.isInline; this.isMutable = payload.isMutable; this.isConstructed = payload.isConstructed; this.startLine = payload.startLine; this.startColumn = payload.startColumn; this.endLine = payload.endLine; this.endColumn = payload.endColumn; this.contentLength = payload.length; if (payload.ownerNode) { this.ownerNode = new DeferredDOMNode(cssModel.target(), payload.ownerNode); } this.sourceMapURL = payload.sourceMapURL as Platform.DevToolsPath.UrlString; this.loadingFailed = payload.loadingFailed ?? false; this.#originalContentProviderInternal = null; } originalContentProvider(): TextUtils.ContentProvider.ContentProvider { if (!this.#originalContentProviderInternal) { const lazyContent = (async(): Promise<TextUtils.ContentProvider.DeferredContent> => { const originalText = await this.#cssModelInternal.originalStyleSheetText(this); if (originalText === null) { return {content: null, error: i18nString(UIStrings.couldNotFindTheOriginalStyle), isEncoded: false}; } return {content: originalText, isEncoded: false}; }); this.#originalContentProviderInternal = new TextUtils.StaticContentProvider.StaticContentProvider(this.contentURL(), this.contentType(), lazyContent); } return this.#originalContentProviderInternal; } setSourceMapURL(sourceMapURL?: Platform.DevToolsPath.UrlString): void { this.sourceMapURL = sourceMapURL; } cssModel(): CSSModel { return this.#cssModelInternal; } isAnonymousInlineStyleSheet(): boolean { return !this.resourceURL() && !this.#cssModelInternal.sourceMapManager().sourceMapForClient(this); } isConstructedByNew(): boolean { return this.isConstructed && this.sourceURL.length === 0; } resourceURL(): Platform.DevToolsPath.UrlString { const url = this.isViaInspector() ? this.viaInspectorResourceURL() : this.sourceURL; if (!url && Root.Runtime.experiments.isEnabled(Root.Runtime.ExperimentName.STYLES_PANE_CSS_CHANGES)) { return this.dynamicStyleURL(); } return url; } private getFrameURLPath(): string { const model = this.#cssModelInternal.target().model(ResourceTreeModel); console.assert(Boolean(model)); if (!model) { return ''; } const frame = model.frameForId(this.frameId); if (!frame) { return ''; } console.assert(Boolean(frame)); const parsedURL = new Common.ParsedURL.ParsedURL(frame.url); let urlPath = parsedURL.host + parsedURL.folderPathComponents; if (!urlPath.endsWith('/')) { urlPath += '/'; } return urlPath; } private viaInspectorResourceURL(): Platform.DevToolsPath.UrlString { return `inspector://${this.getFrameURLPath()}inspector-stylesheet` as Platform.DevToolsPath.UrlString; } private dynamicStyleURL(): Platform.DevToolsPath.UrlString { return `stylesheet://${this.getFrameURLPath()}style#${this.id}` as Platform.DevToolsPath.UrlString; } lineNumberInSource(lineNumberInStyleSheet: number): number { return this.startLine + lineNumberInStyleSheet; } columnNumberInSource(lineNumberInStyleSheet: number, columnNumberInStyleSheet: number): number|undefined { return (lineNumberInStyleSheet ? 0 : this.startColumn) + columnNumberInStyleSheet; } /** * Checks whether the position is in this style sheet. Assumes that the * position's columnNumber is consistent with line endings. */ containsLocation(lineNumber: number, columnNumber: number): boolean { const afterStart = (lineNumber === this.startLine && columnNumber >= this.startColumn) || lineNumber > this.startLine; const beforeEnd = lineNumber < this.endLine || (lineNumber === this.endLine && columnNumber <= this.endColumn); return afterStart && beforeEnd; } contentURL(): Platform.DevToolsPath.UrlString { return this.resourceURL(); } contentType(): Common.ResourceType.ResourceType { return Common.ResourceType.resourceTypes.Stylesheet; } async requestContent(): Promise<TextUtils.ContentProvider.DeferredContent> { try { const cssText = await this.#cssModelInternal.getStyleSheetText(this.id); return {content: (cssText as string), isEncoded: false}; } catch (err) { return { content: null, error: i18nString(UIStrings.thereWasAnErrorRetrievingThe), isEncoded: false, }; } } async searchInContent(query: string, caseSensitive: boolean, isRegex: boolean): Promise<TextUtils.ContentProvider.SearchMatch[]> { const requestedContent = await this.requestContent(); if (requestedContent.content === null) { return []; } return TextUtils.TextUtils.performSearchInContent(requestedContent.content, query, caseSensitive, isRegex); } isViaInspector(): boolean { return this.origin === 'inspector'; } createPageResourceLoadInitiator(): PageResourceLoadInitiator { return { target: null, frameId: this.frameId, initiatorUrl: this.hasSourceURL ? Platform.DevToolsPath.EmptyUrlString : this.sourceURL, }; } }