···1111import { ILauncher } from '@jupyterlab/launcher';
1212import { ITranslator } from '@jupyterlab/translation';
1313import { ISettingRegistry } from '@jupyterlab/settingregistry';
1414+import { IKernelMenu, IMainMenu } from '@jupyterlab/mainmenu';
14151516import { BlocklyEditorFactory } from 'jupyterlab-blockly';
1617import { IBlocklyRegistry } from 'jupyterlab-blockly';
···4849 ISettingRegistry,
4950 ITranslator
5051 ],
5151- optional: [ILauncher, ICommandPalette],
5252+ optional: [ILauncher, ICommandPalette, IMainMenu],
5253 provides: IBlocklyRegistry,
5354 activate: (
5455 app: JupyterFrontEnd,
···5960 settings: ISettingRegistry,
6061 translator: ITranslator,
6162 launcher: ILauncher | null,
6262- palette: ICommandPalette | null
6363+ palette: ICommandPalette | null,
6464+ mainMenu: IMainMenu | null
6365 ): IBlocklyRegistry => {
6466 console.log('JupyterLab extension jupyterlab-blocky is activated!');
6567···8082 }
81838284 const { commands } = app;
8383- const command = CommandIDs.createNew;
84858586 // Creating the widget factory to register it so the document manager knows about
8687 // our new DocumentWidget
···159160 widgetFactory.registry.setlanguage(language);
160161 });
161162162162- commands.addCommand(command, {
163163+ commands.addCommand(CommandIDs.createNew, {
163164 label: args =>
164165 args['isPalette'] ? 'New Blockly Editor' : 'Blockly Editor',
165166 caption: 'Create a new Blockly Editor',
···188189 // Add the command to the launcher
189190 if (launcher) {
190191 launcher.add({
191191- command,
192192+ command: CommandIDs.createNew,
192193 category: 'Other',
193194 rank: 1
194195 });
···197198 // Add the command to the palette
198199 if (palette) {
199200 palette.addItem({
200200- command,
201201+ command: CommandIDs.createNew,
201202 args: { isPalette: true },
202203 category: PALETTE_CATEGORY
203204 });
205205+ }
206206+207207+ // Add the command to the main menu
208208+ if (mainMenu) {
209209+ mainMenu.kernelMenu.kernelUsers.add({
210210+ tracker,
211211+ interruptKernel: current => {
212212+ const kernel = current.context.sessionContext.session?.kernel;
213213+ if (kernel) {
214214+ return kernel.interrupt();
215215+ }
216216+ return Promise.resolve(void 0);
217217+ },
218218+ reconnectToKernel: current => {
219219+ const kernel = current.context.sessionContext.session?.kernel;
220220+ if (kernel) {
221221+ return kernel.reconnect();
222222+ }
223223+ return Promise.resolve(void 0);
224224+ },
225225+ restartKernel: current => {
226226+ const kernel = current.context.sessionContext.session?.kernel;
227227+ if (kernel) {
228228+ return kernel.restart();
229229+ }
230230+ return Promise.resolve(void 0);
231231+ },
232232+ shutdownKernel: current => current.context.sessionContext.shutdown()
233233+ } as IKernelMenu.IKernelUser<BlocklyEditor>);
204234 }
205235206236 return widgetFactory.registry;
+22-23
packages/blockly/src/layout.ts
···4455import { Message } from '@lumino/messaging';
66import { PartialJSONValue } from '@lumino/coreutils';
77-import { PanelLayout, Widget } from '@lumino/widgets';
77+import { SplitLayout, SplitPanel, Widget } from '@lumino/widgets';
88import { IIterator, ArrayIterator } from '@lumino/algorithm';
99import { Signal } from '@lumino/signaling';
1010···1616/**
1717 * A blockly layout to host the Blockly editor.
1818 */
1919-export class BlocklyLayout extends PanelLayout {
2020- private _host: HTMLElement;
1919+export class BlocklyLayout extends SplitLayout {
2020+ private _host: Widget;
2121 private _manager: BlocklyManager;
2222 private _workspace: Blockly.WorkspaceSvg;
2323 private _sessionContext: ISessionContext;
···3232 sessionContext: ISessionContext,
3333 rendermime: IRenderMimeRegistry
3434 ) {
3535- super();
3535+ super({ renderer: SplitPanel.defaultRenderer, orientation: 'vertical' });
3636 this._manager = manager;
3737 this._sessionContext = sessionContext;
38383939 // Creating the container for the Blockly editor
4040 // and the output area to render the execution replies.
4141- this._host = document.createElement('div');
4141+ this._host = new Widget();
42424343 // Creating a CodeCell widget to render the code and
4444 // outputs from the execution reply.
···8383 init(): void {
8484 super.init();
8585 // Add the blockly container into the DOM
8686- this.addWidget(new Widget({ node: this._host }));
8686+ this.addWidget(this._host);
8787+ this.addWidget(this._cell);
8788 }
88898990 /**
···141142 const code =
142143 extra_init + this._manager.generator.workspaceToCode(this._workspace);
143144 this._cell.model.sharedModel.setSource(code);
144144- this.addWidget(this._cell);
145145- this._resizeWorkspace();
146145147146 // Execute the code using the kernel, by using a static method from the
148147 // same class to make an execution request.
···165164 * Handle `update-request` messages sent to the widget.
166165 */
167166 protected onUpdateRequest(msg: Message): void {
167167+ super.onUpdateRequest(msg);
168168 this._resizeWorkspace();
169169 }
170170171171 /**
172172 * Handle `resize-request` messages sent to the widget.
173173 */
174174- protected onResize(msg: Message): void {
174174+ protected onResize(msg: Widget.ResizeMessage): void {
175175+ super.onResize(msg);
175176 this._resizeWorkspace();
176177 }
177178···179180 * Handle `fit-request` messages sent to the widget.
180181 */
181182 protected onFitRequest(msg: Message): void {
183183+ super.onFitRequest(msg);
182184 this._resizeWorkspace();
183185 }
184186···186188 * Handle `after-attach` messages sent to the widget.
187189 */
188190 protected onAfterAttach(msg: Message): void {
191191+ super.onAfterAttach(msg);
189192 //inject Blockly with appropiate JupyterLab theme.
190190- this._workspace = Blockly.inject(this._host, {
193193+ this._workspace = Blockly.inject(this._host.node, {
191194 toolbox: this._manager.toolbox,
192195 theme: THEME
193196 });
197197+198198+ this._workspace.addChangeListener(() => {
199199+ // Get extra code from the blocks in the workspace.
200200+ const extra_init = this.getBlocksToplevelInit();
201201+ // Serializing our workspace into the chosen language generator.
202202+ const code =
203203+ extra_init + this._manager.generator.workspaceToCode(this._workspace);
204204+ this._cell.model.sharedModel.setSource(code);
205205+ });
194206 }
195207196208 private _resizeWorkspace(): void {
197209 //Resize logic.
198198- const rect = this.parent.node.getBoundingClientRect();
199199- const { height } = this._cell.node.getBoundingClientRect();
200200- const margin = rect.height / 3;
201201-202202- if (height > margin) {
203203- this._host.style.height = rect.height - margin + 'px';
204204- this._cell.node.style.height = margin + 'px';
205205- this._cell.node.style.overflowY = 'scroll';
206206- } else {
207207- this._host.style.height = rect.height - height + 'px';
208208- this._cell.node.style.overflowY = 'scroll';
209209- }
210210-211210 Blockly.svgResize(this._workspace);
212211 }
213212
+2-2
packages/blockly/src/widget.ts
···66import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
77import { runIcon } from '@jupyterlab/ui-components';
8899-import { Panel } from '@lumino/widgets';
99+import { SplitPanel } from '@lumino/widgets';
1010import { Signal } from '@lumino/signaling';
11111212import { BlocklyLayout } from './layout';
···7676/**
7777 * Widget that contains the main view of the DocumentWidget.
7878 */
7979-export class BlocklyPanel extends Panel {
7979+export class BlocklyPanel extends SplitPanel {
8080 private _context: DocumentRegistry.IContext<DocumentModel>;
81818282 /**