Skip to content

Commit 5cee0a7

Browse files
authored
Merge pull request #10 from hbcarlos/manager
Manager
2 parents 3e326e2 + 8343e7f commit 5cee0a7

File tree

8 files changed

+563
-315
lines changed

8 files changed

+563
-315
lines changed

package.json

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,20 @@
4545
"watch:labextension": "jupyter labextension watch ."
4646
},
4747
"dependencies": {
48-
"@jupyterlab/application": "^4.0.0-alpha.4",
49-
"@jupyterlab/apputils": "^4.0.0-alpha.4",
50-
"@jupyterlab/docregistry": "^4.0.0-alpha.4",
48+
"@jupyterlab/application": "^4.0.0-alpha.7",
49+
"@jupyterlab/apputils": "^4.0.0-alpha.7",
50+
"@jupyterlab/docregistry": "^4.0.0-alpha.7",
51+
"@jupyterlab/outputarea": "^4.0.0-alpha.7",
52+
"@jupyterlab/rendermime": "^4.0.0-alpha.7",
53+
"@lumino/algorithm": "^1.9.1",
54+
"@lumino/coreutils": "^1.12.0",
55+
"@lumino/messaging": "^1.10.1",
5156
"@lumino/signaling": "^1.10.1",
52-
"@lumino/widgets": "^1.31.0",
57+
"@lumino/widgets": "^1.31.1",
5358
"blockly": "^7.20211209.2"
5459
},
5560
"devDependencies": {
56-
"@jupyterlab/builder": "^4.0.0-alpha.4",
61+
"@jupyterlab/builder": "^4.0.0-alpha.7",
5762
"@typescript-eslint/eslint-plugin": "^5.12.1",
5863
"@typescript-eslint/parser": "^5.12.1",
5964
"eslint": "^8.9.0",

src/factory.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,23 +3,34 @@ import {
33
DocumentRegistry,
44
DocumentModel
55
} from '@jupyterlab/docregistry';
6+
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
67

78
import { BlocklyEditor, BlocklyPanel } from './widget';
9+
import { BlocklyManager } from './manager';
810

911
/**
10-
* A widget factory to create new instances of ExampleDocWidget.
12+
* A widget factory to create new instances of BlocklyEditor.
1113
*/
1214
export class BlocklyEditorFactory extends ABCWidgetFactory<
1315
BlocklyEditor,
1416
DocumentModel
1517
> {
18+
private _manager: BlocklyManager;
19+
private _rendermime: IRenderMimeRegistry;
20+
1621
/**
17-
* Constructor of ExampleWidgetFactory.
22+
* Constructor of BlocklyEditorFactory.
1823
*
1924
* @param options Constructor options
2025
*/
21-
constructor(options: DocumentRegistry.IWidgetFactoryOptions) {
26+
constructor(options: BlocklyEditorFactory.IOptions) {
2227
super(options);
28+
this._manager = new BlocklyManager();
29+
this._rendermime = options.rendermime;
30+
}
31+
32+
get manager(): BlocklyManager {
33+
return this._manager;
2334
}
2435

2536
/**
@@ -33,7 +44,16 @@ export class BlocklyEditorFactory extends ABCWidgetFactory<
3344
): BlocklyEditor {
3445
return new BlocklyEditor({
3546
context,
36-
content: new BlocklyPanel(context)
47+
content: new BlocklyPanel(context, this._manager, this._rendermime)
3748
});
3849
}
3950
}
51+
52+
export namespace BlocklyEditorFactory {
53+
export interface IOptions extends DocumentRegistry.IWidgetFactoryOptions {
54+
/*
55+
* A rendermime instance.
56+
*/
57+
rendermime: IRenderMimeRegistry;
58+
}
59+
}

src/index.ts

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@ import {
33
JupyterFrontEndPlugin,
44
ILayoutRestorer
55
} from '@jupyterlab/application';
6-
76
import { WidgetTracker } from '@jupyterlab/apputils';
7+
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
88

99
import { BlocklyEditorFactory } from './factory';
10-
10+
import { IBlocklyManager } from './token';
1111
import { BlocklyEditor } from './widget';
1212

1313
/**
@@ -18,11 +18,16 @@ const FACTORY = 'Blockly editor';
1818
/**
1919
* Initialization data for the jupyterlab-blocky extension.
2020
*/
21-
const plugin: JupyterFrontEndPlugin<void> = {
21+
const plugin: JupyterFrontEndPlugin<IBlocklyManager> = {
2222
id: 'jupyterlab-blocky:plugin',
2323
autoStart: true,
24-
requires: [ILayoutRestorer],
25-
activate: (app: JupyterFrontEnd, restorer: ILayoutRestorer) => {
24+
requires: [ILayoutRestorer, IRenderMimeRegistry],
25+
provides: IBlocklyManager,
26+
activate: (
27+
app: JupyterFrontEnd,
28+
restorer: ILayoutRestorer,
29+
rendermime: IRenderMimeRegistry
30+
): IBlocklyManager => {
2631
console.log('JupyterLab extension jupyterlab-blocky is activated!');
2732

2833
// Namespace for the tracker
@@ -46,7 +51,20 @@ const plugin: JupyterFrontEndPlugin<void> = {
4651
const widgetFactory = new BlocklyEditorFactory({
4752
name: FACTORY,
4853
modelName: 'text',
49-
fileTypes: ['json']
54+
fileTypes: ['json'],
55+
defaultFor: ['json'],
56+
57+
// Kernel options, in this case we need to execute the code generated
58+
// in the blockly editor. The best way would be to use kernels, for
59+
// that reason, we tell the widget factory to start a kernel session
60+
// when opening the editor, and close the session when closing the editor.
61+
canStartKernel: true,
62+
preferKernel: true,
63+
shutdownOnClose: true,
64+
65+
// The rendermime instance, necessary to render the outputs
66+
// after a code execution.
67+
rendermime: rendermime
5068
});
5169

5270
// Add the widget to the tracker when it's created
@@ -59,6 +77,8 @@ const plugin: JupyterFrontEndPlugin<void> = {
5977
});
6078
// Registering the widget factory
6179
app.docRegistry.addWidgetFactory(widgetFactory);
80+
81+
return widgetFactory.manager;
6282
}
6383
};
6484

src/layout.ts

Lines changed: 45 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,42 @@
1-
import { Layout, Widget } from '@lumino/widgets';
1+
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
2+
import { ISessionContext } from '@jupyterlab/apputils';
23

4+
import { Message } from '@lumino/messaging';
35
import { PartialJSONValue } from '@lumino/coreutils';
4-
6+
import { PanelLayout, Widget } from '@lumino/widgets';
57
import { IIterator, ArrayIterator } from '@lumino/algorithm';
68

7-
import { Message } from '@lumino/messaging';
8-
99
import * as Blockly from 'blockly';
1010

11-
import { TOOLBOX } from './utils';
11+
import { BlocklyManager } from './manager';
1212

1313
/**
1414
* A blockly layout to host the Blockly editor.
1515
*/
16-
export class BlocklyLayout extends Layout {
17-
private _workspace: Blockly.WorkspaceSvg;
16+
export class BlocklyLayout extends PanelLayout {
1817
private _host: HTMLElement;
18+
private _manager: BlocklyManager;
19+
private _workspace: Blockly.WorkspaceSvg;
20+
private _sessionContext: ISessionContext;
21+
private _outputArea: Widget;
1922

2023
/**
2124
* Construct a `BlocklyLayout`.
2225
*
2326
*/
24-
constructor() {
27+
constructor(
28+
manager: BlocklyManager,
29+
sessionContext: ISessionContext,
30+
rendermime: IRenderMimeRegistry
31+
) {
2532
super();
26-
console.debug('[BlocklyLayout]');
33+
this._manager = manager;
34+
this._sessionContext = sessionContext;
2735

2836
// Creating the container for the Blockly editor
37+
// and the output area to render the execution replies.
2938
this._host = document.createElement('div');
30-
this._host.className = 'grid-stack';
39+
this._outputArea = new Widget();
3140
}
3241

3342
get workspace(): PartialJSONValue {
@@ -55,9 +64,8 @@ export class BlocklyLayout extends Layout {
5564
*/
5665
init(): void {
5766
super.init();
58-
console.debug('[BlocklyLayout] init');
5967
// Add the blockly container into the DOM
60-
this.parent!.node.appendChild(this._host);
68+
this.addWidget(new Widget({ node: this._host }));
6169
}
6270

6371
/**
@@ -76,49 +84,56 @@ export class BlocklyLayout extends Layout {
7684
return;
7785
}
7886

87+
run(): void {
88+
const code = this._manager.generator.workspaceToCode(this._workspace);
89+
// Execute the code using the kernel
90+
}
91+
7992
/**
8093
* Handle `update-request` messages sent to the widget.
8194
*/
8295
protected onUpdateRequest(msg: Message): void {
83-
console.debug('[BlocklyLayout] onUpdateRequest');
84-
// TODO: write the resize logic
96+
this._resizeWorkspace();
8597
}
8698

8799
/**
88100
* Handle `resize-request` messages sent to the widget.
89101
*/
90102
protected onResize(msg: Message): void {
91-
console.debug('[BlocklyLayout] onResize');
92-
// TODO: write the resize logic
93-
const rect = this.parent.node.getBoundingClientRect();
94-
this._host.style.width = rect.width + 'px';
95-
this._host.style.height = rect.height + 'px';
96-
Blockly.svgResize(this._workspace);
103+
this._resizeWorkspace();
97104
}
98105

99106
/**
100107
* Handle `fit-request` messages sent to the widget.
101108
*/
102109
protected onFitRequest(msg: Message): void {
103-
console.debug('[BlocklyLayout] onFitRequest');
104-
// TODO: write the resize logic
105-
//
110+
this._resizeWorkspace();
106111
}
107112

108113
/**
109114
* Handle `after-attach` messages sent to the widget.
110115
*/
111116
protected onAfterAttach(msg: Message): void {
112-
console.debug('[BlocklyLayout] onAfterAttach');
113117
this._workspace = Blockly.inject(this._host, {
114-
toolbox: TOOLBOX
118+
toolbox: this._manager.toolbox
115119
});
116120
}
117121

118-
/**
119-
* Handle `after-show` messages sent to the widget.
120-
*/
121-
protected onAfterShow(msg: Message): void {
122-
console.debug('[BlocklyLayout] onAfterShow');
122+
private _resizeWorkspace(): void {
123+
const rect = this.parent.node.getBoundingClientRect();
124+
const { height } = this._outputArea.node.getBoundingClientRect();
125+
this._host.style.width = rect.width + 'px';
126+
const margin = rect.height / 3;
127+
128+
if (height > margin) {
129+
this._host.style.height = rect.height - margin + 'px';
130+
this._outputArea.node.style.height = margin + 'px';
131+
this._outputArea.node.style.overflowY = 'scroll';
132+
} else {
133+
this._host.style.height = rect.height - height + 'px';
134+
this._outputArea.node.style.overflowY = 'hidden';
135+
}
136+
137+
Blockly.svgResize(this._workspace);
123138
}
124139
}

src/manager.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { JSONObject } from '@lumino/coreutils';
2+
3+
import * as Blockly from 'blockly';
4+
5+
import BlocklyPy from 'blockly/python';
6+
7+
import { IBlocklyManager } from './token';
8+
import { TOOLBOX } from './utils';
9+
10+
export class BlocklyManager implements IBlocklyManager {
11+
private _toolbox: JSONObject;
12+
private _activeGenerator: Blockly.Generator;
13+
private _generators: Map<string, Blockly.Generator>;
14+
15+
/**
16+
* Constructor of BlocklyEditorFactory.
17+
*
18+
* @param options Constructor options
19+
*/
20+
constructor() {
21+
this._toolbox = TOOLBOX;
22+
this._activeGenerator = BlocklyPy;
23+
this._generators = new Map<string, Blockly.Generator>();
24+
}
25+
26+
get toolbox(): JSONObject {
27+
return this._toolbox;
28+
}
29+
30+
set activeGenerator(name: string) {
31+
this._activeGenerator = this._generators.get(name);
32+
}
33+
34+
get generator(): Blockly.Generator {
35+
return this._activeGenerator;
36+
}
37+
38+
registerToolbox(value: JSONObject): void {
39+
this._toolbox = value;
40+
}
41+
42+
registerBlocks(blocks: JSONObject[]): void {
43+
Blockly.defineBlocksWithJsonArray(blocks);
44+
}
45+
46+
registerGenerator(kernel: string, generator: Blockly.Generator): void {
47+
this._generators.set(kernel, generator);
48+
}
49+
}

src/token.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Token } from '@lumino/coreutils';
2+
import { JSONObject } from '@lumino/coreutils';
3+
4+
import * as Blockly from 'blockly';
5+
6+
/**
7+
* The manager token.
8+
*/
9+
export const IBlocklyManager = new Token<IBlocklyManager>(
10+
'jupyterlab-blockly/manager'
11+
);
12+
13+
export interface IBlocklyManager {
14+
registerToolbox(value: JSONObject): void;
15+
registerBlocks(blocks: JSONObject[]): void;
16+
registerGenerator(kernel: string, generator: Blockly.Generator): void;
17+
}

0 commit comments

Comments
 (0)