Custom Blocks: Block Paradigms

There are several paradigms to choose from when designing an application which uses Blockly. Consideration of these choices should be made early, since they affect the blocks the user will need.

Configuration

Many Blockly applications are used to describe configurations, rather than executable programs. Configuration applications typically start by initializing one root level block on the workspace. A good example is the Block Factory tab of the Blockly Developer Tools:

var xml = '<xml><block type="factory_base" deletable="false" movable="false"></block></xml>';
Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), workspace);

This creates an undeletable, unmovable block that that holds all the user's configuration. The workspace may be exported to XML at any time to determine the current configuration.

Such applications may wish to automatically disable any block not connected to the root block. This can be accomplished on the web version of Blockly with one line:

workspace.addChangeListener(Blockly.Events.disableOrphans);

Serial Program

The majority of Blockly applications are designed to create serial programs. Users stack together blocks which are executed in order.

Every (non-disabled) block on the workspace will form part of the program. If there are multiple stacks of blocks, higher ones are executed first. (If two stacks are approximately the same height, stacks to the left (right in RTL mode) are given priority.)

The workspace may be exported to executable code at any time. This code may be executed client side in JavaScript (using eval or the JS Interpreter), or server side in any language.

var code = Blockly.JavaScript.workspaceToCode(workspace);

Parallel Program

Some Blockly applications choose to execute all stacks of blocks in parallel, rather than serially. An example would be a music application where a drum loop runs concurrently with a melody.

One way of implementing parallel execution is to generate multiple code sections using a headless workspace:

var allXml = Blockly.Xml.workspaceToDom(workspace);
var allCode = [];
for (var i = 0, xml; xml = allXml[i]; i++) {
  var headless = new Blockly.Workspace();
  Blockly.Xml.domToWorkspace(xml, headless);
  allCode.push(Blockly.JavaScript.workspaceToCode(headless));
  headless.dispose();
}

If the target language is JavaScript, the allCode array may then be used to create multiple JS Interpreters for simultaneous execution. If the target language is something like Python, then the allCode array may be assembled into a single program that uses a threading module.

As with any parallel program, careful decisions must me made regarding any shared resources such as variables and functions. A Blockly-specific problem is that there is (currently) no way to highlight more than one block to indicate execution.

Event Driven Program

Event handlers are just functions that get called by the system, rather than by the program. These blocks can either enclose the stack of blocks to be executed, or they may be headers that sit on top of a stack of blocks.

Some developers like to add a 'hat' to the top of event blocks so that they look distinct from other blocks. This is not the default look for Blockly, but it may be added by setting Blockly.BlockSvg.START_HAT = true;

Within an event-driven model, it might make sense to also make a handler for the program start. Under this model, any block on the workspace not connected to an event handler would be ignored and would not execute.

When designing a system that uses events, consider whether it is possible or desirable to support multiple instances of the same event handler.