| // Copyright 2022 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| import * as i18n from '../../core/i18n/i18n.js'; |
| import type * as Platform from '../../core/platform/platform.js'; |
| import type * as SDK from '../../core/sdk/sdk.js'; |
| import {createIcon} from '../../ui/kit/kit.js'; |
| |
| import {ApplicationPanelTreeElement, ExpandableApplicationPanelTreeElement} from './ApplicationPanelTreeElement.js'; |
| import * as PreloadingHelper from './preloading/helper/helper.js'; |
| import {PreloadingAttemptView, PreloadingRuleSetView, PreloadingSummaryView} from './preloading/PreloadingView.js'; |
| import type {ResourcesPanel} from './ResourcesPanel.js'; |
| |
| const UIStrings = { |
| /** |
| * @description Text in Application Panel Sidebar of the Application panel |
| */ |
| speculativeLoads: 'Speculative loads', |
| /** |
| * @description Text in Application Panel Sidebar of the Application panel |
| */ |
| rules: 'Rules', |
| /** |
| * @description Text in Application Panel Sidebar of the Application panel |
| */ |
| speculations: 'Speculations', |
| } as const; |
| const str_ = i18n.i18n.registerUIStrings('panels/application/PreloadingTreeElement.ts', UIStrings); |
| const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); |
| |
| class PreloadingTreeElementBase<View extends PreloadingRuleSetView|PreloadingAttemptView> extends |
| ApplicationPanelTreeElement { |
| #model?: SDK.PreloadingModel.PreloadingModel; |
| #viewConstructor: {new(model: SDK.PreloadingModel.PreloadingModel): View}; |
| protected view?: View; |
| #path: Platform.DevToolsPath.UrlString; |
| #selected: boolean; |
| |
| constructor( |
| panel: ResourcesPanel, viewConstructor: {new(model: SDK.PreloadingModel.PreloadingModel): View}, |
| path: Platform.DevToolsPath.UrlString, title: string) { |
| super(panel, title, false, 'speculative-loads'); |
| |
| this.#viewConstructor = viewConstructor; |
| this.#path = path; |
| |
| const icon = createIcon('speculative-loads'); |
| this.setLeadingIcons([icon]); |
| this.#selected = false; |
| |
| // TODO(https://crbug.com/1384419): Set link |
| } |
| |
| override get itemURL(): Platform.DevToolsPath.UrlString { |
| return this.#path; |
| } |
| |
| initialize(model: SDK.PreloadingModel.PreloadingModel): void { |
| this.#model = model; |
| |
| // Show the view if the model was initialized after selection. |
| if (this.#selected && !this.view) { |
| this.onselect(false); |
| } |
| } |
| |
| override onselect(selectedByUser?: boolean): boolean { |
| super.onselect(selectedByUser); |
| this.#selected = true; |
| |
| if (!this.#model) { |
| return false; |
| } |
| |
| if (!this.view) { |
| this.view = new this.#viewConstructor(this.#model); |
| } |
| |
| this.showView(this.view); |
| |
| return false; |
| } |
| } |
| |
| export class PreloadingSummaryTreeElement extends ExpandableApplicationPanelTreeElement { |
| #model?: SDK.PreloadingModel.PreloadingModel; |
| #view?: PreloadingSummaryView; |
| #selected: boolean; |
| |
| #ruleSet: PreloadingRuleSetTreeElement|null = null; |
| #attempt: PreloadingAttemptTreeElement|null = null; |
| |
| constructor(panel: ResourcesPanel) { |
| super(panel, i18nString(UIStrings.speculativeLoads), '', '', 'preloading'); |
| |
| const icon = createIcon('speculative-loads'); |
| this.setLeadingIcons([icon]); |
| this.#selected = false; |
| |
| // TODO(https://crbug.com/1384419): Set link |
| } |
| |
| // Note that |
| // |
| // - TreeElement.ensureSelection assumes TreeElement.treeOutline initialized. |
| // - TreeElement.treeOutline is propagated in TreeElement.appendChild. |
| // |
| // So, `this.constructChildren` should be called just after `parent.appendChild(this)` |
| // to enrich children with TreeElement.selectionElementInternal correctly. |
| constructChildren(panel: ResourcesPanel): void { |
| this.#ruleSet = new PreloadingRuleSetTreeElement(panel); |
| this.#attempt = new PreloadingAttemptTreeElement(panel); |
| this.appendChild(this.#ruleSet); |
| this.appendChild(this.#attempt); |
| } |
| |
| initialize(model: SDK.PreloadingModel.PreloadingModel): void { |
| if (this.#ruleSet === null || this.#attempt === null) { |
| throw new Error('unreachable'); |
| } |
| |
| this.#model = model; |
| this.#ruleSet.initialize(model); |
| this.#attempt.initialize(model); |
| |
| // Show the view if the model was initialized after selection. |
| // However, if the user last viewed this page and clicked into Rules or |
| // Speculations, we ensure that we instead show those pages. |
| if (this.#attempt.selected) { |
| const filter = new PreloadingHelper.PreloadingForward.AttemptViewWithFilter(null); |
| this.expandAndRevealAttempts(filter); |
| } else if (this.#ruleSet.selected) { |
| const filter = new PreloadingHelper.PreloadingForward.RuleSetView(null); |
| this.expandAndRevealRuleSet(filter); |
| } else if (this.#selected && !this.#view) { |
| this.onselect(false); |
| } |
| } |
| |
| override onselect(selectedByUser?: boolean): boolean { |
| super.onselect(selectedByUser); |
| this.#selected = true; |
| |
| if (!this.#model) { |
| return false; |
| } |
| |
| if (!this.#view) { |
| this.#view = new PreloadingSummaryView(this.#model); |
| } |
| |
| this.showView(this.#view); |
| |
| return false; |
| } |
| |
| expandAndRevealRuleSet(revealInfo: PreloadingHelper.PreloadingForward.RuleSetView): void { |
| if (this.#ruleSet === null) { |
| throw new Error('unreachable'); |
| } |
| |
| this.expand(); |
| this.#ruleSet.revealRuleSet(revealInfo); |
| } |
| |
| expandAndRevealAttempts(filter: PreloadingHelper.PreloadingForward.AttemptViewWithFilter): void { |
| if (this.#attempt === null) { |
| throw new Error('unreachable'); |
| } |
| |
| this.expand(); |
| this.#attempt.revealAttempts(filter); |
| } |
| } |
| |
| export class PreloadingRuleSetTreeElement extends PreloadingTreeElementBase<PreloadingRuleSetView> { |
| constructor(panel: ResourcesPanel) { |
| super( |
| panel, PreloadingRuleSetView, 'preloading://rule-set' as Platform.DevToolsPath.UrlString, |
| i18nString(UIStrings.rules)); |
| } |
| |
| revealRuleSet(revealInfo: PreloadingHelper.PreloadingForward.RuleSetView): void { |
| this.select(); |
| |
| if (this.view === undefined) { |
| return; |
| } |
| |
| this.view?.revealRuleSet(revealInfo); |
| } |
| } |
| |
| class PreloadingAttemptTreeElement extends PreloadingTreeElementBase<PreloadingAttemptView> { |
| constructor(panel: ResourcesPanel) { |
| super( |
| panel, PreloadingAttemptView, 'preloading://attempt' as Platform.DevToolsPath.UrlString, |
| i18nString(UIStrings.speculations)); |
| } |
| |
| revealAttempts(filter: PreloadingHelper.PreloadingForward.AttemptViewWithFilter): void { |
| this.select(); |
| this.view?.setFilter(filter); |
| } |
| } |