Пользовательские блоки: парадигмы блоков

При разработке приложения, использующего Blockly, можно выбирать из нескольких парадигм. Рассмотрение этих вариантов следует сделать заранее, поскольку они влияют на блоки, которые понадобятся пользователю.

Конфигурация

Многие приложения Blockly используются для описания конфигураций, а не исполняемых программ. Приложения конфигурации обычно начинаются с инициализации одного блока корневого уровня в рабочей области. Хорошим примером является вкладка Block Factory в Blockly Developer Tools:

Blockly.Blocks['factory_base'] = {
  init: function() {
    this.setDeletable(false);
    this.setMovable(false);
    this.setEditable(false);
    // etc...
  }
}

Blockly.serialization.blocks.append({'type': 'factory_base'}, workspace);

При этом создается неудаляемый, неподвижный блок, в котором хранится вся конфигурация пользователя. Рабочая область может быть сериализована в любое время для определения текущей конфигурации.

Такие приложения могут захотеть автоматически отключить любой блок, не связанный с корневым блоком. Это можно сделать одной строкой:

workspace.addChangeListener(Blockly.Events.disableOrphans);

Серийная программа

Большинство приложений Blockly предназначены для создания серийных программ. Пользователи складывают блоки, которые выполняются по порядку.

Каждый (не отключенный) блок в рабочей области будет частью программы. Если имеется несколько стеков блоков, сначала выполняются более высокие. (Если две стопки примерно одинаковой высоты, приоритет отдается стопкам слева (справа в режиме RTL).)

Рабочая область может быть экспортирована в исполняемый код в любое время. Этот код может быть выполнен на стороне клиента в JavaScript (с использованием eval или интерпретатора JS) или на стороне сервера на любом языке.

import {javascriptGenerator} from 'blockly/javascript';

var code = javascriptGenerator.workspaceToCode(workspace);

Параллельная программа

Некоторые приложения Blockly предпочитают выполнять все стеки блоков параллельно, а не последовательно. Примером может служить музыкальное приложение, в котором одновременно с мелодией запускается барабанная петля.

Один из способов реализации параллельного выполнения — генерировать код для каждого блока индивидуально:

import {javascriptGenerator} from 'blockly/javascript';

var json = Blockly.serialization.workspaces.save(workspace);

// Store top blocks separately, and remove them from the JSON.
var blocks = json['blocks']['blocks'];
var topBlocks = blocks.slice();  // Create shallow copy.
blocks.length = 0;

// Load each block into the workspace individually and generate code.
var allCode = [];
var headless = new Blockly.Workspace();
for (var i = 0; block < topBlocks.length; i++) {
  var block = topBlocks[i];
  blocks.push(block);
  Blockly.serialization.workspaces.load(json, headless);
  allCode.push(javascriptGenerator.workspaceToCode(headless));
  blocks.length = 0;
}

Если целевым языком является JavaScript, массив allCode можно затем использовать для создания нескольких интерпретаторов JS для одновременного выполнения. Если целевой язык похож на Python, то массив allCode можно собрать в одну программу, использующую модуль потоковой обработки.

Как и в любой параллельной программе, необходимо принимать осторожные решения в отношении любых общих ресурсов, таких как переменные и функции.

Программа, управляемая событиями

Обработчики событий — это просто функции, которые вызываются системой, а не программой. Эти блоки могут либо включать в себя стек блоков, подлежащих выполнению, либо представлять собой заголовки, расположенные поверх стека блоков.

Некоторым разработчикам нравится добавлять «шляпу» вверху блоков событий, чтобы они отличались от других блоков. Это не внешний вид Blockly по умолчанию, но его можно добавить, переопределив константу рендеринга ADD_START_HATS на true ( кодовая лаборатория пользовательских рендереров — Переопределить константы ). или добавив тему и установив опцию шляпы в стиле блока. Более подробную информацию по установке шапок на блоках в рамках тем можно найти здесь .

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

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