UNPKG

chrome-devtools-frontend

Version:
291 lines (259 loc) • 12 kB
// Copyright 2015 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. /* eslint-disable rulesdir/no_underscored_properties */ import * as Common from '../common/common.js'; import * as i18n from '../i18n/i18n.js'; import * as Platform from '../platform/platform.js'; import * as SDK from '../sdk/sdk.js'; import * as UI from '../ui/ui.js'; export const UIStrings = { /** *@description Title of toolbar item in console context selector of the console panel */ javascriptContextNotSelected: 'JavaScript context: Not selected', /** *@description Text in Console Context Selector of the Console panel */ extension: 'Extension', /** *@description Text in Console Context Selector of the Console panel *@example {top} PH1 */ javascriptContextS: 'JavaScript context: {PH1}', }; const str_ = i18n.i18n.registerUIStrings('console/ConsoleContextSelector.ts', UIStrings); const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_); export class ConsoleContextSelector implements SDK.SDKModel.SDKModelObserver<SDK.RuntimeModel.RuntimeModel>, UI.SoftDropDown.Delegate<SDK.RuntimeModel.ExecutionContext> { _items: UI.ListModel.ListModel<SDK.RuntimeModel.ExecutionContext>; _dropDown: UI.SoftDropDown.SoftDropDown<SDK.RuntimeModel.ExecutionContext>; _toolbarItem: UI.Toolbar.ToolbarItem; constructor() { this._items = new UI.ListModel.ListModel(); this._dropDown = new UI.SoftDropDown.SoftDropDown(this._items, this); this._dropDown.setRowHeight(36); this._toolbarItem = new UI.Toolbar.ToolbarItem(this._dropDown.element); this._toolbarItem.setEnabled(false); this._toolbarItem.setTitle(i18nString(UIStrings.javascriptContextNotSelected)); this._items.addEventListener( UI.ListModel.Events.ItemsReplaced, () => this._toolbarItem.setEnabled(Boolean(this._items.length))); this._toolbarItem.element.classList.add('toolbar-has-dropdown'); SDK.SDKModel.TargetManager.instance().addModelListener( SDK.RuntimeModel.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextCreated, this._onExecutionContextCreated, this); SDK.SDKModel.TargetManager.instance().addModelListener( SDK.RuntimeModel.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextChanged, this._onExecutionContextChanged, this); SDK.SDKModel.TargetManager.instance().addModelListener( SDK.RuntimeModel.RuntimeModel, SDK.RuntimeModel.Events.ExecutionContextDestroyed, this._onExecutionContextDestroyed, this); SDK.SDKModel.TargetManager.instance().addModelListener( SDK.ResourceTreeModel.ResourceTreeModel, SDK.ResourceTreeModel.Events.FrameNavigated, this._frameNavigated, this); UI.Context.Context.instance().addFlavorChangeListener( SDK.RuntimeModel.ExecutionContext, this._executionContextChangedExternally, this); UI.Context.Context.instance().addFlavorChangeListener( SDK.DebuggerModel.CallFrame, this._callFrameSelectedInUI, this); SDK.SDKModel.TargetManager.instance().observeModels(SDK.RuntimeModel.RuntimeModel, this); SDK.SDKModel.TargetManager.instance().addModelListener( SDK.DebuggerModel.DebuggerModel, SDK.DebuggerModel.Events.CallFrameSelected, this._callFrameSelectedInModel, this); } toolbarItem(): UI.Toolbar.ToolbarItem { return this._toolbarItem; } highlightedItemChanged( from: SDK.RuntimeModel.ExecutionContext|null, to: SDK.RuntimeModel.ExecutionContext|null, fromElement: Element|null, toElement: Element|null): void { SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight(); if (to && to.frameId) { const frame = SDK.FrameManager.FrameManager.instance().getFrame(to.frameId); if (frame && !frame.isTopFrame()) { frame.highlight(); } } if (fromElement) { fromElement.classList.remove('highlighted'); } if (toElement) { toElement.classList.add('highlighted'); } } titleFor(executionContext: SDK.RuntimeModel.ExecutionContext): string { const target = executionContext.target(); const maybeLabel = executionContext.label(); let label: string = maybeLabel ? target.decorateLabel(maybeLabel) : ''; if (executionContext.frameId) { const resourceTreeModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel); const frame = resourceTreeModel && resourceTreeModel.frameForId(executionContext.frameId); if (frame) { label = label || frame.displayName(); } } label = label || executionContext.origin; return label; } _depthFor(executionContext: SDK.RuntimeModel.ExecutionContext): number { let target = executionContext.target(); let depth = 0; if (!executionContext.isDefault) { depth++; } if (executionContext.frameId) { let frame = SDK.FrameManager.FrameManager.instance().getFrame(executionContext.frameId); while (frame) { frame = frame.parentFrame(); if (frame) { depth++; target = frame.resourceTreeModel().target(); } } } let targetDepth = 0; let parentTarget = target.parentTarget(); // Special casing service workers to be top-level. while (parentTarget && target.type() !== SDK.SDKModel.Type.ServiceWorker) { targetDepth++; target = parentTarget; parentTarget = target.parentTarget(); } depth += targetDepth; return depth; } _executionContextCreated(executionContext: SDK.RuntimeModel.ExecutionContext): void { this._items.insertWithComparator(executionContext, executionContext.runtimeModel.executionContextComparator()); if (executionContext === UI.Context.Context.instance().flavor(SDK.RuntimeModel.ExecutionContext)) { this._dropDown.selectItem(executionContext); } } _onExecutionContextCreated(event: Common.EventTarget.EventTargetEvent): void { const executionContext = (event.data as SDK.RuntimeModel.ExecutionContext); this._executionContextCreated(executionContext); } _onExecutionContextChanged(event: Common.EventTarget.EventTargetEvent): void { const executionContext = (event.data as SDK.RuntimeModel.ExecutionContext); if (this._items.indexOf(executionContext) === -1) { return; } this._executionContextDestroyed(executionContext); this._executionContextCreated(executionContext); } _executionContextDestroyed(executionContext: SDK.RuntimeModel.ExecutionContext): void { const index = this._items.indexOf(executionContext); if (index === -1) { return; } this._items.remove(index); } _onExecutionContextDestroyed(event: Common.EventTarget.EventTargetEvent): void { const executionContext = (event.data as SDK.RuntimeModel.ExecutionContext); this._executionContextDestroyed(executionContext); } _executionContextChangedExternally(event: Common.EventTarget.EventTargetEvent): void { const executionContext = (event.data as SDK.RuntimeModel.ExecutionContext | null); this._dropDown.selectItem(executionContext); } _isTopContext(executionContext: SDK.RuntimeModel.ExecutionContext|null): boolean { if (!executionContext || !executionContext.isDefault) { return false; } const resourceTreeModel = executionContext.target().model(SDK.ResourceTreeModel.ResourceTreeModel); const frame = executionContext.frameId && resourceTreeModel && resourceTreeModel.frameForId(executionContext.frameId); if (!frame) { return false; } return frame.isTopFrame(); } _hasTopContext(): boolean { return this._items.some(executionContext => this._isTopContext(executionContext)); } modelAdded(runtimeModel: SDK.RuntimeModel.RuntimeModel): void { runtimeModel.executionContexts().forEach(this._executionContextCreated, this); } modelRemoved(runtimeModel: SDK.RuntimeModel.RuntimeModel): void { for (let i = this._items.length - 1; i >= 0; i--) { if (this._items.at(i).runtimeModel === runtimeModel) { this._executionContextDestroyed(this._items.at(i)); } } } createElementForItem(item: SDK.RuntimeModel.ExecutionContext): Element { const element = document.createElement('div'); const shadowRoot = UI.Utils.createShadowRootWithCoreStyles( element, {cssFile: 'console/consoleContextSelector.css', enableLegacyPatching: true, delegatesFocus: undefined}); const title = shadowRoot.createChild('div', 'title'); UI.UIUtils.createTextChild(title, Platform.StringUtilities.trimEndWithMaxLength(this.titleFor(item), 100)); const subTitle = shadowRoot.createChild('div', 'subtitle'); UI.UIUtils.createTextChild(subTitle, this._subtitleFor(item)); element.style.paddingLeft = (8 + this._depthFor(item) * 15) + 'px'; return element; } _subtitleFor(executionContext: SDK.RuntimeModel.ExecutionContext): string { const target = executionContext.target(); let frame: SDK.ResourceTreeModel.ResourceTreeFrame|null = null; if (executionContext.frameId) { const resourceTreeModel = target.model(SDK.ResourceTreeModel.ResourceTreeModel); frame = resourceTreeModel && resourceTreeModel.frameForId(executionContext.frameId); } if (executionContext.origin.startsWith('chrome-extension://')) { return i18nString(UIStrings.extension); } const sameTargetParentFrame = frame && frame.sameTargetParentFrame(); // TODO(crbug.com/1159332): Understand why condition involves the sameTargetParentFrame. if (!frame || !sameTargetParentFrame || sameTargetParentFrame.securityOrigin !== executionContext.origin) { const url = Common.ParsedURL.ParsedURL.fromString(executionContext.origin); if (url) { return url.domain(); } } if (frame && frame.securityOrigin) { const domain = new Common.ParsedURL.ParsedURL(frame.securityOrigin).domain(); if (domain) { return domain; } } return 'IFrame'; } isItemSelectable(item: SDK.RuntimeModel.ExecutionContext): boolean { const callFrame = item.debuggerModel.selectedCallFrame(); const callFrameContext = callFrame && callFrame.script.executionContext(); return !callFrameContext || item === callFrameContext; } itemSelected(item: SDK.RuntimeModel.ExecutionContext|null): void { this._toolbarItem.element.classList.toggle('warning', !this._isTopContext(item) && this._hasTopContext()); const title = item ? i18nString(UIStrings.javascriptContextS, {PH1: this.titleFor(item)}) : i18nString(UIStrings.javascriptContextNotSelected); this._toolbarItem.setTitle(title); UI.Context.Context.instance().setFlavor(SDK.RuntimeModel.ExecutionContext, item); } _callFrameSelectedInUI(): void { const callFrame = UI.Context.Context.instance().flavor(SDK.DebuggerModel.CallFrame); const callFrameContext = callFrame && callFrame.script.executionContext(); if (callFrameContext) { UI.Context.Context.instance().setFlavor(SDK.RuntimeModel.ExecutionContext, callFrameContext); } } _callFrameSelectedInModel(event: Common.EventTarget.EventTargetEvent): void { const debuggerModel = (event.data as SDK.DebuggerModel.DebuggerModel); for (const executionContext of this._items) { if (executionContext.debuggerModel === debuggerModel) { this._dropDown.refreshItem(executionContext); } } } _frameNavigated(event: Common.EventTarget.EventTargetEvent): void { const frame = (event.data as SDK.ResourceTreeModel.ResourceTreeFrame); const runtimeModel = frame.resourceTreeModel().target().model(SDK.RuntimeModel.RuntimeModel); if (!runtimeModel) { return; } for (const executionContext of runtimeModel.executionContexts()) { if (frame.id === executionContext.frameId) { this._dropDown.refreshItem(executionContext); } } } }