···33 DocumentRegistry,
44 DocumentModel
55} from '@jupyterlab/docregistry';
66+import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
6778import { BlocklyEditor, BlocklyPanel } from './widget';
99+import { BlocklyManager } from './manager';
810911/**
1010- * A widget factory to create new instances of ExampleDocWidget.
1212+ * A widget factory to create new instances of BlocklyEditor.
1113 */
1214export class BlocklyEditorFactory extends ABCWidgetFactory<
1315 BlocklyEditor,
1416 DocumentModel
1517> {
1818+ private _manager: BlocklyManager;
1919+ private _rendermime: IRenderMimeRegistry;
2020+1621 /**
1717- * Constructor of ExampleWidgetFactory.
2222+ * Constructor of BlocklyEditorFactory.
1823 *
1924 * @param options Constructor options
2025 */
2121- constructor(options: DocumentRegistry.IWidgetFactoryOptions) {
2626+ constructor(options: BlocklyEditorFactory.IOptions) {
2227 super(options);
2828+ this._manager = new BlocklyManager();
2929+ this._rendermime = options.rendermime;
3030+ }
3131+3232+ get manager(): BlocklyManager {
3333+ return this._manager;
2334 }
24352536 /**
···3344 ): BlocklyEditor {
3445 return new BlocklyEditor({
3546 context,
3636- content: new BlocklyPanel(context)
4747+ content: new BlocklyPanel(context, this._manager, this._rendermime)
3748 });
3849 }
3950}
5151+5252+export namespace BlocklyEditorFactory {
5353+ export interface IOptions extends DocumentRegistry.IWidgetFactoryOptions {
5454+ /*
5555+ * A rendermime instance.
5656+ */
5757+ rendermime: IRenderMimeRegistry;
5858+ }
5959+}
+26-6
src/index.ts
···33 JupyterFrontEndPlugin,
44 ILayoutRestorer
55} from '@jupyterlab/application';
66-76import { WidgetTracker } from '@jupyterlab/apputils';
77+import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
8899import { BlocklyEditorFactory } from './factory';
1010-1010+import { IBlocklyManager } from './token';
1111import { BlocklyEditor } from './widget';
12121313/**
···1818/**
1919 * Initialization data for the jupyterlab-blocky extension.
2020 */
2121-const plugin: JupyterFrontEndPlugin<void> = {
2121+const plugin: JupyterFrontEndPlugin<IBlocklyManager> = {
2222 id: 'jupyterlab-blocky:plugin',
2323 autoStart: true,
2424- requires: [ILayoutRestorer],
2525- activate: (app: JupyterFrontEnd, restorer: ILayoutRestorer) => {
2424+ requires: [ILayoutRestorer, IRenderMimeRegistry],
2525+ provides: IBlocklyManager,
2626+ activate: (
2727+ app: JupyterFrontEnd,
2828+ restorer: ILayoutRestorer,
2929+ rendermime: IRenderMimeRegistry
3030+ ): IBlocklyManager => {
2631 console.log('JupyterLab extension jupyterlab-blocky is activated!');
27322833 // Namespace for the tracker
···4651 const widgetFactory = new BlocklyEditorFactory({
4752 name: FACTORY,
4853 modelName: 'text',
4949- fileTypes: ['json']
5454+ fileTypes: ['json'],
5555+ defaultFor: ['json'],
5656+5757+ // Kernel options, in this case we need to execute the code generated
5858+ // in the blockly editor. The best way would be to use kernels, for
5959+ // that reason, we tell the widget factory to start a kernel session
6060+ // when opening the editor, and close the session when closing the editor.
6161+ canStartKernel: true,
6262+ preferKernel: true,
6363+ shutdownOnClose: true,
6464+6565+ // The rendermime instance, necessary to render the outputs
6666+ // after a code execution.
6767+ rendermime: rendermime
5068 });
51695270 // Add the widget to the tracker when it's created
···5977 });
6078 // Registering the widget factory
6179 app.docRegistry.addWidgetFactory(widgetFactory);
8080+8181+ return widgetFactory.manager;
6282 }
6383};
6484
+45-30
src/layout.ts
···11-import { Layout, Widget } from '@lumino/widgets';
11+import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
22+import { ISessionContext } from '@jupyterlab/apputils';
2344+import { Message } from '@lumino/messaging';
35import { PartialJSONValue } from '@lumino/coreutils';
44-66+import { PanelLayout, Widget } from '@lumino/widgets';
57import { IIterator, ArrayIterator } from '@lumino/algorithm';
66-77-import { Message } from '@lumino/messaging';
8899import * as Blockly from 'blockly';
10101111-import { TOOLBOX } from './utils';
1111+import { BlocklyManager } from './manager';
12121313/**
1414 * A blockly layout to host the Blockly editor.
1515 */
1616-export class BlocklyLayout extends Layout {
1616+export class BlocklyLayout extends PanelLayout {
1717+ private _host: HTMLElement;
1818+ private _manager: BlocklyManager;
1719 private _workspace: Blockly.WorkspaceSvg;
1818- private _host: HTMLElement;
2020+ private _sessionContext: ISessionContext;
2121+ private _outputArea: Widget;
19222023 /**
2124 * Construct a `BlocklyLayout`.
2225 *
2326 */
2424- constructor() {
2727+ constructor(
2828+ manager: BlocklyManager,
2929+ sessionContext: ISessionContext,
3030+ rendermime: IRenderMimeRegistry
3131+ ) {
2532 super();
2626- console.debug('[BlocklyLayout]');
3333+ this._manager = manager;
3434+ this._sessionContext = sessionContext;
27352836 // Creating the container for the Blockly editor
3737+ // and the output area to render the execution replies.
2938 this._host = document.createElement('div');
3030- this._host.className = 'grid-stack';
3939+ this._outputArea = new Widget();
3140 }
32413342 get workspace(): PartialJSONValue {
···5564 */
5665 init(): void {
5766 super.init();
5858- console.debug('[BlocklyLayout] init');
5967 // Add the blockly container into the DOM
6060- this.parent!.node.appendChild(this._host);
6868+ this.addWidget(new Widget({ node: this._host }));
6169 }
62706371 /**
···7684 return;
7785 }
78868787+ run(): void {
8888+ const code = this._manager.generator.workspaceToCode(this._workspace);
8989+ // Execute the code using the kernel
9090+ }
9191+7992 /**
8093 * Handle `update-request` messages sent to the widget.
8194 */
8295 protected onUpdateRequest(msg: Message): void {
8383- console.debug('[BlocklyLayout] onUpdateRequest');
8484- // TODO: write the resize logic
9696+ this._resizeWorkspace();
8597 }
86988799 /**
88100 * Handle `resize-request` messages sent to the widget.
89101 */
90102 protected onResize(msg: Message): void {
9191- console.debug('[BlocklyLayout] onResize');
9292- // TODO: write the resize logic
9393- const rect = this.parent.node.getBoundingClientRect();
9494- this._host.style.width = rect.width + 'px';
9595- this._host.style.height = rect.height + 'px';
9696- Blockly.svgResize(this._workspace);
103103+ this._resizeWorkspace();
97104 }
9810599106 /**
100107 * Handle `fit-request` messages sent to the widget.
101108 */
102109 protected onFitRequest(msg: Message): void {
103103- console.debug('[BlocklyLayout] onFitRequest');
104104- // TODO: write the resize logic
105105- //
110110+ this._resizeWorkspace();
106111 }
107112108113 /**
109114 * Handle `after-attach` messages sent to the widget.
110115 */
111116 protected onAfterAttach(msg: Message): void {
112112- console.debug('[BlocklyLayout] onAfterAttach');
113117 this._workspace = Blockly.inject(this._host, {
114114- toolbox: TOOLBOX
118118+ toolbox: this._manager.toolbox
115119 });
116120 }
117121118118- /**
119119- * Handle `after-show` messages sent to the widget.
120120- */
121121- protected onAfterShow(msg: Message): void {
122122- console.debug('[BlocklyLayout] onAfterShow');
122122+ private _resizeWorkspace(): void {
123123+ const rect = this.parent.node.getBoundingClientRect();
124124+ const { height } = this._outputArea.node.getBoundingClientRect();
125125+ this._host.style.width = rect.width + 'px';
126126+ const margin = rect.height / 3;
127127+128128+ if (height > margin) {
129129+ this._host.style.height = rect.height - margin + 'px';
130130+ this._outputArea.node.style.height = margin + 'px';
131131+ this._outputArea.node.style.overflowY = 'scroll';
132132+ } else {
133133+ this._host.style.height = rect.height - height + 'px';
134134+ this._outputArea.node.style.overflowY = 'hidden';
135135+ }
136136+137137+ Blockly.svgResize(this._workspace);
123138 }
124139}