Crea bloques de procedimiento personalizados

Para crear bloques de procedimientos personalizados, debes hacer lo siguiente:

  1. Instala @blockly/block-shareable-procedures. como se describe en los procedimientos de uso .
  2. Usa el sistema de serialización JSON, como se explica en la descripción general. .

Agrega modelos de datos al lugar de trabajo

Tanto la definición de procedimiento como los bloques de llamada de procedimientos hacen referencia a datos de copia de seguridad. que define la firma del procedimiento (nombre, parámetros y devolver). Esto permite una mayor flexibilidad en el diseño de tu aplicación (p.ej., podrías permitir que los procedimientos se definan en un espacio de trabajo y se haga referencia a ellos en otro).

Esto significa que deberás agregar los modelos de datos de procedimientos al lugar de trabajo. para que funcionen los bloques. Existen muchas formas de hacer esto (p.ej., a través de IUs).

@blockly/block-shareable-procedures lo hace de la siguiente manera: Hacer que los bloques de definición de procedimientos creen dinámicamente sus modelos de datos de copia de seguridad cuando se crean instancias de estas en el espacio de trabajo. Para implementarlo por tu cuenta, crea el modelo en init y bórralo en 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());
  }
}

Devuelve información sobre los bloques

Tu definición de procedimiento y los bloques de llamada a procedimiento deben implementar el getProcedureModel, isProcedureDef y getVarModels. Estos son los hooks que usa el código de Blockly para obtener información sobre los bloques de tu procedimiento

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 [];
  },
};

Cómo activar la opción para volver a renderizarlas en las actualizaciones

Tu definición de procedimiento y los bloques de llamada a procedimiento deben implementar el doProcedureUpdate. Este es el elemento clave que llaman los modelos de datos para decirle a los para que los bloques de procedimiento se vuelvan a renderizar.

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

Agregar serialización personalizada

La serialización para bloques de procedimiento debe llevar a cabo dos acciones separadas.

  1. Cuando se cargan desde JSON, los bloques deberán tomar una referencia a su modelo de datos de respaldo, ya que los bloques y los modelos se serializan por separado.
  2. Cuando se copia y pega un bloque de procedimiento, este debe serializarse. todo el estado de su modelo de procedimiento para poder replicarlo.

Ambos elementos se controlan mediante saveExtraState y loadExtraState. Ten en cuenta que los bloques de procedimiento personalizados solo se admiten cuando se usa el archivo JSON de serialización, así que solo necesitamos definir los hooks de serialización 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();
      }
    }
  }
};

Modifica el modelo de procedimiento de forma opcional

También puedes agregar la capacidad de que los usuarios modifiquen el modelo de procedimiento. Llamando insertParameter, deleteParameter o setReturnTypes métodos activará automáticamente tus bloqueos para que se vuelvan a renderizar (a través de doProcedureUpdate).

Las opciones para crear IU que permitan modificar el modelo de procedimiento incluyen el uso de mutadores (que los uso de bloques de procedimiento integrados), campos de imagen con controladores de clics, totalmente externos a Blockly, etc.

Agrega bloques a la caja de herramientas

La categoría de procedimiento dinámico integrado de Blockly es específica de la interfaz bloques de procedimiento. Por lo tanto, para poder acceder a los bloques, deberá definir tu propia dinámica personalizada categoría y agregarla a tu caja de herramientas.

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