undefined dropdowndiv 'textcontent'

116 views
Skip to first unread message

Vitor Souza

unread,
Apr 15, 2024, 11:39:50 AM4/15/24
to Blockly
Hi,

I am injecting Blockly into a div inside a JupyterLab widget as an extension. I have extensions for Python and R languages.

When I run each extension individually (one workspace at a time), it works fine. However, when I run the two widgets at the same time (two workspaces running at the same time) and try to open a dropdown menu (both from Blockly's own blocks and custom blocks), I get the error:
Captura de tela 2024-04-15 123206.png

The error only occurs in the second open widget, in the first one it works fine.

In the second open widget (which in this case, is the second workspace), when I right-click I also get the error:
Captura de tela 2024-04-15 123350.png

Upon creating and injecting the second workspace, it appears that a crucial div is not being generated.

I'd appreciate any guidance or suggestions on how to resolve this issue.

Maribeth Moffatt

unread,
Apr 15, 2024, 12:56:33 PM4/15/24
to Blockly
Hello,

I'm not familiar with building JupyterLab widgets so I'm going to need a bit more information from you.

How are you creating the second workspace? Are you still calling `Blockly.inject`? If you are manually creating a workspace with `new Blockly.WorkspaceSvg()` then you would be missing the steps that handle the dom creation.

Can you share the skeleton of how your HTML structure looks?

The dropdown div and widget div are both treated as singletons. They will be created as elements outside the main Blockly SVG but inside the parent container (usually the document body, but could be an element of your choice if you call `Blockly.common.setParentContainer` before you call `inject`) only if they don't already exist. If you have multiple Blockly workspaces on the same page, there is still only one WidgetDiv and one DropdownDiv element which are used by all workspaces. It's hard to say more about why one of the workspaces wouldn't be able to find these divs without knowing how your page structure looks.

Best,
Maribeth

Vitor Souza

unread,
Apr 15, 2024, 2:16:23 PM4/15/24
to Blockly
Hi Maribeth,

Thanks for your explanation about singleton divs. Here's the relevant code structure for the Python extension:

Python Extension Code:

class BlocklyWidget extends Widget {
  public div: HTMLElement;
  constructor(notebooks: INotebookTracker) {
    super();
    this.notebooks = notebooks;
    this.generator = pythonGenerator;
   
    this.div = document.createElement("div");
    this.div.id = "blocklyDivPython";
    this.node.appendChild(this.div); // Append div to widget's DOM node
  }
  onAfterAttach(): void{
    const this$: BlocklyWidget = this;
    BlocklyWidget__set_workspace(this$, Blockly.inject("blocklyDivPython", {
      toolbox: toolbox,
    }));
    console.log("jupyterlab_blockly_extension_python: blockly palette initialized");
  }
}

export function BlocklyWidget__set_workspace(__: BlocklyWidget, v: Blockly.Workspace): void {
  __["workspace@"] = v;
}


// ... other helper functions and plugin definition

export default pluginPython;



Key Points:

* I'm not directly manipulating the HTML. Each widget has a node property that represents its DOM element.

* I create a new div element with the ID "blocklyDivPython" and append it to the widget's node.

* Inside onAfterAttach, I use Blockly.inject to create the Blockly workspace within this div.

* The R extension follows a similar structure, using "blocklyDivR" as the div ID and RGenerator for code generation (in another file).

* I'm calling Blockly.inject for each widget instance.


I understand that Blockly.inject typically handles DOM creation for the dropdown and widget divs. Since I'm using node.appendChild to manage the div creation within the widget, I might be missing some steps.
Could you advise on any potential issues with this approach, considering the singleton nature of these divs?

Sincerely,
Vitor

Mark Friedman

unread,
Apr 15, 2024, 2:29:42 PM4/15/24
to blo...@googlegroups.com
Hm, I wonder if you are, perhaps, ending up with multiple divs in the same document with the same id (i.e. "blocklyDivPython").  If that's the case, there are a couple of ways to deal with it.
  1. Change the code so that it generates unique IDs.  This is probably the best solution since, in theory, element IDs are supposed to be unique in an HTML doc.
  2. Pass the actual div element, rather than the ID string into the call to Blockly.inject
Hope this helps.

-Mark


--
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/197478c0-2e3e-4cde-b679-a95e33116a20n%40googlegroups.com.

Piper, Zachary Evan

unread,
Apr 17, 2024, 11:48:06 AM4/17/24
to blo...@googlegroups.com
Can you stop emailing me please?

From: blo...@googlegroups.com <blo...@googlegroups.com> on behalf of Mark Friedman <mark.f...@gmail.com>
Sent: Monday, April 15, 2024 2:29:14 PM
To: blo...@googlegroups.com <blo...@googlegroups.com>
Subject: [External] Re: undefined dropdowndiv 'textcontent'
 

This message was sent from a non-IU address. Please exercise caution when clicking links or opening attachments from external sources.

Vitor Souza

unread,
Apr 17, 2024, 12:32:35 PM4/17/24
to Blockly

Hi everyone,

Following up on the previous response I received, I've tried a couple of different solutions:

1. Passing the div directly to blockly.inject: I modified both Python and R files to pass the created div element directly to the Blockly.inject function.

Here's the code snippet for Python (blocklyPython/index.ts):
class BlocklyWidget extends Widget {
  public div: HTMLElement;
  constructor(notebooks: INotebookTracker) {
    super();
    this.div = document.createElement("div");
    this.div.id = "blocklyDivPython";
    this.node.appendChild(this.div); // Append div to widget's DOM node
  }
  onAfterAttach(): void{
    const this$: BlocklyWidget = this;
    BlocklyWidget__set_workspace(this$, Blockly.inject(this.div, {
      toolbox: toolbox,
    }));
  }
}

Here's the code snippet for R (blocklyR/index.ts):
class BlocklyWidget extends Widget {
  public div: HTMLElement;
  constructor(notebooks: INotebookTracker) {
    super();
    this.div = document.createElement("div");
    this.div.id = "blocklyDivR";
    this.node.appendChild(this.div); // Append div to widget's DOM node
  }
  onAfterAttach(): void{
    const this$: BlocklyWidget = this;
    BlocklyWidget__set_workspace(this$, Blockly.inject(this.div, {
      toolbox: toolbox,
    }));
  }
}


2. Using unique IDs for Blockly divs: I ensured both divs (blocklyDivPython and blocklyDivR) have unique IDs to avoid conflicts.

I also examined the generated HTML in the browser and confirmed the presence of the dropdown and widget divs.
Captura de tela 2024-04-17 130840.png

However, when I run the code (both Python and R), including the following line:
BlocklyWidget__set_workspace(this$, Blockly.inject(this.div, {
  toolbox: toolbox,
}));

console.log(Blockly.common.getParentContainer())

I consistently get undefined in the console. I'm unsure if this is the expected behavior.

I further attempted to set the parent container explicitly:
Blockly.common.setParentContainer(document.getElementById("main")!);

BlocklyWidget__set_workspace(this$, Blockly.inject(this.div, {
  toolbox: toolbox,
}));

While this changes the parent container, the original error persists.

I hope this additional information provides more context to my situation. I'm unsure if this issue is related to the error I encounter when opening a dropdown menu.
Thank you for your patience and continued support.

Best,
Vitor

Maribeth Moffatt

unread,
Apr 18, 2024, 1:47:44 PM4/18/24
to Blockly
Hi Vitor,

Thanks for the additional context! Unfortunately I'm still not sure what could be going on. Can you show the HTML that includes the Blockly workspaces too? I don't see them in the screenshot. Maybe the JL widget uses shadow dom? Blockly is not compatible with shadow dom. But even then I'm not sure why it would work for one workspace but not two.

Perhaps using the debugger would help, and we could see where on the page Blockly is looking for the widget/dropdownDivs?

I believe if you never call `setParentContainer` then it's expected that `getParentContainer` returns undefined, in which case we'll just assume the parent container is the document. So I'm not worried about that part.

Maribeth

Vitor Souza

unread,
Apr 23, 2024, 8:07:57 AM4/23/24
to Blockly
Hi Maribeth,

here is the HTML generated by JupyterLab where I'm embedding the Blockly workspaces.
HTML:
Captura de tela 2024-04-23 080645.png

I've also added debugging logs to try to understand the issue better. Here are the logs for Python and R:

Python:
    BlocklyWidget__set_workspace(this$, Blockly.inject(this.div, {
      toolbox: toolbox,
    }));

    console.log("python dropdown div")
    console.log(Blockly.DropDownDiv.getContentDiv())
   
    console.log("python widget div")
    console.log(Blockly.WidgetDiv.getDiv())

R:
    BlocklyWidget__set_workspace(this$, Blockly.inject(this.div, {
      toolbox: toolbox,
    }));

    console.log("R dropdown div")
    console.log(Blockly.DropDownDiv.getContentDiv())
     
    console.log("R widget div")
    console.log(Blockly.WidgetDiv.getDiv())

    console.log("querySelector dropdown div")
    console.log(document.querySelector(".blocklyDropDownDiv"))

here is the output of these logs as well. Interestingly, the dropdown div is found within the Blockly widget for R, even though it's not functional.
Captura de tela 2024-04-23 084634.png

Delving deeper into the Blockly code, I noticed that the createDom function in dropdowndiv.ts is only called once, during the creation of the first workspace. I'm unsure if this is expected behavior.
Additionally, when clicking on the dropdown menu of the first workspace (which functions correctly), the content variable in dropdowndiv.ts has an empty string value (""). This is the same for the second workspace. However, the div variable receives the blocklyDropDownDiv for the first workspace but remains undefined for the second.

I appreciate the attention and support so far. I'm still struggling to resolve this issue.
Thank you for your time and consideration.

Sincerely,
Vitor
Reply all
Reply to author
Forward
0 new messages