cannot dispose minimap

133 views
Skip to first unread message

Seb Seb

unread,
Sep 10, 2023, 1:00:05 PM9/10/23
to Blockly
Hi,
as I'm wokring on modifying renderer on blockly workspace, my only solution was to dispose workspace and inject it again.
I create minimap:
const minimap = new PositionedMinimap(workspace);
minimap.init();

And to dispose:
minimap.dispose();

But doing this, the  plugin breaks with a "this.focusRegion is undefined.".
Am I wrong?
Thanks for helping.

Beka Westberg

unread,
Sep 11, 2023, 1:14:16 PM9/11/23
to Blockly
Hello!

I was not able to reproduce this error :/ Could you post your full code + the full text of your error?

Hopefully with a bit more info we can get this sorted!

Best wishes,
--Beka

Seb Seb

unread,
Sep 11, 2023, 5:50:19 PM9/11/23
to Blockly
Hello, dammit, it's a problem with my code? I hope no... In my code I added many plugins and I fear they create conflicts...
I added a checkbox to ini or dispose plugin.

My error debug from webpack:
this.focusRegion is undefined 339/s</t.prototype.isFocusEnabled@webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:5449 339/s</t.prototype.dispose@webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:3838 setupWorkspacePlugins@webpack-internal:///./src/index.ts:6258:29 rebootWorkspace@webpack-internal:///./src/index.ts:6244:26 changeRenderer@webpack-internal:///./src/index.ts:5902:5 HTMLonChange/rendererMenu.onchange@webpack-internal:///./src/index.ts:6208:40

I tried to put 2 plugins on same checkbox :
const pluginHighlightCheck = <HTMLInputElement>document.getElementById('pluginHighlight');
  pluginHighlightCheck.onchange = () => {
    pluginHighlightCheck.checked ? contentHighlight.init() : contentHighlight.dispose();
    if (pluginHighlightCheck.checked) {
      minimap = new PositionedMinimap(µcB.workspace);
      minimap.init(µcB.workspace);
    } else minimap.dispose();

So I can create the 2 plugins, dispose it but cannot check again:
Plugin "minimap" with capabilities "positionable" already added. addComponent@webpack-internal:///./node_modules/blockly/blockly_compressed.js:806:235 245/s</i.prototype.init@webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:6339 HTMLonChange/pluginHighlightCheck.onchange@webpack-internal:///./src/index.ts:6228:21 EventHandlerNonNull*HTMLonChange@webpack-internal:///./src/index.ts:6224:5 window.onload@webpack-internal:///./src/index.ts:6340:5 EventHandlerNonNull*@webpack-internal:///./src/index.ts:6325:1 ./src/index.ts@http://localhost:8080/bundle.js:418:1 __webpack_require__@http://localhost:8080/bundle.js:552:33 @http://localhost:8080/bundle.js:1633:56 @http://localhost:8080/bundle.js:1635:12

Any idea is welcome, thanks a lot.

Seb Seb

unread,
Sep 11, 2023, 6:32:51 PM9/11/23
to Blockly
Well in fact it works, but I had to look after this plugin in a special way.
Sorry for the mistake.
However if I want to change workspace render, how can I change minimap'sone ? and theme too?
Many thanks.

Beka Westberg

unread,
Sep 11, 2023, 7:07:07 PM9/11/23
to Blockly
Hello =)

The minimap will automatically mirror the theme of the main workspace, but it looks like we're not doing the same for the renderer. I've filed an issue for this.

Best wishes,
--Beka

Seb Seb

unread,
Sep 12, 2023, 10:10:42 AM9/12/23
to Blockly
Thanks a lot!

Seb Seb

unread,
Sep 18, 2023, 6:33:46 AM9/18/23
to Blockly
Sorry to reopen this problem...
I tried as in minimap plugin demo to change theme, but when I do it the minimap as the same first theme, not the same as main workspace.
And trying to change renderer, as you explained Becka, this my relaucnh workspace scenarii:
  1. save workspace blocks
  2. dispose minimap plugin
  3. dispose workspace
  4. change renderer
  5. inject workspace
  6. recreate objct minimap linked to the new workspace
  7. init minimap object
But I have a problem with link between main workspace and minimap, as explained in video, do you have any idea? I Really have no clue at all...
Thanks a lot.
chrome_YsrwG7WUTc.mp4

Seb Seb

unread,
Sep 18, 2023, 6:37:17 AM9/18/23
to Blockly
Sorry, wrong video, here's the good one.
chrome_NSvSRiILY4.mp4

Beka Westberg

unread,
Sep 18, 2023, 8:59:34 AM9/18/23
to blo...@googlegroups.com
Hello!

Looks like the error is happening in your index.js `update` method. Could you share the code that's running there?

Hopefully with a bit more info we can get this sorted =)
--Beka

--
You received this message because you are subscribed to the Google Groups "Blockly" group.
To unsubscribe from this group and stop receiving emails from it, send an email to blockly+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/blockly/89299ba8-608b-42ed-a478-5d8fffe672c4n%40googlegroups.com.

Seb Seb

unread,
Sep 18, 2023, 10:48:52 AM9/18/23
to Blockly
Hello,
Maybe it's simplier than copy-paste a lot of code?
Tell me if you prefer copy-paste code here.

Beka Westberg

unread,
Sep 18, 2023, 12:44:30 PM9/18/23
to blo...@googlegroups.com
Hello! I can't seem to find the `update` method that is throwing the error in your video :/ Could you click on the link in your browser console and then share the code that it's pointing to?

Best wishes,
--Beka

Seb Seb

unread,
Sep 18, 2023, 6:00:58 PM9/18/23
to Blockly
Hello,
thanks for your help. So first a language dropdown menu change launch this function (https://github.com/A-S-T-U-C-E/ucBlockly/blob/main/src/options.ts#L50):

export const changeRenderer = (app: BlocklyApplicationType, renderNew: string = (document.getElementById('rendererMenu') as HTMLSelectElement).value): string => {
  app.WORKSPACE_OPTIONS['renderer'] = renderNew;
  workspaceReboot(app);
  window.history.pushState({}, "µcB", addReplaceParamToUrl(window.location.search, "renderer", renderNew));
  return renderNew;
}

The options are part of the BlocklyApplicationType  (https://github.com/A-S-T-U-C-E/ucBlockly/blob/main/src/index.ts#L50):
WORKSPACE_OPTIONS = {
  grid:
  {
    spacing: 20,
    length: 3,
    colour: '#ccc',
    snap: true
  },
  scrollbars: true,
  toolbox: µcB.toolbox,
  zoom:
  {
    controls: true,
    wheel: true,
    startScale: 1.0,
    maxScale: 6,
    minScale: 0.1,
    scaleSpeed: 1.2,
    pinch: true
  },
  trashcan: true,
}

export const workspaceReboot = (app: BlocklyApplicationType): void => {
  workspaceSaveBlocks(app.workspace, 'mainWorkspace_blocks');
  workspaceSetupPlugins(app.workspace, true);
  app.workspace.dispose();
  app.workspace = Blockly.inject(div_workspace_content_blockly, app.WORKSPACE_OPTIONS);
  workspaceSetupPlugins(app.workspace, false);
  workspaceLoadBlocks(app.workspace, 'mainWorkspace_blocks');
  (app.workspace as Blockly.WorkspaceSvg).scrollCenter();
}

export const workspaceSaveBlocks = function(workspace: Blockly.Workspace, storageKeyWorkspaceBlocks: string) {
  const data = Blockly.serialization.workspaces.save(workspace);
  window.sessionStorage?.setItem(storageKeyWorkspaceBlocks, JSON.stringify(data));
};

export const workspaceLoadBlocks = function(workspace: Blockly.Workspace, storageKeyWorkspaceBlocks: string) {
  const data = window.sessionStorage?.getItem(storageKeyWorkspaceBlocks);
  if (!data) return;

  // Don't emit events during loading.
  Blockly.Events.disable();
  Blockly.serialization.workspaces.load(JSON.parse(data), workspace);
  Blockly.Events.enable();
};

I define plugin object as global object/variable to (re)use it when I need (https://github.com/A-S-T-U-C-E/ucBlockly/blob/main/src/index.ts#L110):
const plugin_KeyboardNav = new NavigationController();
let plugin_contentHighlight = new ContentHighlight();
let plugin_minimap = new PositionedMinimap();
let plugin_modal = new Modal();
let plugin_workspaceSearch = new WorkspaceSearch();
let plugin_zoomToFit = new ZoomToFitControl();

export const workspaceSetupPlugins = (workspace: Blockly.Workspace, disposePlugin: boolean = false): void => {
  const backpackOptions = {
    allowEmptyBackpackOpen: true,
    useFilledBackpackImage: true,
    skipSerializerRegistration: false,
    contextMenu: {
      emptyBackpack: true,
      removeFromBackpack: true,
      copyToBackpack: true,
      copyAllToBackpack: true,
      pasteAllToBackpack: true,
      disablePreconditionChecks: true,
    },
  };
  const plugin_backpack = new Backpack(workspace as Blockly.WorkspaceSvg, backpackOptions);
  plugin_contentHighlight = new ContentHighlight(workspace);
  plugin_modal = new Modal(workspace);
  plugin_workspaceSearch = new WorkspaceSearch(workspace);
  plugin_zoomToFit = new ZoomToFitControl(workspace);

  const pluginHighlightCheck = <HTMLInputElement>document.getElementById('pluginHighlight');
  const pluginMinimap = <HTMLInputElement>document.getElementById('pluginMinimap');
  if (disposePlugin) {
    µcB.workspace.addChangeListener(shadowBlockConversionChangeListener);
    plugin_KeyboardNav.dispose();
    plugin_backpack.dispose();
    if (pluginHighlightCheck.checked) {
      plugin_contentHighlight.dispose();
      pluginHighlightCheck.checked = false;
    }
    plugin_minimap.dispose();
    pluginMinimap.checked = false;
    plugin_modal.dispose();
    plugin_workspaceSearch.dispose();
    plugin_zoomToFit.dispose();
  } else {
    µcB.workspace.removeChangeListener(shadowBlockConversionChangeListener);
    plugin_KeyboardNav.init();
    plugin_KeyboardNav.addWorkspace(workspace);
    plugin_backpack.init();
    if (pluginHighlightCheck.checked) {
      plugin_contentHighlight.init();
    }
    //particular to this plugin
    plugin_minimap = new PositionedMinimap(workspace);
    plugin_minimap.init();
    pluginMinimap.checked = true;
    plugin_modal.init();
    plugin_workspaceSearch.init();
    plugin_zoomToFit.init();
  }
  /* it seems there's conflict with nav keyboard copy function
  const options = {
    contextMenu: true,
    shortcut: true
  }
  const crossTabCopyPastePlugin = new CrossTabCopyPaste();
  crossTabCopyPastePlugin.init(options);*/
}

I hope it could help understand why I did.

Beka Westberg

unread,
Sep 19, 2023, 9:43:58 AM9/19/23
to blo...@googlegroups.com
Hello!

Ok I pulled down your code to dig into it and figured out the issue =) You have to leave events enabled during loading, otherwise the minimap won't mirror your changes. This was causing the primary workspace content to be different from the minimap workspace content, which was causing the transform error.

So you need to modify your workspaceLoadBlocks function:

```
export const workspaceLoadBlocks = function(workspace: Blockly.Workspace, storageKeyWorkspaceBlocks: string) {
  const data = window.sessionStorage?.getItem(storageKeyWorkspaceBlocks);
  if (!data) return;
  Blockly.serialization.workspaces.load(JSON.parse(data), workspace);
};

```

I hope that helps! If you run into any further issues please reply!
--Beka

Seb Seb

unread,
Sep 19, 2023, 10:18:15 AM9/19/23
to Blockly
Hello Beka,
thank you very much, it's very kind of you to test my code!

I had copied this serialization code from the sample-app-ts example and I had also tried to remove the Blockly.Events, but this seems to destroy the link between the workspace and the minimap (see text in yellow below): when I change the size of the workspace (resizable) it constantly generates an error. And the browsers don't give the same information:
- in chromium it displays :
Cannot read properties of null (reading 'setAttribute')
TypeError: Cannot read properties of null (reading 'setAttribute')
    at i.setAttributes (webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:7784)
    at i.position (webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:6677)
    at WorkspaceSvg$$module$build$src$core$workspace_svg.resize (webpack-internal:///./node_modules/blockly/blockly_compressed.js:1386:80)
    at Object.svgResize$$module$build$src$core$common [as svgResize] (webpack-internal:///./node_modules/blockly/blockly_compressed.js:68:417)
    at HTMLBodyElement.eval (webpack-internal:///./src/index.ts:6469:17)

- in Firefox this displays :
this.minimapWorkspace.getInjectionDiv().parentElement is null
245/s</i.prototype.setAttributes@webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:7753
245/s</i.prototype.position@webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:6677
resize@webpack-internal:///./node_modules/blockly/blockly_compressed.js:1386:80
svgResize$$module$build$src$core$common@webpack-internal:///./node_modules/blockly/blockly_compressed.js:68:417
HTML_addFlexResizerEvents/<@webpack-internal:///./src/index.ts:6469:17

And also, the right part, whic contains the javascript code, cannot be reduced at all, like it is when you launch index.
Thanks a lot for your help!

Maribeth Moffatt

unread,
Sep 20, 2023, 2:20:30 PM9/20/23
to Blockly
Hi, I'm jumping in on this issue since I'm on call for this week. 

I'm trying to catch up on what the issue is but I can't reproduce it.

Here's what I've done:

1) Cloned your repository
2) Ran npm install --force (to resolve peer dependency issues with one of your deps)
3) Ran npm run dev to start the server
4) Drag blocks onto the workspace, minimap works fine. Refresh the page, minimap breaks <-- this is what Beka debugged previously
5) Change the `workspaceLoadBlocks` function to be what Beka suggested.
6) Drag blocks onto the workspace, minimap works fine. Refresh the page, minimap still works fine. Change the renderer, minimap still works fine. So it appears to me that Beka's change above fixed the issue.

I'm not able to reproduce the error you've shown here. Can you provide me with reproduction steps, or a branch that has the code you're trying now?

Thanks!
Maribeth

Seb Seb

unread,
Sep 20, 2023, 3:43:46 PM9/20/23
to Blockly
Hi,
thanks a lot for your test, very kind.
The error occurs when you try to modify the resizable workspace, using the vertical and horizontal sliders. My UI needs the code vizualisation and a "console" at bottom, like in Arduino IDE.
That's great if you can help, thanks.

Maribeth Moffatt

unread,
Sep 20, 2023, 3:47:14 PM9/20/23
to Blockly
Using the sliders also works fine for me, both before and after reloading the page / changing the renderer / etc. Can you double check anything else you've changed other than the change to the `load` function?

Maribeth

Seb Seb

unread,
Sep 20, 2023, 5:43:56 PM9/20/23
to Blockly
Totally weird!!! I did like you (cloned on another PC/Windows, typed "npm install --force" and "npm run dev"), and I still have error on Chromium v 117.0.5938.89, on moving slide bars after modify the render:
Cannot read properties of null (reading 'setAttribute') TypeError: Cannot read properties of null (reading 'setAttribute') at i.setAttributes (webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:7784) at i.position (webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:6677) at WorkspaceSvg$$module$build$src$core$workspace_svg.resize (webpack-internal:///./node_modules/blockly/blockly_compressed.js:1386:80) at Object.svgResize$$module$build$src$core$common [as svgResize] (webpack-internal:///./node_modules/blockly/blockly_compressed.js:68:417) at HTMLBodyElement.eval (webpack-internal:///./src/index.ts:6466:17)

On Firefox v107.0.1:
this.minimapWorkspace.getInjectionDiv().parentElement is null 245/s</i.prototype.setAttributes@webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:7753 245/s</i.prototype.position@webpack-internal:///./node_modules/@blockly/workspace-minimap/dist/index.js:2:6677 resize@webpack-internal:///./node_modules/blockly/blockly_compressed.js:1386:80 svgResize$$module$build$src$core$common@webpack-internal:///./node_modules/blockly/blockly_compressed.js:68:417 HTML_addFlexResizerEvents/<@webpack-internal:///./src/index.ts:6466:17

I don't think browser nor OS can be the problem source...
I posted a video to show you what I did, hope this helps: https://youtu.be/MJPwUzykFeQ

Maribeth Moffatt

unread,
Sep 20, 2023, 6:33:33 PM9/20/23
to Blockly
OK, I was able to reproduce the problem -- I must have missed a step before.

This error is occurring because in your `HTML_addFlexResizerEvents` you have an event handler that calls `Blockly.svgResize` on the workspace that is passed into the function. However, you never update this event handler after you tear down and re-inject the workspace. So when you do change the renderer and create a new workspace and then activate the event listener by dragging the flex resizers, it is trying to call `Blockly.svgResize` on the outdated workspace reference. If you change that code to call µcB.workspace instead of the one passed into the function, it has the most up-to-date reference to the workspace and it works correctly. 

I hope that helps,
Maribeth

Seb Seb

unread,
Sep 20, 2023, 7:12:35 PM9/20/23
to Blockly
WONDERFUL!!!! Tricky advice, thanks a lot !!! I'd never have found it!
I'll continue struggle with bugs :-D
I discovered a funny one: when adding blocks, I cannot totally fold back the right part with code, and when I delete all blocks it gets back.
And the block-plus-minus plugin does not works,
Well it will be another task...thanks again.
Reply all
Reply to author
Forward
0 new messages