UNPKG

3.02 kBPlain TextView Raw
1// Copyright (c) Jupyter Development Team.
2// Distributed under the terms of the Modified BSD License.
3
4import { WidgetTracker } from '@jupyterlab/apputils';
5import { Cell } from '@jupyterlab/cells';
6import { ISignal, Signal } from '@lumino/signaling';
7import { NotebookPanel } from './panel';
8import { INotebookTracker } from './tokens';
9import { Notebook } from './widget';
10
11export class NotebookTracker
12 extends WidgetTracker<NotebookPanel>
13 implements INotebookTracker
14{
15 /**
16 * The currently focused cell.
17 *
18 * #### Notes
19 * This is a read-only property. If there is no cell with the focus, then this
20 * value is `null`.
21 */
22 get activeCell(): Cell | null {
23 const widget = this.currentWidget;
24 if (!widget) {
25 return null;
26 }
27 return widget.content.activeCell || null;
28 }
29
30 /**
31 * A signal emitted when the current active cell changes.
32 *
33 * #### Notes
34 * If there is no cell with the focus, then `null` will be emitted.
35 */
36 get activeCellChanged(): ISignal<this, Cell | null> {
37 return this._activeCellChanged;
38 }
39
40 /**
41 * A signal emitted when the selection state changes.
42 */
43 get selectionChanged(): ISignal<this, void> {
44 return this._selectionChanged;
45 }
46
47 /**
48 * Add a new notebook panel to the tracker.
49 *
50 * @param panel - The notebook panel being added.
51 */
52 add(panel: NotebookPanel): Promise<void> {
53 const promise = super.add(panel);
54 panel.content.activeCellChanged.connect(this._onActiveCellChanged, this);
55 panel.content.selectionChanged.connect(this._onSelectionChanged, this);
56 return promise;
57 }
58
59 /**
60 * Dispose of the resources held by the tracker.
61 */
62 dispose(): void {
63 this._activeCell = null;
64 super.dispose();
65 }
66
67 /**
68 * Handle the current change event.
69 */
70 protected onCurrentChanged(widget: NotebookPanel): void {
71 // Store an internal reference to active cell to prevent false positives.
72 const activeCell = this.activeCell;
73 if (activeCell && activeCell === this._activeCell) {
74 return;
75 }
76 this._activeCell = activeCell;
77
78 if (!widget) {
79 return;
80 }
81
82 // Since the notebook has changed, immediately signal an active cell change
83 this._activeCellChanged.emit(widget.content.activeCell || null);
84 }
85
86 private _onActiveCellChanged(sender: Notebook, cell: Cell): void {
87 // Check if the active cell change happened for the current notebook.
88 if (this.currentWidget && this.currentWidget.content === sender) {
89 this._activeCell = cell || null;
90 this._activeCellChanged.emit(this._activeCell);
91 }
92 }
93
94 private _onSelectionChanged(sender: Notebook): void {
95 // Check if the selection change happened for the current notebook.
96 if (this.currentWidget && this.currentWidget.content === sender) {
97 this._selectionChanged.emit(void 0);
98 }
99 }
100
101 private _activeCell: Cell | null = null;
102 private _activeCellChanged = new Signal<this, Cell | null>(this);
103 private _selectionChanged = new Signal<this, void>(this);
104}