123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 |
- // Copyright (c) Jupyter Development Team.
- // Distributed under the terms of the Modified BSD License.
- import {
- Message
- } from 'phosphor/lib/core/messaging';
- import {
- clearSignalData, ISignal
- } from 'phosphor/lib/core/signaling';
- import {
- Token
- } from 'phosphor/lib/core/token';
- import {
- Panel
- } from 'phosphor/lib/ui/panel';
- import {
- TabPanel
- } from 'phosphor/lib/ui/tabpanel';
- import {
- Widget
- } from 'phosphor/lib/ui/widget';
- import {
- Toolbar, ToolbarButton
- } from '../toolbar';
- /**
- * The class name added to inspector panels.
- */
- const PANEL_CLASS = 'jp-Inspector';
- /**
- * The class name added to inspector child item widgets.
- */
- const ITEM_CLASS = 'jp-InspectorItem';
- /**
- * The class name added to inspector child item widgets' content.
- */
- const CONTENT_CLASS = 'jp-InspectorItem-content';
- /**
- * The history clear button class name.
- */
- const CLEAR_CLASS = 'jp-InspectorItem-clear';
- /**
- * The back button class name.
- */
- const BACK_CLASS = 'jp-InspectorItem-back';
- /**
- * The forward button class name.
- */
- const FORWARD_CLASS = 'jp-InspectorItem-forward';
- /* tslint:disable */
- /**
- * The inspector panel token.
- */
- export
- const IInspector = new Token<IInspector>('jupyter.services.inspector');
- /* tslint:enable */
- /**
- * An interface for an inspector panel.
- */
- export
- interface IInspector {
- /**
- * The source of events the inspector panel listens for.
- */
- source: Inspector.IInspectable;
- }
- /**
- * A panel which contains a set of inspectors.
- */
- export
- class Inspector extends TabPanel implements IInspector {
- /**
- * Construct an inspector.
- */
- constructor(options: Inspector.IOptions) {
- super();
- this.addClass(PANEL_CLASS);
- let items = options.items || [];
- // Create inspector child items and add them to the inspectors panel.
- items.forEach(value => {
- let widget = value.widget || new InspectorItem();
- widget.rank = value.rank;
- widget.remembers = !!value.remembers;
- widget.title.closable = false;
- widget.title.label = value.name;
- if (value.className) {
- widget.addClass(value.className);
- }
- this._items[value.type] = widget;
- this.addWidget(widget);
- });
- if (items.length < 2) {
- this.tabBar.hide();
- }
- }
- /**
- * The source of events the inspector panel listens for.
- */
- get source(): Inspector.IInspectable {
- return this._source;
- }
- set source(source: Inspector.IInspectable) {
- if (this._source === source) {
- return;
- }
- // Disconnect old signal handler.
- if (this._source) {
- this._source.inspected.disconnect(this.onInspectorUpdate, this);
- this._source.disposed.disconnect(this.onSourceDisposed, this);
- }
- // Clear the inspector child items (but maintain history) if necessary.
- if (this._items) {
- Object.keys(this._items).forEach(i => this._items[i].content = null);
- }
- this._source = source;
- // Connect new signal handler.
- if (this._source) {
- this._source.inspected.connect(this.onInspectorUpdate, this);
- this._source.disposed.connect(this.onSourceDisposed, this);
- }
- }
- /**
- * Dispose of the resources held by the widget.
- */
- dispose(): void {
- if (this._items == null) {
- return;
- }
- let items = this._items;
- this._items = null;
- this.source = null;
- // Dispose the inspector child items.
- Object.keys(items).forEach(i => { items[i].dispose(); });
- super.dispose();
- }
- /**
- * Handle `'activate-request'` messages.
- */
- protected onActivateRequest(msg: Message): void {
- this.node.tabIndex = -1;
- this.node.focus();
- }
- /**
- * Handle `'close-request'` messages.
- */
- protected onCloseRequest(msg: Message): void {
- super.onCloseRequest(msg);
- this.dispose();
- }
- /**
- * Handle inspector update signals.
- */
- protected onInspectorUpdate(sender: any, args: Inspector.IInspectorUpdate): void {
- let widget = this._items[args.type];
- if (!widget) {
- return;
- }
- // Update the content of the inspector widget.
- widget.content = args.content;
- let items = this._items;
- // If any inspector with a higher rank has content, do not change focus.
- if (args.content) {
- for (let type in items) {
- let inspector = this._items[type];
- if (inspector.rank < widget.rank && inspector.content) {
- return;
- }
- }
- this.currentWidget = widget;
- return;
- }
- // If the inspector was emptied, show the next best ranked inspector.
- let lowest = Infinity;
- widget = null;
- for (let type in items) {
- let inspector = this._items[type];
- if (inspector.rank < lowest && inspector.content) {
- lowest = inspector.rank;
- widget = inspector;
- }
- }
- if (widget) {
- this.currentWidget = widget;
- }
- }
- /**
- * Handle source disposed signals.
- */
- protected onSourceDisposed(sender: any, args: void): void {
- this.source = null;
- }
- private _items: { [type: string]: InspectorItem } = Object.create(null);
- private _source: Inspector.IInspectable = null;
- }
- /**
- * A namespace for Inspector statics.
- */
- export
- namespace Inspector {
- /**
- * The definition of an inspector.
- */
- export
- interface IInspectable {
- /**
- * A signal emitted when the handler is disposed.
- */
- disposed: ISignal<any, void>;
- /**
- * A signal emitted when inspector should clear all items with no history.
- */
- ephemeralCleared: ISignal<any, void>;
- /**
- * A signal emitted when an inspector value is generated.
- */
- inspected: ISignal<any, IInspectorUpdate>;
- }
- /**
- * An update value for code inspectors.
- */
- export
- interface IInspectorUpdate {
- /**
- * The content being sent to the inspector for display.
- */
- content: Widget;
- /**
- * The type of the inspector being updated.
- */
- type: string;
- }
- /**
- * The definition of a child item of an inspector panel.
- */
- export
- interface IInspectorItem {
- /**
- * The optional class name added to the inspector child widget.
- */
- className?: string;
- /**
- * The display name of the inspector child.
- */
- name: string;
- /**
- * The rank order of display priority for inspector updates. A lower rank
- * denotes a higher display priority.
- */
- rank: number;
- /**
- * A flag that indicates whether the inspector remembers history.
- *
- * The default value is `false`.
- */
- remembers?: boolean;
- /**
- * The type of the inspector.
- */
- type: string;
- /**
- * The optional inspector child item instance.
- */
- widget?: InspectorItem;
- }
- /**
- * The initialization options for an inspector panel.
- */
- export
- interface IOptions {
- /**
- * The list of available child inspectors items for code introspection.
- *
- * #### Notes
- * The order of items in the inspectors array is the order in which they
- * will be rendered in the inspectors tab panel.
- */
- items?: IInspectorItem[];
- }
- }
- /**
- * A code inspector child widget.
- */
- export
- class InspectorItem extends Panel {
- /**
- * Construct an inspector widget.
- */
- constructor() {
- super();
- this.addClass(ITEM_CLASS);
- this._toolbar = this._createToolbar();
- this.addWidget(this._toolbar);
- }
- /**
- * The text of the inspector.
- */
- get content(): Widget {
- return this._content;
- }
- set content(newValue: Widget) {
- if (newValue === this._content) {
- return;
- }
- if (this._content) {
- if (this._remembers) {
- this._content.hide();
- } else {
- this._content.dispose();
- }
- }
- this._content = newValue;
- if (this._content) {
- this._content.addClass(CONTENT_CLASS);
- this.addWidget(this._content);
- if (this.remembers) {
- this._history.push(newValue);
- this._index++;
- }
- }
- }
- /**
- * A flag that indicates whether the inspector remembers history.
- */
- get remembers(): boolean {
- return this._remembers;
- }
- set remembers(newValue: boolean) {
- if (newValue === this._remembers) {
- return;
- }
- this._clear();
- this._remembers = newValue;
- if (!this._remembers) {
- this._history = null;
- }
- this.update();
- }
- /**
- * The display rank of the inspector.
- */
- get rank(): number {
- return this._rank;
- }
- set rank(newValue: number) {
- this._rank = newValue;
- }
- /**
- * Dispose of the resources held by the widget.
- */
- dispose(): void {
- if (this._toolbar === null) {
- return;
- }
- let toolbar = this._toolbar;
- let history = this._history;
- this._toolbar = null;
- this._history = null;
- history.forEach(widget => widget.dispose());
- toolbar.dispose();
- super.dispose();
- }
- /**
- * Navigate back in history.
- */
- private _back(): void {
- if (this._history.length) {
- this._navigateTo(Math.max(this._index - 1, 0));
- }
- }
- /**
- * Clear history.
- */
- private _clear(): void {
- if (this._history) {
- this._history.forEach(widget => widget.dispose());
- }
- this._history = [];
- this._index = -1;
- }
- /**
- * Navigate forward in history.
- */
- private _forward(): void {
- if (this._history.length) {
- this._navigateTo(Math.min(this._index + 1, this._history.length - 1));
- }
- }
- /**
- * Create a history toolbar.
- */
- private _createToolbar(): Toolbar<Widget> {
- let toolbar = new Toolbar();
- if (!this._remembers) {
- return toolbar;
- }
- let clear = new ToolbarButton({
- className: CLEAR_CLASS,
- onClick: () => { this._clear(); },
- tooltip: 'Clear history.'
- });
- toolbar.addItem('clear', clear);
- let back = new ToolbarButton({
- className: BACK_CLASS,
- onClick: () => { this._back(); },
- tooltip: 'Navigate back in history.'
- });
- toolbar.addItem('back', back);
- let forward = new ToolbarButton({
- className: FORWARD_CLASS,
- onClick: () => { this._forward(); },
- tooltip: 'Navigate forward in history.'
- });
- toolbar.addItem('forward', forward);
- return toolbar;
- }
- /**
- * Navigate to a known index in history.
- */
- private _navigateTo(index: number): void {
- if (this._content) {
- this._content.hide();
- }
- this._content = this._history[index];
- this._index = index;
- this._content.show();
- }
- private _content: Widget = null;
- private _history: Widget[] = null;
- private _index: number = -1;
- private _rank: number = Infinity;
- private _remembers: boolean = false;
- private _toolbar: Toolbar<Widget> = null;
- }
|