Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Cannot set a shadow block to take 'any' input?

20 views
Skip to first unread message

Mark Murawski

unread,
Dec 31, 2024, 12:27:23 PM12/31/24
to blo...@googlegroups.com
Blockly 11.1

Goals:
Create a basic single-input block that's auto connected to a shadow
block that can take any type of input including a default blockly variable

Using the built-in variables category
      <category name="Variables" colour="#a55b80"
css-icon="customIcon_cat_variables" css-row="cat_row"
css-label="cat_label" expanded="false" custom="VARIABLE">
      </category>


And using my handy-dandy helper

Blockly.Custom.appendShadowBlock = function(block_svg, input_name,
block_name, defaultValue) {
  let shadowBlock = block_svg.workspace.newBlock(block_name);

  shadowBlock.setShadow(true);
  shadowBlock.initSvg();
  shadowBlock.render();

  // Note: If we support other types of shadow blocks in the future,
we'll need to monkey this up to support defaults
  shadowBlock.getField("NUM")?.setValue(defaultValue);  // A shadow
block is typically either
  shadowBlock.getField("TEXT")?.setValue(defaultValue); //  a number
input or a text input

  var input = block_svg.getInput(input_name);

  if (!input) {
    alert('Blockly.Custom.appendShadowBlock: Input not found: ' +
input_name + ', In block:' + block_name);
    return;
  }

  let cc = input.connection;
  cc.connect(shadowBlock.outputConnection);
};


And my handy-dandy shadow-block builder-helper (I'm really surprised
something like this doesn't already exist in the API... seems like
everyone asks for it according to google)

Blockly.Custom.DefineBlock = function ( opts ) {
  Blockly.Blocks[opts.type] = {
    init: function() {
      this.jsonInit(opts);

      var self = this; // The block we just defined

      if (opts.args0) {
        opts.args0.forEach((arg) => {
          if (arg.shadow) {
            // (block, block_name, shadowblock_type,
shadowblock_default_value
            Blockly.Custom.appendShadowBlock(self, arg.name,
arg.shadow, arg.value);
          }
        });
      }
    }
  };
};

Blockly.Custom.DefineBlock({
  "type"           : "function_convert_to_number",
  "message0"       : "Convert %1 to Number",
  "colour"         : 330,
  "tooltip"        : "",
  "helpUrl"        : "",
  "args0"          : [{
    "type"   : "input_value",
    "name"   : "VALUE",
    "text"   : "",
    "shadow" : "text",
    "check"  : "String"
  }],
  output : "Number"
});

The above works perfectly fine for connecting a "String" type.  But I'm
unable to connect a blockly default variable created in 'Variables',
because from what I can tell the output type is null, which doesn't
match up with "String".

So... if I change check: to null... or get rid of check: alltogether,
then I get this:

blockly_compressed.js:971 Uncaught Error: Could not connect shadow block
to connection
    at
RenderedConnection$$module$build$src$core$rendered_connection.createShadowBlock
(blockly_compressed.js:971:227)
    at
RenderedConnection$$module$build$src$core$rendered_connection.respawnShadow_
(blockly_compressed.js:965:297)
    at
RenderedConnection$$module$build$src$core$rendered_connection.respawnShadow_
(blockly_compressed.js:1209:147)
    at
RenderedConnection$$module$build$src$core$rendered_connection.setShadowStateInternal
(blockly_compressed.js:970:79)
    at
RenderedConnection$$module$build$src$core$rendered_connection.setShadowDom
(blockly_compressed.js:966:551)
    at applyInputTagNodes$$module$build$src$core$xml
(blockly_compressed.js:306:3)
    at domToBlockHeadless$$module$build$src$core$xml
(blockly_compressed.js:308:325)
    at applyInputTagNodes$$module$build$src$core$xml
(blockly_compressed.js:305:374)
    at domToBlockHeadless$$module$build$src$core$xml
(blockly_compressed.js:308:325)
    at applyInputTagNodes$$module$build$src$core$xml
(blockly_compressed.js:305:374)


And then you wind up with a 'stuck' block in the canvas, that when you
click on it does this:
blockly_compressed.js:737 Uncaught TypeError: Cannot read properties of
null (reading 'isShadow')
    at Gesture$$module$build$src$core$gesture.setTargetBlock
(blockly_compressed.js:737:402)
    at Gesture$$module$build$src$core$gesture.setTargetBlock
(blockly_compressed.js:737:418)
    at Gesture$$module$build$src$core$gesture.setStartBlock
(blockly_compressed.js:737:363)
    at Gesture$$module$build$src$core$gesture.handleBlockStart
(blockly_compressed.js:733:132)
    at BlockSvg$$module$build$src$core$block_svg.onMouseDown_
(blockly_compressed.js:1236:466)
    at SVGGElement.f (blockly_compressed.js:87:149)

Which looks like it's this bug:
https://github.com/google/blockly/issues/4847


Also...
If I set 'check' to null, why should I get a connection error?  One
would think that if you're allowing any kind of input, you can connect a
generic shadow block that didn't define any.
And, as mentioned... a default/standard variable doesn't have an output
type, so in theory it should be able to connect?

Christopher Allen

unread,
Jan 7, 2025, 11:11:45 AMJan 7
to blo...@googlegroups.com
Hi Mark,

Goals:
Create a basic single-input block that's auto connected to a shadow
block that can take any type of input including a default blockly variable

There are very few situations in which we would suggest writing code to create shadow blocks explicitly.  Instead, we recommend that you add preset configurations of blocks (some of which might be shadows) to your toolbox definition.

(One of the few exceptions to this would be if you have a block that is mutable: where the users mutates it to add additional inputs, it might be desirable to dynamically create additional blocks attached to the new inputs—but that does not seem to apply to your situation.)

I would therefore recommend that you replace all of the code you have presented with a toolbox configuration including appropriate pre-arranged groups of blocks (some of which can be shadows) if possible.  (I will nevertheless reply to the remainder of your points, in case it is not.)

And using my handy-dandy helper

Blockly.Custom.appendShadowBlock = function(block_svg, input_name,
block_name, defaultValue) {

An aside: we would discourage you from adding properties (like .Custom) to the Blockly module object.  Normally module objects are immutable and attempting to add properties would fail; it only works here because of some quirks about how we package Bockly + the way your build tooling (e.g. WebPack) works, and it is likely to stop working in a future version of Blockly.  You should instead define your functions in your own module scope / namespace.

And my handy-dandy shadow-block builder-helper (I'm really surprised
something like this doesn't already exist in the API... seems like
everyone asks for it according to google)

We don't provide anything like this because (as noted) we already provide a much simpler way to define shadow blocks using the toolbox.
 
The above works perfectly fine for connecting a "String" type.  But I'm
unable to connect a blockly default variable created in 'Variables',
because from what I can tell the output type is null, which doesn't
match up with "String".

That is certainly curious.  Checking the playground just now, I was able to connect an output connection of with check: null to one with check: ['String'] as expected.  Have you verified the values of the .check properties of the two Connections at runtime?

So... if I change check: to null... or get rid of check: alltogether,
then I get this:

blockly_compressed.js:971 Uncaught Error: Could not connect shadow block
to connection

The call to connect might be failing for various reasons but you are right to suspect that it has to do with the check property.  I would again encourage you to verify the .check properties on the two connections actually have the expected values.

And then you wind up with a 'stuck' block in the canvas, that when you
click on it does this:
blockly_compressed.js:737 Uncaught TypeError: Cannot read properties of
null (reading 'isShadow')

That is broadly expected: we did not intend for shadow blocks to ever appear as top-level blocks on the workspace, so various things go wrong if they ever end up there (which they can sometimes due to the issue that you mention—though usually only in combination with developer code that does something unexpected).
 
Also...
If I set 'check' to null, why should I get a connection error?  One
would think that if you're allowing any kind of input, you can connect a
generic shadow block that didn't define any.

Yes: if either connetion's .check property is null then the two should be able to connect.

And, as mentioned... a default/standard variable doesn't have an output
type, so in theory it should be able to connect?

Yes.

 
Best wishes,

Christopher

Reply all
Reply to author
Forward
0 new messages