创建自定义过程块

创建自定义过程块要求您执行以下操作:

  1. 安装 @blockly/block-shareable-procedures使用过程说明中所述, 页面
  2. 使用 JSON 序列化系统,如概览 页面

将数据模型添加到工作区

过程定义和过程调用方块都会引用后备数据 用于定义过程签名的模型(名称、参数和 return)。这可以让您更灵活地设计应用(例如 您可以允许在一个工作区中定义过程,并在一个工作区中引用 另一个)。

这意味着,您需要将过程数据模型添加到工作区 才能正常发挥作用为此,您可以采用多种方式 界面)。

@blockly/block-shareable-procedures 执行此操作 让过程定义块动态创建其支持数据模型 它们会在工作区中被实例化。要自行实现此功能 在 init 中创建模型并在 destroy 中将其删除。

import {ObservableProcedureModel} from '@blockly/block-shareable-procedures';

Blockly.Blocks['my_procedure_def'] = {
  init: function() {
    this.model = new ObservableProcedureModel('default name');
    this.workspace.getProcedureMap().add(model);
    // etc...
  }

  destroy: function() {
    // (Optionally) Destroy the model when the definition block is deleted.

    // Insertion markers reference the model of the original block.
    if (this.isInsertionMarker()) return;
    this.workpace.getProcedureMap().delete(model.getId());
  }
}

返回有关块的信息

您的过程定义和过程调用块需要实现 getProcedureModelisProcedureDefgetVarModels 方法。这些是 钩子 Blockly 代码,用于获取有关过程块的信息。

Blockly.Blocks['my_procedure_def'] = {
  getProcedureModel() {
    return this.model;
  },

  isProcedureDef() {
    return true;
  },

  getVarModels() {
    // If your procedure references variables
    // then you should return those models here.
    return [];
  },
};

Blockly.Blocks['my_procedure_call'] = {
  getProcedureModel() {
    return this.model;
  },

  isProcedureDef() {
    return false;
  },

  getVarModels() {
    // If your procedure references variables
    // then you should return those models here.
    return [];
  },
};

有更新时触发重新渲染

您的过程定义和过程调用块需要实现 doProcedureUpdate 方法结合使用。这是数据模型调用的钩子,用于告知 程序块进行重新渲染

Blockly.Blocks['my_procedure_def'] = {
  doProcedureUpdate() {
    this.setFieldValue('NAME', this.model.getName());
    this.setFieldValue(
        'PARAMS',
        this.model.getParameters()
            .map((p) => p.getName())
            .join(','));
    this.setFieldValue(
        'RETURN', this.model.getReturnTypes().join(',');
  }
};

Blockly.Blocks['my_procedure_call'] = {
  doProcedureUpdate() {
    // Similar to the def block above...
  }
};

添加自定义序列化

过程块的序列化必须执行两项独立的操作。

  1. 从 JSON 加载时,您的块需要获取引用 支持数据模型,因为块和模型是单独序列化的。
  2. 复制并粘贴过程块时,该过程块需要序列化 保留其过程模型的整个状态,以便对其进行复制。

这两项操作均通过 saveExtraStateloadExtraState 处理。 请再次注意,只有在使用 JSON 格式时,才支持自定义过程块 序列化系统,因此我们只需要定义 JSON 序列化钩子。

import {
    ObservableProcedureModel,
    ObservableParameterModel,
    isProcedureBlock
} from '@blockly/block-shareable-procedures';

Blockly.Blocks['my_procedure_def'] = {
  // When doFullSerialization is true, we should serialize the full state of
  // the model.
  saveExtraState(doFullSerialization) {
    const state = Object.create(null);
    state['procedureId']: this.model.getId();

    if (doFullSerialization) {
      state['name'] = this.model.getName();
      state['parameters'] = this.model.getParameters().map((p) => {
        return {name: p.getName(), p.getId()};
      });
      state['returnTypes'] = this.model.getReturnTypes();

      // Flag for deserialization.
      state['createNewModel'] = true;
    }

    return state;
  },

  loadExtraState(state) {
    const id = state['procedureId']
    const map = this.workspace.getProcedureMap();

    if (map.has(id) && !state['createNewModel']) {
      // Delete the existing model (created in init).
      map.delete(this.model.getId());
      // Grab a reference to the model we're supposed to reference.
      this.model = map.get(id);
      this.doProcedureUpdate();
      return;
    }

    // There is no existing procedure model (we are likely pasting), so
    // generate it from JSON.
    this.model
        .setName(state['name'])
        .setReturnTypes(state['returnTypes']);
    for (const [i, param] of state['parameters'].entries()) {
      this.model.insertParameter(
          i,
          new ObservableParameterModel(
              this.workspace, param['name'], param['id']));
    }
    this.doProcedureUpdate();
  },
};

Blockly.Blocks['my_procedure_call'] = {
  saveExtraState() {
    return {
      'procedureId': this.model.getId(),
    };
  },

  loadExtraState(state) {
    // Delete our existing model (created in init).
    this.workspace.getProcedureMap().delete(model.getId());
    // Grab a reference to the new model.
    this.model = this.workspace.getProcedureMap()
        .get(state['procedureId']);
    if (this.model) this.doProcedureUpdate();
  },

  // Handle pasting after the procedure definition has been deleted.
  onchange(event) {
    if (event.type === Blockly.Events.BLOCK_CREATE &&
        event.blockId === this.id) {
      if(!this.model) { // Our procedure definition doesn't exist =(
        this.dispose();
      }
    }
  }
};

(可选)修改过程模型

您还可以添加用户修改手术模型。正在呼叫 insertParameterdeleteParametersetReturnTypes 方法 会自动触发您的块进行重新呈现(通过 doProcedureUpdate)。

用于创建修改过程模型的界面的选项包括: 赋值函数(由 使用内置程序块)、带有点击处理程序的图片字段、 完全位于 Blockly 等对象的外部

向工具箱中添加砌块

Blockly 的内置动态程序类别特定于 Blockly 的内置 过程块。因此,要访问砌块,您需要定义 您的自定义动态 类别,然后将其添加到 工具箱中

const proceduresFlyoutCallback = function(workspace) {
  const blockList = [];
  blockList.push({
    'kind': 'block',
    'type': 'my_procedure_def',
  });
  for (const model of
        workspace.getProcedureMap().getProcedures()) {
    blockList.push({
      'kind': 'block',
      'type': 'my_procedure_call',
      'extraState': {
        'procedureId': model.getId(),
      },
    });
  }
  return blockList;
};

myWorkspace.registerToolboxCategoryCallback(
    'MY_PROCEDURES', proceduresFlyoutCallback);