10

I have done the following block with Blockly in a customBlocks.js file:

Blockly.Blocks['move_right'] = {
  init: function() {
    this.appendValueInput("PIXELS")
        .setCheck("Number")
        .appendField("move to right");
    this.setInputsInline(true);
    this.setPreviousStatement(true, null);
    this.setNextStatement(true, null);
    this.setColour(290);
    this.setTooltip('');
    this.setHelpUrl('http://www.example.com/');
  }
};

Blockly.JavaScript['move_right'] = function(block) {
  var value_pixels = Blockly.JavaScript.valueToCode(block, 'PIXELS', Blockly.JavaScript.ORDER_ATOMIC);
  // TODO: Assemble JavaScript into code variable.
  var codeMoveRight = "$(\"#moveDiv\").animate({\n " + 
                        "left: \"+=" + value_pixels + "px\"\n" +
                      "},1000);\n";  
  return codeMoveRight;
};

that moves a div to the right depending of how much pixels you set on it. You will have to put a math_number block inside move_right block to put the amount of pixels you want to move it.

I have on my html file a workspace variable that injects the Blockly workspace:

var workspace = Blockly.inject('blocklyDiv',
              {toolbox: document.getElementById('toolbox')});

What I want to do

It is to retrieve from JavaScript this amount of pixels one time the block have been displayed on the workspace of Blockly, not before.

What I have tried

  • I directly tried to access to the workspace variable from the console of my broser (Google Chrome) and could get the "child blocks" but not the value of them. As follows:

    console.log(workspace.topBlocks_[0].childBlocks_);
    
  • I also tried to translate the workspace to dom and then to text:

    var xml = Blockly.Xml.workspaceToDom(workspace);
    var xml_text = Blockly.Xml.domToText(xml); 
    console.log(xml_text);
    

    and here I can see that the value of the "child Block", I mean, the math_number block, it is stored on the text but I do not know how can I get it.

Why I want to achieve that?

Because what I want it is to check if the user has moved 300 pixels to the right. If so, then I will show a message in which I will put "You get it!".

My question

Is there a posibility to make an instance of that Block that I have put on the workspace and then get access to its pixels value with that instance?

EDIT:

I also could get the left value as @Oriol said doing:

$('#moveDiv').css('left');

but I did not put it here because it is using a property of Jquery (It does not matter at all, because it is a good option too, but not as intended). My intention it is to get an instance of a Block after put it on the Blockly workspace to operate later with it at any time.

Zoe
  • 27,060
  • 21
  • 118
  • 148
Francisco Romero
  • 12,787
  • 22
  • 92
  • 167
  • Something like `$('#moveDiv').css('left')`? – Oriol Apr 10 '16 at 12:55
  • @Oriol Yes, it was the final conclusion I had (I forgot to update the question, I am going to do it now) but I would like to have an instance of a `Block` to operate with it later. Anyway, thank you for your input :) – Francisco Romero Apr 10 '16 at 13:20

2 Answers2

8

There is a method setWarningText to show this kind of warnings. You could modify yor generator as follows:

Blockly.JavaScript['move_right'] = function(block) {
    var value_pixels = Blockly.JavaScript.valueToCode(block, 'PIXELS', Blockly.JavaScript.ORDER_ATOMIC);
    // TODO: Assemble JavaScript into code variable.
    var codeMoveRight = "$(\"#moveDiv\").animate({\n " + 
                    "left: \"+=" + value_pixels + "px\"\n" +
                  "},1000);\n";

    // You can show a blockly warning
    if( value_pixels >= 300 ) block.setWarningText("You get it!");

    // Or you can store its value elsewere...
    // myExternalVar = value_pixels;

    return codeMoveRight;
};

This will appear as a warning icon in the block itselfs.

In any case, if you want to "remember" this value_pixels variable, I believe the more easy way is to do it in the generator, as shown above. You can always store it in an external var accessible from your custom functions.

EDIT:

If you need to traverse the block structure for some other purpose, you may use:

  • Blockly.mainWorkspace.getTopBlocks(true); // To get the top-level blocks
  • An iteration over the top-level block list
  • block = block.nextConnection && block.nextConnection.targetBlock(); // To "descend" into the sub-blocks of a block, then iterate over them
  • if(block.type=="move_right") ... // To check for a particular block type

I hope this will give a start point, but the best way to learn about these "tricks" is reading the Blockly source code. Even as the code is generally well commented, AFAIK there is no way to autogenerate a document, and it is not available on the web neither.

jrierab
  • 605
  • 5
  • 15
  • Yes, what I want to achieve it is to store the value to use it later. I like your option without need to use `Jquery`. Also I like your `setWarningText` if I need in the future to not to store the value but I wanted to know if it is something similar to get an instance of the Blocks displayed on the workspace. Anyway +1 for both points. If anyone answer, the points will also be for you. Thanks! – Francisco Romero Apr 12 '16 at 11:50
  • I don't undestand completely if you want a reference to this block (you may use the same trick: store it in an external variable) or a list of all the blocks in the workspace... – jrierab Apr 12 '16 at 16:04
  • I tried to get the list of all the blocks in a first instance because I guess than then I could retrieve an instance of the block or something similar. I expect now it will be more clear. – Francisco Romero Apr 12 '16 at 18:16
  • As by the moment it seems that this way it is the only one to get the blocks, I give to you the bounty and I accept your answer until a new better solution will be available. Thank you! – Francisco Romero Apr 18 '16 at 09:16
0

I know this question is somewhat old, but if you still desire more granular access, you should work with blocks IDs (each block has a unique ID).

And, to get block elements, don't forget to define its inputs and fields names so you can refere to them:

example block:

Blockly.Blocks['my_block_unique_name'] = {
    init: function() {
    this.appendDummyInput("this_input_unique_name_for_this_block")
        .appendField("this block do:")
        .appendField(new Blockly.SomeField(...), "this_field_unique_name_for_this_block");
        this.setColour(60);
        this.setTooltip('this block do something');
    }
    //an crude example, be aware that blocks on fyout list will trigger it, if you did not use the block this block is disposed.
    console.log(this.id); 
};

You can use an event to get its ID, store the IDs with some useful info on another place, etc... And so you can do things like:

mainworkspace = Blockly.mainWorkspace
block = mainworkspace.getBlockById(id);
input = block.getInput("imageInput");
// You can use `setField(newValue,name)` too in a more clean way.
input.removeField("FieldImageButton");
input.appendField(new Blockly.SomeField(...), "this_field_unique_name_for_this_block")

And so you can analise the block isInFlyout to see if it is or not used (if it is a block from the openned category or a block dragged out of it, in use), I hope it help you and others.

RomuloPBenedetti
  • 163
  • 2
  • 12