Shadow block input definition

1,161 views
Skip to first unread message

asd das

unread,
Jun 5, 2019, 3:37:58 AM6/5/19
to Blockly
Hello

I was wondering if it's possible to add a shadow block input (with a value) to a block during definition, either in JavaScript or JSON.

Thanks a lot for any help

Coda Highland

unread,
Jun 5, 2019, 10:32:17 AM6/5/19
to blo...@googlegroups.com
Yep!

I don't know how to do it with JSON because that's a part of the API I haven't taken the time to research, but in Javascript all you have to do is use the standard block APIs in the init() method to create and attach the block, then use setShadow() to turn it into a shadow block.

It's not strictly necessary, though. If you define the shadow blocks in the toolbox XML, then they'll behave exactly as you would want them to behave at runtime. Do you have a particular use case where defining the shadow blocks in the toolbox isn't going to work for you?

One noteworthy caveat about doing it in JS code is that it'll always fire when the block is created, no matter how you do it -- this could _potentially_ cause issues when reloading a saved workspace from XML. You should evaluate this if you try it. I don't think you should have a problem as long as you're using shadow blocks, but automatically creating non-shadow blocks in this manner could have conflicts.

/s/ Adam

--
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/a5999d4e-0988-43b1-8723-cce27b44a37c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

asd das

unread,
Jun 6, 2019, 7:56:53 AM6/6/19
to Blockly
Thanks for the reply Adam.

I think I'm looking for a bit more information though. I have shadow inputs that I'd like to dynamically change when the dropdown value changes. 
I don't have a better example, but lets say we have the following block:

Screenshot from 2019-06-06 13-53-35.png

and if we changed "i" to lets say "String", the shadow values would change as well. Can this be done?

Also, any idea how to add them in the block factory developer tools?


On Wednesday, 5 June 2019 16:32:17 UTC+2, Coda Highland wrote:
Yep!

I don't know how to do it with JSON because that's a part of the API I haven't taken the time to research, but in Javascript all you have to do is use the standard block APIs in the init() method to create and attach the block, then use setShadow() to turn it into a shadow block.

It's not strictly necessary, though. If you define the shadow blocks in the toolbox XML, then they'll behave exactly as you would want them to behave at runtime. Do you have a particular use case where defining the shadow blocks in the toolbox isn't going to work for you?

One noteworthy caveat about doing it in JS code is that it'll always fire when the block is created, no matter how you do it -- this could _potentially_ cause issues when reloading a saved workspace from XML. You should evaluate this if you try it. I don't think you should have a problem as long as you're using shadow blocks, but automatically creating non-shadow blocks in this manner could have conflicts.

/s/ Adam

On Wed, Jun 5, 2019 at 2:38 AM asd das <kontotestow...@gmail.com> wrote:
Hello

I was wondering if it's possible to add a shadow block input (with a value) to a block during definition, either in JavaScript or JSON.

Thanks a lot for any help

--
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 blo...@googlegroups.com.

Coda Highland

unread,
Jun 6, 2019, 12:55:54 PM6/6/19
to blo...@googlegroups.com
I'm not sure how to do that with the dropdown, I'm afraid. Someone else may have an idea.

As far as the block factory is concerned, there's no way to do it directly, but all you have to do is change "block" to "shadow" in the XML. This is documented somewhere but I don't recall where.

/s/ Adam

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/8a212d73-c0ae-45a3-82ce-c10161f94a81%40googlegroups.com.

Beka Westberg

unread,
Jun 6, 2019, 6:22:00 PM6/6/19
to Blockly
Hello,

I worked up a minimal example that I think does what you want. Here's a gif of the block in action.

Blockly.Blocks['shadow_example'] = {
  init
: function() {
   
this.appendValueInput("SHADOW_INPUT")
     
.setCheck(null)
     
.appendField("type:")
     
.appendField(new Blockly.FieldDropdown(
         
[
           
["number", "NUMBER"],
           
["string", "STRING"]
         
], this.updateShape_.bind(this)), "TYPE");
   
this.setInputsInline(true);
   
this.setColour(230);
   
this.updateShape_(this.getFieldValue('TYPE'));
 
},


  updateShape_
: function(type) {
   
var connection = this.getInput('SHADOW_INPUT').connection;
   
var otherConnection;
   
if (connection.isConnected()) {
     
var otherBlock = connection.targetConnection.getSourceBlock();
     
if (otherBlock.isShadow()) {
       
// Don't respawn shadows.
        connection
.setShadowDom(null);
        connection
.disconnect();
        otherBlock
.dispose(false);
     
} else {
       
// Used to reconnect non-shadows later.
        otherConnection
= connection.targetConnection;


       
// This is assuming you don't want to mess with actual blocks that have
       
// been connected (e.g handling types). You could do special handling
       
// here though.
     
}
   
}


   
var dom;
   
switch(type) {
     
case 'NUMBER':
        dom
= Blockly.Xml.textToDom(
         
'<xml>' +
         
'  <shadow type="math_number"></shadow>' +
         
'</xml>');
       
// textToDom expects top level <xml> tags, but setShadowDom expects
       
// top level <shadow> tags. Issue #2029
        dom
= dom.children[0];
       
break;
     
case 'STRING':
        dom
= Blockly.Xml.textToDom(
         
'<xml>' +
         
'  <shadow type="text"></shadow>' +
         
'</xml>').children[0];
       
break;
   
}


    connection
.setShadowDom(dom);
   
// This is a private function, meaning it /is not/ safe to call and may
   
// change in the future.
    connection
.respawnShadow_();


   
if (otherConnection) {
      connection
.connect(otherConnection);
   
}
 
},
};




Note that it does not actually handle setting the input's type (setCheck) I don't think this would be too too tricky to add.

Also note that while it is possible, I don't necessarily recommend this approach as it is fragile (e.g. having to call respawnShadow_() which is a private method). I would try my best to come up with a different UI before commiting to this strategy.

I hope that helps! If you have any further questions please reply!
Beka

P.S: that was a really fun challenge thank you!
Reply all
Reply to author
Forward
0 new messages