|
@@ -1,6 +1,10 @@
|
|
|
// Copyright (c) Jupyter Development Team.
|
|
|
// Distributed under the terms of the Modified BSD License.
|
|
|
|
|
|
+import {
|
|
|
+ each
|
|
|
+} from 'phosphor/lib/algorithm/iteration';
|
|
|
+
|
|
|
import {
|
|
|
IDisposable
|
|
|
} from 'phosphor/lib/core/disposable';
|
|
@@ -17,6 +21,10 @@ import {
|
|
|
CommandRegistry
|
|
|
} from 'phosphor/lib/ui/commandregistry';
|
|
|
|
|
|
+import {
|
|
|
+ FocusTracker
|
|
|
+} from 'phosphor/lib/ui/focustracker';
|
|
|
+
|
|
|
import {
|
|
|
Widget
|
|
|
} from 'phosphor/lib/ui/widget';
|
|
@@ -35,11 +43,6 @@ import {
|
|
|
*/
|
|
|
export
|
|
|
interface IInstanceTracker<T extends Widget> {
|
|
|
- /**
|
|
|
- * A signal emitted when a widget is added or removed from the tracker.
|
|
|
- */
|
|
|
- readonly changed: ISignal<this, 'add' | 'remove'>;
|
|
|
-
|
|
|
/**
|
|
|
* A signal emitted when the current widget changes.
|
|
|
*
|
|
@@ -88,9 +91,6 @@ interface IInstanceTracker<T extends Widget> {
|
|
|
* A class that keeps track of widget instances.
|
|
|
*
|
|
|
* #### Notes
|
|
|
- * This is meant to be used in conjunction with a `FocusTracker` and will
|
|
|
- * typically be kept in sync with focus tracking events.
|
|
|
- *
|
|
|
* The API surface area of this concrete implementation is substantially larger
|
|
|
* than the instance tracker interface it implements. The interface is intended
|
|
|
* for export by JupyterLab plugins that create widgets and have clients who may
|
|
@@ -106,6 +106,10 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
*/
|
|
|
constructor(options: InstanceTracker.IOptions) {
|
|
|
this.namespace = options.namespace;
|
|
|
+ this._tracker.currentChanged.connect((sender, args) => {
|
|
|
+ this.onCurrentChanged();
|
|
|
+ this.currentChanged.emit(this.currentWidget);
|
|
|
+ }, this);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -113,16 +117,8 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
*/
|
|
|
readonly namespace: string;
|
|
|
|
|
|
- /**
|
|
|
- * A signal emitted when a widget is added or removed from the tracker.
|
|
|
- */
|
|
|
- readonly changed: ISignal<this, 'add' | 'remove'>;
|
|
|
-
|
|
|
/**
|
|
|
* A signal emitted when the current widget changes.
|
|
|
- *
|
|
|
- * #### Notes
|
|
|
- * If the last widget being tracked is disposed, `null` will be emitted.
|
|
|
*/
|
|
|
readonly currentChanged: ISignal<this, T>;
|
|
|
|
|
@@ -130,21 +126,21 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
* The current widget is the most recently focused widget.
|
|
|
*/
|
|
|
get currentWidget(): T {
|
|
|
- return this._currentWidget;
|
|
|
+ return this._tracker.currentWidget;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Test whether the tracker is disposed.
|
|
|
*/
|
|
|
get isDisposed(): boolean {
|
|
|
- return this._widgets === null;
|
|
|
+ return this._isDisposed;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* The number of widgets held by the tracker.
|
|
|
*/
|
|
|
get size(): number {
|
|
|
- return this._widgets.size;
|
|
|
+ return this._tracker.widgets.length;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -153,12 +149,12 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
* @param widget - The widget being added.
|
|
|
*/
|
|
|
add(widget: T): Promise<void> {
|
|
|
- if (this._widgets.has(widget)) {
|
|
|
+ if (this._tracker.has(widget)) {
|
|
|
let warning = `${widget.id} already exists in the tracker.`;
|
|
|
console.warn(warning);
|
|
|
return Promise.reject(warning);
|
|
|
}
|
|
|
- this._widgets.add(widget);
|
|
|
+ this._tracker.add(widget);
|
|
|
|
|
|
let injected = Private.injectedProperty.get(widget);
|
|
|
let promise: Promise<void>;
|
|
@@ -183,7 +179,6 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
|
|
|
// Handle widget disposal.
|
|
|
widget.disposed.connect(() => {
|
|
|
- this._widgets.delete(widget);
|
|
|
// If restore data was saved, delete it from the database.
|
|
|
if (!injected && this._restore) {
|
|
|
let { state } = this._restore;
|
|
@@ -193,19 +188,8 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
state.remove(name);
|
|
|
}
|
|
|
}
|
|
|
- // Emit a changed signal.
|
|
|
- this.changed.emit('remove');
|
|
|
- // If this was the last widget, emit null for current widget signal.
|
|
|
- if (!this._widgets.size) {
|
|
|
- this._currentWidget = null;
|
|
|
- this.onCurrentChanged();
|
|
|
- this.currentChanged.emit(null);
|
|
|
- }
|
|
|
});
|
|
|
|
|
|
- // Emit a changed signal.
|
|
|
- this.changed.emit('add');
|
|
|
-
|
|
|
return promise || Promise.resolve(void 0);
|
|
|
}
|
|
|
|
|
@@ -216,10 +200,8 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
if (this.isDisposed) {
|
|
|
return;
|
|
|
}
|
|
|
+ this._isDisposed = true;
|
|
|
clearSignalData(this);
|
|
|
- this._currentWidget = null;
|
|
|
- this._widgets.clear();
|
|
|
- this._widgets = null;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -229,7 +211,7 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
*/
|
|
|
find(fn: (widget: T) => boolean): T {
|
|
|
let result: T = null;
|
|
|
- this._widgets.forEach(widget => {
|
|
|
+ each(this._tracker.widgets, widget => {
|
|
|
// If a result has already been found, short circuit.
|
|
|
if (result) {
|
|
|
return;
|
|
@@ -247,7 +229,7 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
* @param fn - The function to call on each widget.
|
|
|
*/
|
|
|
forEach(fn: (widget: T) => void): void {
|
|
|
- this._widgets.forEach(widget => { fn(widget); });
|
|
|
+ each(this._tracker.widgets, widget => { fn(widget); });
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -276,7 +258,7 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
* @param widget - The widget whose existence is being checked.
|
|
|
*/
|
|
|
has(widget: Widget): boolean {
|
|
|
- return this._widgets.has(widget as any);
|
|
|
+ return this._tracker.has(widget as any);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -342,35 +324,6 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- /**
|
|
|
- * Syncs the state of the tracker with a widget known to have focus.
|
|
|
- *
|
|
|
- * @param current The currently focused widget.
|
|
|
- *
|
|
|
- * @returns The current widget or `null` if there is none.
|
|
|
- *
|
|
|
- * #### Notes
|
|
|
- * Syncing acts as a gate returning a widget only if it is the current widget.
|
|
|
- */
|
|
|
- sync(current: Widget): T {
|
|
|
- if (this.isDisposed) {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (current && this._widgets.has(current as any)) {
|
|
|
- // If no state change needs to occur, just bail.
|
|
|
- if (this._currentWidget === current) {
|
|
|
- return this._currentWidget;
|
|
|
- }
|
|
|
- this._currentWidget = current as T;
|
|
|
- this.onCurrentChanged();
|
|
|
- this.currentChanged.emit(this._currentWidget);
|
|
|
- return this._currentWidget;
|
|
|
- }
|
|
|
-
|
|
|
- return null;
|
|
|
- }
|
|
|
-
|
|
|
/**
|
|
|
* Handle the current change event.
|
|
|
*
|
|
@@ -382,14 +335,14 @@ class InstanceTracker<T extends Widget> implements IInstanceTracker<T>, IDisposa
|
|
|
/* This is a no-op. */
|
|
|
}
|
|
|
|
|
|
- private _currentWidget: T = null;
|
|
|
+ private _isDisposed = false;
|
|
|
private _restore: InstanceTracker.IRestoreOptions<T> = null;
|
|
|
+ private _tracker = new FocusTracker<T>();
|
|
|
private _widgets = new Set<T>();
|
|
|
}
|
|
|
|
|
|
|
|
|
// Define the signals for the `InstanceTracker` class.
|
|
|
-defineSignal(InstanceTracker.prototype, 'changed');
|
|
|
defineSignal(InstanceTracker.prototype, 'currentChanged');
|
|
|
|
|
|
|