Tworzenie niestandardowych bloków procedur

Tworzenie bloków procedur niestandardowych wymaga:

  1. Zainstaluj procedurę @blockly/block-shareable-procedures. zgodnie z opisem korzystania z procedury .
  2. Użyj systemu serializacji JSON zgodnie z opisem w omówieniu .
.

Dodawanie modeli danych do obszaru roboczego

Zarówno definicja procedury, jak i bloki wywołującego procedury odwołują się do danych zapasowych model określający podpis procedury (nazwa, parametry i zwrot ). Zapewnia to większą elastyczność w projektowaniu aplikacji (np. możesz zezwolić na definiowanie procedur w jednym obszarze roboczym i odwoływanie się do nich inny).

Oznacza to, że musisz dodać do obszaru roboczego modele danych procedur aby bloki działały. Możesz to zrobić na wiele sposobów (np. wprowadzając UI).

@blockly/block-shareable-procedures: Możliwość dynamicznego tworzenia bazowych modeli danych w blokach definicji procedury gdy są tworzone w obszarze roboczym. Aby wdrożyć to samodzielnie, utwórz model w init i usuń go w 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());
  }
}

Zwróć informacje o blokadach

Definicja procedury i bloki wywołania procedury muszą implementować Metody getProcedureModel, isProcedureDef i getVarModels. Są to punkty zaczepienia używane przez kod Blockly do pobierania informacji o blokach procedur.

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

Aktywuj ponowne renderowanie po aktualizacji

Definicja procedury i bloki wywołania procedury muszą implementować Metoda doProcedureUpdate. Ten punkt zaczepienia wysyła model danych, na ponowne wyrenderowanie treści.

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

Dodaj niestandardową serializację

Serializacja bloków procedur musi wykonać 2 osobne zadania.

  1. Podczas wczytywania z kodu JSON Twoje bloki będą musiały pobrać odwołanie do swoich bazowego modelu danych, ponieważ bloki i modele są serializowane oddzielnie.
  2. Podczas kopiowania i wklejania bloku procedury będzie on musiał zserializować całego stanu modelu swoich procedur, tak aby mógł zostać zreplikowany.

Obie te rzeczy są obsługiwane przez saveExtraState i loadExtraState. Zwróć uwagę, że niestandardowe bloki procedur są obsługiwane tylko w przypadku używania formatu JSON należy zdefiniować tylko punkty zaczepienia serializacji 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();
      }
    }
  }
};

Opcjonalnie zmodyfikuj model procedury

Możesz też dodać możliwość modyfikowania modelu procedury przez użytkowników. Łączę insertParameter, deleteParameter lub setReturnTypes metody spowoduje automatyczne ponowne wyrenderowanie bloków (przy użyciu funkcji doProcedureUpdate).

Opcje tworzenia interfejsów użytkownika w celu modyfikacji modelu procedur obejmują użycie mutatory (które są parametrem z wbudowanymi blokami procedur), pola obrazu z modułami obsługi kliknięć, całkowicie poza Blockly itd.

Dodaj bloki do przyborów

Wbudowana kategoria procedur dynamicznych w Blockly jest związana z wbudowaną usługą Blockly bloki procedury. Aby mieć dostęp do swoich bloków, musisz zdefiniować własne niestandardowe reklamy dynamiczne kategoria i ją dodaj do swojego zestawu narzędzi.

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