Crea blocchi di procedure personalizzate

La creazione di blocchi di procedure personalizzate richiede quanto segue:

  1. Installa @blockly/block-shareable-procedures come descritto nelle procedure di utilizzo .
  2. Utilizza il sistema di serializzazione JSON, come spiegato nella panoramica .
di Gemini Advanced.

Aggiungi modelli dei dati all'area di lavoro

Sia la definizione della procedura che i blocchi del chiamante della procedura fanno riferimento a un dato di supporto modello che definisce la firma della procedura (nome, parametri ). Ciò garantisce una maggiore flessibilità nella progettazione dell'applicazione (ad es. puoi consentire di definire le procedure in un'area di lavoro e di fare riferimento in un'altra).

Ciò significa che dovrai aggiungere i modelli dei dati di procedura all'area di lavoro per far funzionare i blocchi. Puoi farlo in molti modi (ad es., modelli UI).

Per farlo, @blockly/block-shareable-procedures avere blocchi di definizione delle procedure creano dinamicamente i propri modelli dei dati di supporto quando viene creata un'istanza nell'area di lavoro. Per implementarlo personalmente, crea il modello in init ed eliminalo in 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());
  }
}

Restituisci informazioni sui blocchi

La definizione e i blocchi di chiamata della procedura devono implementare Metodi getProcedureModel, isProcedureDef e getVarModels. Queste sono le hook Il codice di Blockly utilizza per ottenere informazioni sui blocchi delle procedure.

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

Attiva il rendering agli aggiornamenti

La definizione e i blocchi di chiamata della procedura devono implementare doProcedureUpdate. Questo è l'hook della chiamata dei modelli di dati per indicare blocchi di procedure per eseguire nuovamente il rendering.

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

Aggiungi serializzazione personalizzata

La serializzazione per i blocchi di procedura deve fare due cose separate.

  1. Quando carichi da JSON, i tuoi blocchi dovranno recuperare un riferimento al loro di base, perché i blocchi e i modelli sono serializzati separatamente.
  2. Quando si copia e incolla un blocco di procedura, il blocco deve essere serializzato l'intero stato del modello di procedura, in modo che possa essere replicato.

Entrambi questi aspetti vengono gestiti tramite saveExtraState e loadExtraState. Ricorda che i blocchi di procedure personalizzate sono supportati solo quando si utilizza il formato JSON di serializzazione, quindi dobbiamo solo definire gli hook di serializzazione 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();
      }
    }
  }
};

Facoltativamente, modifica il modello della procedura

Puoi anche consentire agli utenti di modificare il modello di procedura. Chiamata in corso insertParameter, deleteParameter o setReturnTypes metodi attiverà automaticamente il rendering dei tuoi blocchi (tramite doProcedureUpdate).

Le opzioni per creare interfacce utente per modificare il modello di procedura includono l'uso mutatori (che l'uso di blocchi di procedura integrati), campi immagine con gestori di clic, qualcosa completamente esterne a Blockly, ecc.

Aggiungere blocchi agli strumenti

La categoria di procedure dinamiche integrate di Blockly è specifica per la funzionalità integrata di Blockly i blocchi delle procedure. Per poter accedere ai blocchi, devi definire personalizzate dinamiche personalizzate categoria e aggiungila al set di strumenti.

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