Benutzerdefinierte Prozedurblöcke erstellen

Zum Erstellen benutzerdefinierter Prozedurblöcke ist Folgendes erforderlich:

  1. Installieren Sie das Verfahren @blockly/block-shareable-procedures. wie unter Verwendung des Verfahrens beschrieben. Seite.
  2. Verwenden Sie das JSON-Serialisierungssystem, wie in der Übersicht erläutert. .

Datenmodelle zum Arbeitsbereich hinzufügen

Sowohl die Prozedurdefinition als auch die Prozeduraufruferblöcke verweisen auf eine Sicherungsdaten , das die Signatur der Prozedur definiert (Name, Parameter und Return). Dies ermöglicht mehr Flexibilität bei der Entwicklung Ihrer Anwendung (z.B. können Sie Verfahren in einem Arbeitsbereich definieren und in eine andere).

Dies bedeutet, dass Sie die Prozedurdatenmodelle dem Arbeitsbereich hinzufügen müssen damit Ihre Blöcke funktionieren. Dafür gibt es mehrere Möglichkeiten (z.B. Benutzeroberflächen).

Mit der Methode @blockly/block-shareable-procedures geschieht dies durch die Erstellung ihrer unterstützenden Datenmodelle dynamisch in Blöcken für die Prozedurdefinition wenn sie im Arbeitsbereich instanziiert werden. Um dies selbst zu implementieren, das Modell in init erstellen und in destroy löschen.

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

Informationen zu den Blockierungen zurückgeben

Ihre Prozedurdefinition und Ihre Prozeduraufrufblöcke müssen die getProcedureModel-, isProcedureDef- und getVarModels-Methoden. Dies sind die Hooks Der Blockly-Code verwendet den Abruf von Informationen zu Ihren Prozedurblöcken.

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

Erneutes Rendern bei Updates auslösen

Ihre Prozedurdefinition und Ihre Prozeduraufrufblöcke müssen die doProcedureUpdate-Methode. Dies ist der Aufhänger, den Datenmodelle aufrufen, um sich selbst wieder zu rendern.

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

Benutzerdefinierte Serialisierung hinzufügen

Die Serialisierung von Prozedurblöcken muss zwei verschiedene Dinge bewirken.

  1. Beim Laden aus JSON müssen Ihre Blöcke einen Verweis auf ihre da die Blöcke und Modelle separat serialisiert werden.
  2. Beim Kopieren und Einfügen eines Prozedurblocks muss der Block serialisiert werden den gesamten Status seines Prozedurmodells, sodass es repliziert werden kann.

Beide Vorgänge werden über saveExtraState und loadExtraState abgewickelt. Beachten Sie, dass benutzerdefinierte Prozedurblöcke nur unterstützt werden, wenn die JSON-Datei verwendet wird Serialisierungssystem, sodass wir nur JSON-Serialisierungs-Hooks definieren müssen.

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

Optional: Prozedurmodell ändern

Sie können auch die Möglichkeit für Benutzer hinzufügen, das Prozedurmodell zu ändern. Anrufen insertParameter, deleteParameter oder setReturnTypes Methoden löst automatisch das erneute Rendern Ihrer Blöcke aus (über doProcedureUpdate).

Zu den Optionen zum Erstellen von Benutzeroberflächen zum Ändern des Prozedurmodells gehören unter anderem die Verwendung von Mutators (die der Verwendung integrierter Prozedurblöcke), Image-Felder mit Klick-Handlern, vollständig außerhalb von Blockly usw. liegt.

Blöcke zur Toolbox hinzufügen

Die integrierte dynamische Prozedurkategorie von Blockly ist spezifisch für die in Blockly integrierte Prozedurblöcke. Um auf Ihre Blockierungen zugreifen zu können, müssen Sie also Ihre eigenen benutzerdefinierten dynamischen Creatives Kategorie und fügen Sie sie hinzu, zu Ihrer Toolbox hinzufügen.

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