Extensions and Mutators

Advanced blocks may use extensions or mutators to be even more dynamic and configurable.

Extensions allow programmatic configuration of blocks, extra initialization, or custom behaviors to be added to blocks. For example, several blocks use the parent_tooltip_when_inline extension to display their parent's tooltip when connected to another block.

A mutator is very similar to an extension; in addition to changing the block, it defines how those changes will be saved to XML and loaded from XML. Mutators may also have additional UI for the user to configure their state. The most recognizable mutator in Blockly is the if block.

Extensions

Extensions are custom configuration or behavior for blocks which can be applied to a block through the block's JSON definition. The extensions for a block are added using the extensions key. Multiple extensions may be applied to a single block.

{
  //...,
  "extensions": ["break_warning_extension", "parent_tooltip_extension"],
}

Because an extension performs work beyond Blockly's default behavior, it must be written once for each platform being used. Each platform includes an API for registering the extension with Blockly. Each extension defines a function to run on block creation. Adding an extension to a block's "extensions" key says that the associated function should be run once on each new block of that type as it is created.

Each extension must be registered through a call to the Blockly library.

JavaScript

Blockly.Extensions.register('parent_tooltip_extension',
  new function() {
    // this refers to the block that the extension is being run on
    this.setTooltip(function() {
      var parent = thisBlock.getParent();
      return (parent && parent.getInputsInline() && parent.tooltip) ||
        Blockly.Msg.MATH_NUMBER_TOOLTIP;
    });
  });

JavaScript also provides a convenience method for extensions that are only a mixin, Blockly.Extensions.registerMixin(name, mixinObj).

Java (Android)

// Extending AbstractBlocklyActivity
@Override
public void configureBlockExtensions() {
  super.configureBlockExtensions(); // Adds the default extensions
  BlockFactory blockFactory = mController.getBlockFactory();
  blockFactory.registerExtension("parent_tooltip_extension",
      new BlockExtension() {
    public void applyTo(Block block) {
      block.setTooltip("Coming soon! issue #531");
    }
  });
}

Swift (iOS)

// In the top level controller after creating the block factory
var extensions = [String: BlockExtension]()
extensions["parent_tooltip_extension"] = BlockExtensionClosure {
  block in try block.tooltip = "Coming soon! issue #319"
}
blockFactory.updateBlockExtensions(extensions)

Mutators

Mutators are the only way to provide custom serializable state on a block. They are declared on a block's JSON definition using the mutator key. Only one mutator may be declared on a block.

{
  //...,
  "mutator": "controls_if_mutator",
}

Registering a mutation

Just like extensions, mutations must be written once for each platform and registered with Blockly.

JavaScript

// JS expects a mixin with all of the required methods
Blockly.Extensions.registerMutator('my_mutator_extension',
  MY_MUTATOR_MIXIN, null,
  // This last argument configures the editor UI on web
  ['my_subblock', 'my_other_subblock']);

Java (Android)

// Extending AbstractBlocklyActivity or BlocklyActivityHelper
public void configureMutators() {
  super.configureMutators(); // Adds the default mutators
  BlockFactory blockFactory = mController.getBlockFactory();
  blockFactory.registerMutator("my_mutator_extension",
      MyMutator.FACTORY);
  // Optionally add a UI for the mutator
  blockFactory.registerMutatorUi("my_mutator_extension",
      MyMutatorFragment.FACTORY);
}

For more details on creating mutators, see the section for the platform you're implementing: