Как я могу создать экземпляр блока Blockly с Javascript?

Я сделал следующий блок с Blockly в файле customBlocks.js:

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;
};

который перемещает a div вправо в зависимости от того, сколько пикселей вы установили на нем. Вам нужно будет поместить блок math_number внутри блока move_right, чтобы поместить количество пикселей, которое вы хотите переместить.

У меня на моем html файле a workspace переменная, которая вводит Blockly workspace:

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

Что я хочу сделать

Требуется извлечь из JavaScript это количество пикселей один раз, когда блок был отображен в рабочей области Blockly, а не раньше.

Что я пробовал

  • Я напрямую попытался получить доступ к переменной workspace из консоли моего браузера (Google Chrome) и мог получить "дочерние блоки", но не значение их. Как показано ниже:

    console.log(workspace.topBlocks_[0].childBlocks_);
    
  • Я также попытался перевести рабочее пространство в dom, а затем в текст:

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

    и здесь я вижу, что значение "дочернего блока", я имею в виду, блок math_number, оно сохраняется в тексте, но я не знаю, как его получить.

Почему я хочу достичь этого?

Потому что я хочу, чтобы проверить, переместил ли пользователь 300 пикселей вправо. Если да, тогда я покажу сообщение, в котором я поставлю "Вы его получите!".

Мой вопрос

Есть ли возможность сделать экземпляр этого Блока, который я положил в рабочую область, а затем получить доступ к его пикселю с этим экземпляром?

EDIT:

Я также мог получить значение left, как сказал @Oriol:

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

но я не указал его здесь, потому что он использует свойство Jquery (это вообще не имеет значения, потому что это хороший вариант, но не так, как предполагалось). Мое намерение состоит в том, чтобы получить экземпляр Block после того, как он положил его на Blockly workspace, чтобы работать позже с ним в любое время.

Спасибо заранее!

Ответ 1

Существует метод setWarningText, чтобы показать этот вид предупреждений. Вы можете изменить генератор yor следующим образом:

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;
};

Это будет отображаться как значок предупреждения в самом блоке.

В любом случае, если вы хотите "запомнить" эту переменную value_pixels, я считаю, что более простой способ - сделать это в генераторе, как показано выше. Вы всегда можете сохранить его во внешнем var, доступном из ваших пользовательских функций.

EDIT:

Если вам нужно пересечь структуру блока для какой-либо другой цели, вы можете использовать:

  • Blockly.mainWorkspace.getTopBlocks(true);//Чтобы получить блоки верхнего уровня
  • Итерация по списку блоков верхнего уровня
  • block = block.nextConnection && & block.nextConnection.targetBlock();//Чтобы "спуститься" в подблоки блока, а затем перебрать их
  • if (block.type == "move_right" )...//Чтобы проверить конкретный тип блока

Я надеюсь, что это даст начальную точку, но лучший способ узнать об этих "трюках" - это чтение Blockly исходного кода. Даже когда код, как правило, хорошо комментируется, AFAIK не существует способа автогенерировать документ, и он также не доступен в Интернете.

Ответ 2

Я знаю, что этот вопрос несколько старен, но если вы все еще хотите более детальный доступ, вам следует работать с блоками IDs (каждый блок имеет уникальный ID).

И, чтобы получить элементы блока, не забудьте определить его имена и имена полей, чтобы вы могли ссылаться на них:

Пример блока:

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); 
};

Вы можете использовать событие, чтобы получить его ID, сохранить IDs с некоторой полезной информацией в другом месте и т.д.... И вы можете делать такие вещи, как:

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")

Итак, вы можете проанализировать блок isInFlyout, чтобы узнать, используется ли он или нет (если это блок из открытой категории или блок, вытащенный из него, в использовании), я надеюсь, что это поможет вам и другим.