@fails-components/jupyter-applet-view 0.0.1-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +29 -0
- package/README.md +101 -0
- package/lib/appletview.d.ts +7 -0
- package/lib/appletview.js +333 -0
- package/lib/avoutputarea.d.ts +149 -0
- package/lib/avoutputarea.js +751 -0
- package/lib/avtoolbarextension.d.ts +36 -0
- package/lib/avtoolbarextension.js +213 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +35 -0
- package/lib/splitviewnotebookpanel.d.ts +31 -0
- package/lib/splitviewnotebookpanel.js +127 -0
- package/package.json +226 -0
- package/schema/plugin.json +31 -0
- package/schema/toolbar.json +8 -0
- package/src/appletview.ts +395 -0
- package/src/avoutputarea.ts +966 -0
- package/src/avtoolbarextension.ts +280 -0
- package/src/index.ts +47 -0
- package/src/splitviewnotebookpanel.ts +186 -0
- package/style/base.css +5 -0
- package/style/index.css +163 -0
- package/style/index.js +2 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { ToolbarRegistry } from '@jupyterlab/apputils';
|
|
2
|
+
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
3
|
+
import { IObservableList } from '@jupyterlab/observables';
|
|
4
|
+
import { CommandRegistry } from '@lumino/commands';
|
|
5
|
+
import { IDisposable } from '@lumino/disposable';
|
|
6
|
+
import { Widget } from '@lumino/widgets';
|
|
7
|
+
import { SplitViewNotebookPanel } from './splitviewnotebookpanel';
|
|
8
|
+
import { IFailsLauncherInfo } from '@fails-components/jupyter-launcher';
|
|
9
|
+
export declare const defaultToolbarItems: ToolbarRegistry.IWidget[];
|
|
10
|
+
export declare class AppletViewToolbarExtension implements DocumentRegistry.WidgetExtension {
|
|
11
|
+
static readonly FACTORY_NAME = "AppletView";
|
|
12
|
+
constructor(commands: CommandRegistry, launcherInfo: IFailsLauncherInfo | null, toolbarFactory?: (widget: Widget) => IObservableList<ToolbarRegistry.IToolbarItem>);
|
|
13
|
+
protected get defaultToolbarFactory(): (widget: Widget) => IObservableList<ToolbarRegistry.IToolbarItem>;
|
|
14
|
+
createNew(panel: SplitViewNotebookPanel): IDisposable;
|
|
15
|
+
private _commands;
|
|
16
|
+
private _toolbarFactory;
|
|
17
|
+
private _launcherInfo;
|
|
18
|
+
}
|
|
19
|
+
export declare class AppletViewToolbarTracker implements IDisposable {
|
|
20
|
+
/**
|
|
21
|
+
* AppletViewToolbarTracker constructor
|
|
22
|
+
*
|
|
23
|
+
* @param view The Applet View area
|
|
24
|
+
* @param toolbarFactory The toolbar factory
|
|
25
|
+
*/
|
|
26
|
+
constructor(notebookpanel: SplitViewNotebookPanel, toolbarFactory: (widget: Widget) => IObservableList<ToolbarRegistry.IToolbarItem>, launcherInfo: IFailsLauncherInfo | null);
|
|
27
|
+
dispose(): void;
|
|
28
|
+
get isDisposed(): boolean;
|
|
29
|
+
private _addToolbar;
|
|
30
|
+
_setHiddenToolbars(hidden: boolean): void;
|
|
31
|
+
private _isDisposed;
|
|
32
|
+
private _notebookpanel;
|
|
33
|
+
private _toolbars;
|
|
34
|
+
private _toolbarStore;
|
|
35
|
+
private _toolbarFactory;
|
|
36
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { createDefaultFactory, setToolbar } from '@jupyterlab/apputils';
|
|
2
|
+
import { ObservableList } from '@jupyterlab/observables';
|
|
3
|
+
import { Toolbar } from '@jupyterlab/ui-components';
|
|
4
|
+
import { Signal } from '@lumino/signaling';
|
|
5
|
+
// portions used from Jupyterlab:
|
|
6
|
+
/* -----------------------------------------------------------------------------
|
|
7
|
+
| Copyright (c) Jupyter Development Team.
|
|
8
|
+
| Distributed under the terms of the Modified BSD License.
|
|
9
|
+
|----------------------------------------------------------------------------*/
|
|
10
|
+
// This code contains portions from or is inspired by Jupyter lab's notebook extension, especially the createOutputView part
|
|
11
|
+
// Also a lot is taken from the cell toolbar related parts.
|
|
12
|
+
export const defaultToolbarItems = [
|
|
13
|
+
{
|
|
14
|
+
command: 'fails-components-jupyter-applet-view:move_view_up',
|
|
15
|
+
name: 'move-view-up'
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
command: 'fails-components-jupyter-applet-view:move_view_down',
|
|
19
|
+
name: 'move-view-down'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
command: 'fails-components-jupyter-applet-view:move_view_app_up',
|
|
23
|
+
name: 'move-view-app-up'
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
command: 'fails-components-jupyter-applet-view:move_view_app_down',
|
|
27
|
+
name: 'move-view-app-down'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
command: 'fails-components-jupyter-applet-view:delete_view',
|
|
31
|
+
name: 'delete-view'
|
|
32
|
+
}
|
|
33
|
+
];
|
|
34
|
+
// a lot of code taken from Jupyter labs CellBarExtension
|
|
35
|
+
class AppletViewToolbarExtension {
|
|
36
|
+
constructor(commands, launcherInfo, toolbarFactory) {
|
|
37
|
+
this._commands = commands;
|
|
38
|
+
this._launcherInfo = launcherInfo;
|
|
39
|
+
// # TODO we have to make sure, we get the default, how can we do this?
|
|
40
|
+
this._toolbarFactory = toolbarFactory !== null && toolbarFactory !== void 0 ? toolbarFactory : this.defaultToolbarFactory;
|
|
41
|
+
}
|
|
42
|
+
get defaultToolbarFactory() {
|
|
43
|
+
const itemFactory = createDefaultFactory(this._commands);
|
|
44
|
+
return (widget) => new ObservableList({
|
|
45
|
+
values: defaultToolbarItems.map(item => {
|
|
46
|
+
// console.log('widget? factory', widget);
|
|
47
|
+
const applet = widget.parent;
|
|
48
|
+
const parent = applet.parent;
|
|
49
|
+
const path = parent.path;
|
|
50
|
+
return {
|
|
51
|
+
name: item.name,
|
|
52
|
+
widget: itemFactory(AppletViewToolbarExtension.FACTORY_NAME, widget, {
|
|
53
|
+
...item,
|
|
54
|
+
args: {
|
|
55
|
+
// @ts-expect-error cellid is not part of Widget
|
|
56
|
+
cellid: widget.cellid,
|
|
57
|
+
notepadpath: path,
|
|
58
|
+
// @ts-expect-error appid is not part of Widget
|
|
59
|
+
widgetid: widget.widgetid
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
};
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
createNew(panel) {
|
|
67
|
+
return new AppletViewToolbarTracker(panel, this._toolbarFactory, this._launcherInfo);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
AppletViewToolbarExtension.FACTORY_NAME = 'AppletView';
|
|
71
|
+
export { AppletViewToolbarExtension };
|
|
72
|
+
export class AppletViewToolbarTracker {
|
|
73
|
+
/**
|
|
74
|
+
* AppletViewToolbarTracker constructor
|
|
75
|
+
*
|
|
76
|
+
* @param view The Applet View area
|
|
77
|
+
* @param toolbarFactory The toolbar factory
|
|
78
|
+
*/
|
|
79
|
+
constructor(notebookpanel, toolbarFactory, launcherInfo) {
|
|
80
|
+
this._isDisposed = false;
|
|
81
|
+
this._toolbars = new WeakMap();
|
|
82
|
+
this._toolbarStore = [];
|
|
83
|
+
this._notebookpanel = notebookpanel;
|
|
84
|
+
this._toolbarFactory = toolbarFactory !== null && toolbarFactory !== void 0 ? toolbarFactory : null;
|
|
85
|
+
// Only add the toolbar to the notebook's active cell (if any) once it has fully rendered and been revealed.
|
|
86
|
+
void notebookpanel.revealed.then(() => {
|
|
87
|
+
requestAnimationFrame(() => {
|
|
88
|
+
var _a;
|
|
89
|
+
(_a = this._notebookpanel) === null || _a === void 0 ? void 0 : _a.appletViewWidget.viewChanged.connect(this._addToolbar, this);
|
|
90
|
+
this._addToolbar();
|
|
91
|
+
if (launcherInfo === null || launcherInfo === void 0 ? void 0 : launcherInfo.inLecture) {
|
|
92
|
+
this._setHiddenToolbars(launcherInfo === null || launcherInfo === void 0 ? void 0 : launcherInfo.inLecture);
|
|
93
|
+
}
|
|
94
|
+
if (launcherInfo) {
|
|
95
|
+
let hasToolbar = !(launcherInfo === null || launcherInfo === void 0 ? void 0 : launcherInfo.inLecture);
|
|
96
|
+
launcherInfo.inLectureChanged.connect((sender, newInLecture) => {
|
|
97
|
+
if (hasToolbar !== !newInLecture) {
|
|
98
|
+
this._setHiddenToolbars(newInLecture);
|
|
99
|
+
hasToolbar = !newInLecture;
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
dispose() {
|
|
107
|
+
if (this.isDisposed) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
this._isDisposed = true;
|
|
111
|
+
this._toolbarStore.forEach(tb => tb.dispose());
|
|
112
|
+
this._toolbarStore = [];
|
|
113
|
+
this._toolbars = new WeakMap();
|
|
114
|
+
this._notebookpanel = null;
|
|
115
|
+
Signal.clearData(this);
|
|
116
|
+
}
|
|
117
|
+
get isDisposed() {
|
|
118
|
+
return this._isDisposed;
|
|
119
|
+
}
|
|
120
|
+
_addToolbar() {
|
|
121
|
+
var _a;
|
|
122
|
+
const notebookpanel = this._notebookpanel;
|
|
123
|
+
if (notebookpanel && !notebookpanel.isDisposed) {
|
|
124
|
+
const promises = [
|
|
125
|
+
/*notebookpanel.ready*/
|
|
126
|
+
]; // remove area ready
|
|
127
|
+
const applets = (_a = notebookpanel.appletViewWidget) === null || _a === void 0 ? void 0 : _a.applets;
|
|
128
|
+
const doAddToolbar = (part) => {
|
|
129
|
+
const clone = part.clone;
|
|
130
|
+
if (clone) {
|
|
131
|
+
// eslint-disable-next-line no-constant-condition
|
|
132
|
+
const toolbarWidget = new Toolbar();
|
|
133
|
+
this._toolbars.set(part, toolbarWidget);
|
|
134
|
+
this._toolbarStore.push(toolbarWidget);
|
|
135
|
+
// Note: CELL_MENU_CLASS is deprecated.
|
|
136
|
+
toolbarWidget.addClass('fl-jp-AppletViewToolbar'); // implement MR
|
|
137
|
+
if (this._toolbarFactory) {
|
|
138
|
+
// ts-expect-error Widget has no toolbar
|
|
139
|
+
// clone.toolbar = toolbarWidget;
|
|
140
|
+
setToolbar(clone, this._toolbarFactory, toolbarWidget);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
for (const applet of applets) {
|
|
145
|
+
for (const part of applet.parts) {
|
|
146
|
+
const clone = part.clone;
|
|
147
|
+
if (!this._toolbars.has(part)) {
|
|
148
|
+
if (clone) {
|
|
149
|
+
// eslint-disable-next-line no-constant-condition
|
|
150
|
+
doAddToolbar(part);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
// we have to defer it
|
|
154
|
+
const slot = () => {
|
|
155
|
+
doAddToolbar(part);
|
|
156
|
+
part.cloned.disconnect(slot);
|
|
157
|
+
};
|
|
158
|
+
part.cloned.connect(slot);
|
|
159
|
+
this._toolbars.set(part, null);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// FIXME toolbarWidget.update() - strangely this does not work
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// promises.push(area.ready); // remove?
|
|
166
|
+
// Wait for all the buttons to be rendered before attaching the toolbar.
|
|
167
|
+
Promise.all(promises)
|
|
168
|
+
.then(() => {
|
|
169
|
+
for (const applet of applets) {
|
|
170
|
+
for (const part of applet.parts) {
|
|
171
|
+
const toolbarWidget = this._toolbars.get(part);
|
|
172
|
+
if (!toolbarWidget) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (!part.clone || part.clone.isDisposed) {
|
|
176
|
+
continue;
|
|
177
|
+
}
|
|
178
|
+
const clone = part.clone;
|
|
179
|
+
if (clone) {
|
|
180
|
+
// (clone!.layout as PanelLayout).insertWidget(0, toolbarWidget);
|
|
181
|
+
clone.layout.addWidget(toolbarWidget);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// For rendered markdown, watch for resize events.
|
|
186
|
+
// area.displayChanged.connect(this._resizeEventCallback, this); // remove?
|
|
187
|
+
// Watch for changes in the cell's contents.
|
|
188
|
+
// area.model.contentChanged.connect(this._changedEventCallback, this); ?
|
|
189
|
+
// Hide the cell toolbar if it overlaps with cell contents
|
|
190
|
+
// this._updateCellForToolbarOverlap(area); // remove?
|
|
191
|
+
})
|
|
192
|
+
.catch(e => {
|
|
193
|
+
console.error('Error rendering buttons of the cell toolbar: ', e);
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
_setHiddenToolbars(hidden) {
|
|
198
|
+
var _a;
|
|
199
|
+
const notebookpanel = this._notebookpanel;
|
|
200
|
+
if (notebookpanel && !notebookpanel.isDisposed) {
|
|
201
|
+
const applets = (_a = notebookpanel.appletViewWidget) === null || _a === void 0 ? void 0 : _a.applets;
|
|
202
|
+
for (const applet of applets) {
|
|
203
|
+
for (const part of applet.parts) {
|
|
204
|
+
const toolbarWidget = this._toolbars.get(part);
|
|
205
|
+
if (!toolbarWidget) {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
toolbarWidget.setHidden(hidden);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ILayoutRestorer } from '@jupyterlab/application';
|
|
2
|
+
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
3
|
+
import { ITranslator } from '@jupyterlab/translation';
|
|
4
|
+
import { INotebookTracker } from '@jupyterlab/notebook';
|
|
5
|
+
import { AppletViewToolbarExtension } from './avtoolbarextension';
|
|
6
|
+
import { activateAppletView } from './appletview';
|
|
7
|
+
import { IFailsInterceptor } from '@fails-components/jupyter-interceptor';
|
|
8
|
+
import { IFailsLauncherInfo } from '@fails-components/jupyter-launcher';
|
|
9
|
+
const appletView = {
|
|
10
|
+
id: '@fails-components/jupyter-applet-view:plugin',
|
|
11
|
+
description: "An extension, that let's you select cell and switch to an applet mode, where only the selected cells are visible. This is used for fails-components to have jupyter applets in interactive teaching. ",
|
|
12
|
+
requires: [IDocumentManager, INotebookTracker, ITranslator],
|
|
13
|
+
optional: [ILayoutRestorer, IFailsLauncherInfo, IFailsInterceptor],
|
|
14
|
+
autoStart: true,
|
|
15
|
+
activate: activateAppletView
|
|
16
|
+
};
|
|
17
|
+
const appletViewToolbar = {
|
|
18
|
+
id: '@fails-components/jupyter-applet-view:toolbar',
|
|
19
|
+
description: 'Add the applet view toolbar during editing.',
|
|
20
|
+
autoStart: true,
|
|
21
|
+
activate: async (app, launcherInfo) => {
|
|
22
|
+
const toolbarItems = undefined;
|
|
23
|
+
app.docRegistry.addWidgetExtension('Notebook', new AppletViewToolbarExtension(app.commands, launcherInfo, toolbarItems));
|
|
24
|
+
},
|
|
25
|
+
optional: [IFailsLauncherInfo]
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Initialization data for the @fails-components/jupyter-applet-view extension.
|
|
29
|
+
*/
|
|
30
|
+
const plugins = [
|
|
31
|
+
// all JupyterFrontEndPlugins
|
|
32
|
+
appletView,
|
|
33
|
+
appletViewToolbar
|
|
34
|
+
];
|
|
35
|
+
export default plugins;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { DocumentRegistry, DocumentWidget } from '@jupyterlab/docregistry';
|
|
2
|
+
import { NotebookPanel, Notebook, INotebookModel, NotebookWidgetFactory } from '@jupyterlab/notebook';
|
|
3
|
+
import { AppletViewOutputArea } from './avoutputarea';
|
|
4
|
+
import { IFailsLauncherInfo, IAppletScreenshottaker, IScreenShotOpts } from '@fails-components/jupyter-launcher';
|
|
5
|
+
import { IFailsInterceptor } from '@fails-components/jupyter-interceptor';
|
|
6
|
+
interface IAppletResizeEvent {
|
|
7
|
+
appid: string;
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
}
|
|
11
|
+
export declare class SplitViewNotebookPanel extends NotebookPanel implements IAppletScreenshottaker {
|
|
12
|
+
constructor(options: DocumentWidget.IOptions<Notebook, INotebookModel>, failsLauncherInfo: IFailsLauncherInfo | undefined, failsInterceptor: IFailsInterceptor | undefined);
|
|
13
|
+
appletResizeinfo({ appid, width, height }: IAppletResizeEvent): void;
|
|
14
|
+
get appletViewWidget(): AppletViewOutputArea;
|
|
15
|
+
takeAppScreenshot(opts: IScreenShotOpts): Promise<Blob | undefined>;
|
|
16
|
+
private _appletviewWidget;
|
|
17
|
+
private _failsLauncherInfo;
|
|
18
|
+
}
|
|
19
|
+
declare namespace SplitViewNotebookWidgetFactory {
|
|
20
|
+
interface IOptions extends NotebookWidgetFactory.IOptions<NotebookPanel> {
|
|
21
|
+
failsLauncherInfo?: IFailsLauncherInfo;
|
|
22
|
+
failsInterceptor?: IFailsInterceptor;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export declare class SplitViewNotebookWidgetFactory extends NotebookWidgetFactory {
|
|
26
|
+
constructor(options: SplitViewNotebookWidgetFactory.IOptions);
|
|
27
|
+
protected createNewWidget(context: DocumentRegistry.IContext<INotebookModel>, source?: NotebookPanel): SplitViewNotebookPanel;
|
|
28
|
+
private _failsLauncherInfo;
|
|
29
|
+
private _failsInterceptor;
|
|
30
|
+
}
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { NotebookPanel, NotebookHistory, NotebookWidgetFactory } from '@jupyterlab/notebook';
|
|
2
|
+
import { BoxLayout, SplitPanel } from '@lumino/widgets';
|
|
3
|
+
import { AppletViewOutputArea } from './avoutputarea';
|
|
4
|
+
export class SplitViewNotebookPanel extends NotebookPanel {
|
|
5
|
+
constructor(options, failsLauncherInfo, failsInterceptor) {
|
|
6
|
+
super(options);
|
|
7
|
+
this._failsLauncherInfo = failsLauncherInfo;
|
|
8
|
+
// now we have to do the following
|
|
9
|
+
// 1. remove this._content from the layout
|
|
10
|
+
const content = this['_content'];
|
|
11
|
+
const layout = this.layout;
|
|
12
|
+
layout.removeWidget(content);
|
|
13
|
+
// 2. add a BoxLayout instead
|
|
14
|
+
const splitPanel = new SplitPanel({
|
|
15
|
+
spacing: 1,
|
|
16
|
+
orientation: 'horizontal'
|
|
17
|
+
});
|
|
18
|
+
BoxLayout.setStretch(splitPanel, 1);
|
|
19
|
+
// 3. add content to the BoxLayout, as well as a applet view area
|
|
20
|
+
splitPanel.addWidget(content);
|
|
21
|
+
const widget = (this._appletviewWidget = new AppletViewOutputArea({
|
|
22
|
+
notebook: this,
|
|
23
|
+
applets: undefined,
|
|
24
|
+
translator: options.translator,
|
|
25
|
+
interceptor: failsInterceptor
|
|
26
|
+
}));
|
|
27
|
+
splitPanel.addWidget(widget);
|
|
28
|
+
layout.addWidget(splitPanel);
|
|
29
|
+
// move to separate handler
|
|
30
|
+
if (failsLauncherInfo === null || failsLauncherInfo === void 0 ? void 0 : failsLauncherInfo.inLecture) {
|
|
31
|
+
this.toolbar.hide();
|
|
32
|
+
this.addClass('fl-jl-notebook-inlecture');
|
|
33
|
+
this._appletviewWidget.inLecture = true;
|
|
34
|
+
content.hide();
|
|
35
|
+
splitPanel.setRelativeSizes([0, 1]); // change sizes
|
|
36
|
+
}
|
|
37
|
+
if (failsLauncherInfo) {
|
|
38
|
+
failsLauncherInfo.inLectureChanged.connect((sender, newInLecture) => {
|
|
39
|
+
if (newInLecture) {
|
|
40
|
+
this.toolbar.hide();
|
|
41
|
+
this.addClass('fl-jl-notebook-inlecture');
|
|
42
|
+
this._appletviewWidget.inLecture = true;
|
|
43
|
+
content.hide();
|
|
44
|
+
splitPanel.setRelativeSizes([0, 1]); // change sizes
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
this.toolbar.show();
|
|
48
|
+
this.removeClass('fl-jl-notebook-inlecture');
|
|
49
|
+
this._appletviewWidget.inLecture = false;
|
|
50
|
+
content.show();
|
|
51
|
+
splitPanel.setRelativeSizes([1, 1]); // change sizes
|
|
52
|
+
widget.unselectApplet();
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
if (failsLauncherInfo.inLecture &&
|
|
56
|
+
typeof failsLauncherInfo.selectedAppid !== 'undefined') {
|
|
57
|
+
widget.selectApplet(failsLauncherInfo.selectedAppid);
|
|
58
|
+
}
|
|
59
|
+
failsLauncherInfo.selectedAppidChanged.connect((sender, appid) => {
|
|
60
|
+
if (typeof appid !== 'undefined') {
|
|
61
|
+
widget.selectApplet(appid);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
widget.viewChanged.connect((sender) => {
|
|
66
|
+
const failsData = sender.saveData();
|
|
67
|
+
if (failsData) {
|
|
68
|
+
const model = this.context.model;
|
|
69
|
+
model.setMetadata('failsApp', failsData);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
const metadataUpdater = () => {
|
|
73
|
+
const { failsApp, kernelspec } = this.context.model.metadata;
|
|
74
|
+
if (failsLauncherInfo === null || failsLauncherInfo === void 0 ? void 0 : failsLauncherInfo.reportMetadata) {
|
|
75
|
+
failsLauncherInfo.reportMetadata({ failsApp, kernelspec });
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
this.context.model.metadataChanged.connect(metadataUpdater);
|
|
79
|
+
metadataUpdater();
|
|
80
|
+
}
|
|
81
|
+
appletResizeinfo({ appid, width, height }) {
|
|
82
|
+
if (this._failsLauncherInfo) {
|
|
83
|
+
this._failsLauncherInfo.appletSizes[appid] = { appid, width, height };
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
get appletViewWidget() {
|
|
87
|
+
return this._appletviewWidget;
|
|
88
|
+
}
|
|
89
|
+
async takeAppScreenshot(opts) {
|
|
90
|
+
return await this._appletviewWidget.takeAppScreenshot(opts);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export class SplitViewNotebookWidgetFactory extends NotebookWidgetFactory {
|
|
94
|
+
constructor(options) {
|
|
95
|
+
super(options);
|
|
96
|
+
this._failsLauncherInfo = options.failsLauncherInfo;
|
|
97
|
+
this._failsInterceptor = options.failsInterceptor;
|
|
98
|
+
}
|
|
99
|
+
createNewWidget(context, source) {
|
|
100
|
+
// copied from basis object
|
|
101
|
+
const translator = context.translator;
|
|
102
|
+
const kernelHistory = new NotebookHistory({
|
|
103
|
+
sessionContext: context.sessionContext,
|
|
104
|
+
translator: translator
|
|
105
|
+
});
|
|
106
|
+
const nbOptions = {
|
|
107
|
+
rendermime: source
|
|
108
|
+
? source.content.rendermime
|
|
109
|
+
: this.rendermime.clone({ resolver: context.urlResolver }),
|
|
110
|
+
contentFactory: this.contentFactory,
|
|
111
|
+
mimeTypeService: this.mimeTypeService,
|
|
112
|
+
editorConfig: source
|
|
113
|
+
? source.content.editorConfig
|
|
114
|
+
: this['_editorConfig'],
|
|
115
|
+
notebookConfig: source
|
|
116
|
+
? source.content.notebookConfig
|
|
117
|
+
: this['_notebookConfig'],
|
|
118
|
+
translator,
|
|
119
|
+
kernelHistory
|
|
120
|
+
};
|
|
121
|
+
const content = this.contentFactory.createNotebook(nbOptions);
|
|
122
|
+
return new SplitViewNotebookPanel({
|
|
123
|
+
context,
|
|
124
|
+
content
|
|
125
|
+
}, this._failsLauncherInfo, this._failsInterceptor);
|
|
126
|
+
}
|
|
127
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fails-components/jupyter-applet-view",
|
|
3
|
+
"version": "0.0.1-alpha.10",
|
|
4
|
+
"description": "A collection of extensions, that let's you select cell and switch to an applet mode, where only the selected cells are visible. This is used for fails-components to have jupyter applets in interactive teaching. ",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jupyter",
|
|
7
|
+
"jupyterlab",
|
|
8
|
+
"jupyterlab-extension"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/fails-components/jupyterfails",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/fails-components/jupyterfails/issues"
|
|
13
|
+
},
|
|
14
|
+
"license": "BSD-3-Clause",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "Marten Richter",
|
|
17
|
+
"email": "marten.richter@freenet.de"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
|
|
21
|
+
"style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
|
|
22
|
+
"schema/*.json",
|
|
23
|
+
"src/**/*.{ts,tsx}"
|
|
24
|
+
],
|
|
25
|
+
"main": "lib/index.js",
|
|
26
|
+
"types": "lib/index.d.ts",
|
|
27
|
+
"style": "style/index.css",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/fails-components/jupyterfails.git"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "jlpm build:lib && jlpm build:labextension:dev",
|
|
34
|
+
"build:prod": "jlpm clean && jlpm build:lib:prod && jlpm build:labextension",
|
|
35
|
+
"build:labextension": "jupyter labextension build .",
|
|
36
|
+
"build:labextension:dev": "jupyter labextension build --development True .",
|
|
37
|
+
"build:lib": "tsc --sourceMap",
|
|
38
|
+
"build:lib:prod": "tsc",
|
|
39
|
+
"clean": "jlpm clean:lib",
|
|
40
|
+
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
41
|
+
"clean:lintcache": "rimraf .eslintcache .stylelintcache",
|
|
42
|
+
"clean:labextension": "rimraf fails_components_jupyter_applet_view/labextension fails_components_jupyter_applet_view/_version.py",
|
|
43
|
+
"clean:all": "jlpm clean:lib && jlpm clean:labextension && jlpm clean:lintcache",
|
|
44
|
+
"eslint": "jlpm eslint:check --fix",
|
|
45
|
+
"eslint:check": "eslint . --cache --ext .ts,.tsx",
|
|
46
|
+
"install:extension": "jlpm build",
|
|
47
|
+
"lint": "jlpm stylelint && jlpm prettier && jlpm eslint",
|
|
48
|
+
"lint:check": "jlpm stylelint:check && jlpm prettier:check && jlpm eslint:check",
|
|
49
|
+
"prepublishOnly": "npm run build",
|
|
50
|
+
"prettier": "jlpm prettier:base --write --list-different",
|
|
51
|
+
"prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
|
|
52
|
+
"prettier:check": "jlpm prettier:base --check",
|
|
53
|
+
"stylelint": "jlpm stylelint:check --fix",
|
|
54
|
+
"stylelint:check": "stylelint --cache \"style/**/*.css\"",
|
|
55
|
+
"test": "jest --coverage --passWithNoTests",
|
|
56
|
+
"watch": "run-p watch:src watch:labextension",
|
|
57
|
+
"watch:src": "tsc -w --sourceMap",
|
|
58
|
+
"watch:labextension": "jupyter labextension watch ."
|
|
59
|
+
},
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"@fails-components/jupyter-interceptor": "^0.0.1-alpha.10",
|
|
62
|
+
"@fails-components/jupyter-launcher": "^0.0.1-alpha.10",
|
|
63
|
+
"@jupyter-notebook/application": "^7.2.0",
|
|
64
|
+
"@jupyter-widgets/jupyterlab-manager": "^5.0.13",
|
|
65
|
+
"@jupyterlab/application": "^4.3.4",
|
|
66
|
+
"@jupyterlab/apputils": "^4.3.4",
|
|
67
|
+
"@jupyterlab/cells": "^4.3.4",
|
|
68
|
+
"@jupyterlab/docmanager": "^4.3.4",
|
|
69
|
+
"@jupyterlab/docregistry": "^4.3.4",
|
|
70
|
+
"@jupyterlab/notebook": "^4.3.4",
|
|
71
|
+
"@jupyterlab/observables": "^5.3.4",
|
|
72
|
+
"@jupyterlab/outputarea": "^4.3.4",
|
|
73
|
+
"@jupyterlab/statedb": "^4.3.4",
|
|
74
|
+
"@jupyterlab/translation": "^4.3.4",
|
|
75
|
+
"@jupyterlab/ui-components": "^4.3.4",
|
|
76
|
+
"@jupyterlite/application-extension": "^0.5.0",
|
|
77
|
+
"@jupyterlite/contents": "^0.5.0",
|
|
78
|
+
"@jupyterlite/server": "^0.5.0",
|
|
79
|
+
"@jupyterlite/settings": "^0.5.0",
|
|
80
|
+
"@lumino/algorithm": "^2.0.1",
|
|
81
|
+
"@lumino/commands": "^2.1.2",
|
|
82
|
+
"@lumino/coreutils": "^2.2.0",
|
|
83
|
+
"@lumino/disposable": "^2.1.3",
|
|
84
|
+
"@lumino/signaling": "^2.1.3",
|
|
85
|
+
"@lumino/widgets": "^2.5.0",
|
|
86
|
+
"json5": "^2.2.3",
|
|
87
|
+
"modern-screenshot": "^4.5.5"
|
|
88
|
+
},
|
|
89
|
+
"devDependencies": {
|
|
90
|
+
"@jupyterlab/builder": "^4.0.0",
|
|
91
|
+
"@jupyterlab/testutils": "^4.0.0",
|
|
92
|
+
"@types/jest": "^29.2.0",
|
|
93
|
+
"@types/json-schema": "^7.0.11",
|
|
94
|
+
"@types/react": "^18.0.26",
|
|
95
|
+
"@types/react-addons-linked-state-mixin": "^0.14.22",
|
|
96
|
+
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
|
97
|
+
"@typescript-eslint/parser": "^6.1.0",
|
|
98
|
+
"css-loader": "^6.7.1",
|
|
99
|
+
"eslint": "^8.36.0",
|
|
100
|
+
"eslint-config-prettier": "^8.8.0",
|
|
101
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
102
|
+
"jest": "^29.2.0",
|
|
103
|
+
"npm-run-all": "^4.1.5",
|
|
104
|
+
"prettier": "^3.0.0",
|
|
105
|
+
"rimraf": "^5.0.1",
|
|
106
|
+
"source-map-loader": "^1.0.2",
|
|
107
|
+
"style-loader": "^3.3.1",
|
|
108
|
+
"stylelint": "^15.10.1",
|
|
109
|
+
"stylelint-config-recommended": "^13.0.0",
|
|
110
|
+
"stylelint-config-standard": "^34.0.0",
|
|
111
|
+
"stylelint-csstree-validator": "^3.0.0",
|
|
112
|
+
"stylelint-prettier": "^4.0.0",
|
|
113
|
+
"typescript": "~5.0.2",
|
|
114
|
+
"yjs": "^13.5.0"
|
|
115
|
+
},
|
|
116
|
+
"sideEffects": [
|
|
117
|
+
"style/*.css",
|
|
118
|
+
"style/index.js"
|
|
119
|
+
],
|
|
120
|
+
"styleModule": "style/index.js",
|
|
121
|
+
"publishConfig": {
|
|
122
|
+
"access": "public"
|
|
123
|
+
},
|
|
124
|
+
"jupyterlab": {
|
|
125
|
+
"extension": true,
|
|
126
|
+
"outputDir": "fails_components_jupyter_applet_view/labextension",
|
|
127
|
+
"schemaDir": "schema"
|
|
128
|
+
},
|
|
129
|
+
"jupyterlite": {
|
|
130
|
+
"liteExtension": false
|
|
131
|
+
},
|
|
132
|
+
"eslintIgnore": [
|
|
133
|
+
"node_modules",
|
|
134
|
+
"dist",
|
|
135
|
+
"coverage",
|
|
136
|
+
"**/*.d.ts",
|
|
137
|
+
"tests",
|
|
138
|
+
"**/__tests__",
|
|
139
|
+
"ui-tests"
|
|
140
|
+
],
|
|
141
|
+
"eslintConfig": {
|
|
142
|
+
"extends": [
|
|
143
|
+
"eslint:recommended",
|
|
144
|
+
"plugin:@typescript-eslint/eslint-recommended",
|
|
145
|
+
"plugin:@typescript-eslint/recommended",
|
|
146
|
+
"plugin:prettier/recommended"
|
|
147
|
+
],
|
|
148
|
+
"parser": "@typescript-eslint/parser",
|
|
149
|
+
"parserOptions": {
|
|
150
|
+
"project": "tsconfig.json",
|
|
151
|
+
"sourceType": "module"
|
|
152
|
+
},
|
|
153
|
+
"plugins": [
|
|
154
|
+
"@typescript-eslint"
|
|
155
|
+
],
|
|
156
|
+
"rules": {
|
|
157
|
+
"@typescript-eslint/naming-convention": [
|
|
158
|
+
"error",
|
|
159
|
+
{
|
|
160
|
+
"selector": "interface",
|
|
161
|
+
"format": [
|
|
162
|
+
"PascalCase"
|
|
163
|
+
],
|
|
164
|
+
"custom": {
|
|
165
|
+
"regex": "^I[A-Z]",
|
|
166
|
+
"match": true
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
],
|
|
170
|
+
"@typescript-eslint/no-unused-vars": [
|
|
171
|
+
"warn",
|
|
172
|
+
{
|
|
173
|
+
"args": "none"
|
|
174
|
+
}
|
|
175
|
+
],
|
|
176
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
177
|
+
"@typescript-eslint/no-namespace": "off",
|
|
178
|
+
"@typescript-eslint/no-use-before-define": "off",
|
|
179
|
+
"@typescript-eslint/quotes": [
|
|
180
|
+
"error",
|
|
181
|
+
"single",
|
|
182
|
+
{
|
|
183
|
+
"avoidEscape": true,
|
|
184
|
+
"allowTemplateLiterals": false
|
|
185
|
+
}
|
|
186
|
+
],
|
|
187
|
+
"curly": [
|
|
188
|
+
"error",
|
|
189
|
+
"all"
|
|
190
|
+
],
|
|
191
|
+
"eqeqeq": "error",
|
|
192
|
+
"prefer-arrow-callback": "error"
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
"prettier": {
|
|
196
|
+
"singleQuote": true,
|
|
197
|
+
"trailingComma": "none",
|
|
198
|
+
"arrowParens": "avoid",
|
|
199
|
+
"endOfLine": "auto",
|
|
200
|
+
"overrides": [
|
|
201
|
+
{
|
|
202
|
+
"files": "package.json",
|
|
203
|
+
"options": {
|
|
204
|
+
"tabWidth": 4
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
"stylelint": {
|
|
210
|
+
"extends": [
|
|
211
|
+
"stylelint-config-recommended",
|
|
212
|
+
"stylelint-config-standard",
|
|
213
|
+
"stylelint-prettier/recommended"
|
|
214
|
+
],
|
|
215
|
+
"plugins": [
|
|
216
|
+
"stylelint-csstree-validator"
|
|
217
|
+
],
|
|
218
|
+
"rules": {
|
|
219
|
+
"csstree/validator": true,
|
|
220
|
+
"property-no-vendor-prefix": null,
|
|
221
|
+
"selector-class-pattern": "^([a-z][A-z\\d]*)(-[A-z\\d]+)*$",
|
|
222
|
+
"selector-no-vendor-prefix": null,
|
|
223
|
+
"value-no-vendor-prefix": null
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|