chrome-devtools-frontend
Version:
Chrome DevTools UI
177 lines (161 loc) • 7.1 kB
text/typescript
// Copyright (c) 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 '../../ui/legacy/legacy.js';
import type * as Common from '../../core/common/common.js';
import * as i18n from '../../core/i18n/i18n.js';
import * as Platform from '../../core/platform/platform.js';
import * as SDK from '../../core/sdk/sdk.js';
import type * as TextUtils from '../../models/text_utils/text_utils.js';
import * as UI from '../../ui/legacy/legacy.js';
import {html, render} from '../../ui/lit/lit.js';
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
import {DeveloperResourcesListView} from './DeveloperResourcesListView.js';
import developerResourcesViewStyles from './developerResourcesView.css.js';
const {widgetConfig} = UI.Widget;
const {bindToSetting} = UI.SettingsUI;
const UIStrings = {
/**
*@description Placeholder for a search field in a toolbar
*/
filterByText: 'Filter by URL and error',
/**
* @description Tooltip for a checkbox in the toolbar of the developer resources view. The
* inspected target is the webpage that DevTools is debugging/inspecting/attached to.
*/
loadHttpsDeveloperResources:
'Load `HTTP(S)` developer resources through the website you inspect, not through DevTools',
/**
* @description Text for a checkbox in the toolbar of the developer resources view. The target is
* the webpage that DevTools is debugging/inspecting/attached to. This setting makes it so
* developer resources are requested from the webpage itself, and not from the DevTools
* application.
*/
enableLoadingThroughTarget: 'Load through website',
/**
*@description Text for resources load status
*@example {1} PH1
*@example {1} PH2
*/
resourcesCurrentlyLoading: '{PH1} resources, {PH2} currently loading',
/**
* @description Status text that appears to tell the developer how many resources were loaded in
* total. Resources are files related to the webpage.
*/
resources: '{n, plural, =1 {# resource} other {# resources}}',
} as const;
const str_ = i18n.i18n.registerUIStrings('panels/developer_resources/DeveloperResourcesView.ts', UIStrings);
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
export class DeveloperResourcesRevealer implements Common.Revealer.Revealer<SDK.PageResourceLoader.ResourceKey> {
async reveal(resourceInitiatorKey: SDK.PageResourceLoader.ResourceKey): Promise<void> {
const loader = SDK.PageResourceLoader.PageResourceLoader.instance();
const resource = loader.getResourcesLoaded().get(resourceInitiatorKey.key);
if (resource) {
await UI.ViewManager.ViewManager.instance().showView('developer-resources');
const developerResourcesView =
await UI.ViewManager.ViewManager.instance().view('developer-resources').widget() as DeveloperResourcesView;
return await developerResourcesView.select(resource);
}
}
}
interface ViewInput {
onFilterChanged: (e: CustomEvent<string>) => void;
items: Iterable<SDK.PageResourceLoader.PageResource>;
selectedItem: SDK.PageResourceLoader.PageResource|null;
onSelect: (resource: SDK.PageResourceLoader.PageResource|null) => void;
filters: TextUtils.TextUtils.ParsedFilter[];
numResources: number;
numLoading: number;
}
type View = (input: ViewInput, output: object, target: HTMLElement) => void;
export const DEFAULT_VIEW: View = (input, _output, target) => {
// clang-format off
render(html`
<style>
${developerResourcesViewStyles}
</style>
<div class="vbox flex-auto" jslog=${VisualLogging.panel('developer-resources').track({resize: true})}>
<div class="developer-resource-view-toolbar-container" jslog=${VisualLogging.toolbar()}
role="toolbar">
<devtools-toolbar class="developer-resource-view-toolbar" role="presentation">
<devtools-toolbar-input type="filter" placeholder=${i18nString(UIStrings.filterByText)}
@change=${input.onFilterChanged} style="flex-grow:1">
</devtools-toolbar-input>
<devtools-checkbox
title=${i18nString(UIStrings.loadHttpsDeveloperResources)}
${bindToSetting(SDK.PageResourceLoader.getLoadThroughTargetSetting())}>
${i18nString(UIStrings.enableLoadingThroughTarget)}
</devtools-checkbox>
</devtools-toolbar>
</div>
<div class="developer-resource-view-results">
<devtools-widget
.widgetConfig=${widgetConfig(DeveloperResourcesListView, {
items: input.items,
selectedItem: input.selectedItem,
onSelect: input.onSelect,
filters: input.filters
})}>
</devtools-widget>
</div>
<div class="developer-resource-view-toolbar-summary">
<div class="developer-resource-view-message">
${input.numLoading > 0 ?
i18nString(UIStrings.resourcesCurrentlyLoading, {PH1: input.numResources, PH2: input.numLoading}) :
i18nString(UIStrings.resources, {n: input.numResources})}
</div>
</div>
</div>`, target, {host: input});
// clang-format on
};
export class DeveloperResourcesView extends UI.ThrottledWidget.ThrottledWidget {
readonly #loader: SDK.PageResourceLoader.PageResourceLoader;
readonly #view: View;
#selectedItem: SDK.PageResourceLoader.PageResource|null = null;
#filters: TextUtils.TextUtils.ParsedFilter[] = [];
constructor(view: View = DEFAULT_VIEW) {
super(true);
this.#view = view;
this.#loader = SDK.PageResourceLoader.PageResourceLoader.instance();
this.#loader.addEventListener(SDK.PageResourceLoader.Events.UPDATE, this.update, this);
this.update();
}
override async doUpdate(): Promise<void> {
const {loading, resources} = this.#loader.getScopedNumberOfResources();
const input = {
onFilterChanged: (e: CustomEvent<string>) => {
this.onFilterChanged(e.detail);
},
items: this.#loader.getResourcesLoaded().values(),
selectedItem: this.#selectedItem,
onSelect: (item: SDK.PageResourceLoader.PageResource|null) => {
this.#selectedItem = item;
},
filters: this.#filters,
numResources: resources,
numLoading: loading,
};
const output = {};
this.#view(input, output, this.contentElement);
}
async select(resource: SDK.PageResourceLoader.PageResource): Promise<void> {
await this.lastUpdatePromise;
this.#selectedItem = resource;
this.update();
}
async selectedItem(): Promise<SDK.PageResourceLoader.PageResource|null> {
await this.lastUpdatePromise;
return this.#selectedItem;
}
private onFilterChanged(text: string): void {
const textFilterRegExp = text ? Platform.StringUtilities.createPlainTextSearchRegex(text, 'i') : null;
if (textFilterRegExp) {
this.#filters = [
{key: 'url,error-message', regex: textFilterRegExp, negative: false},
];
} else {
this.#filters = [];
}
this.update();
}
}