Membuat blok prosedur kustom

Membuat blok prosedur khusus mengharuskan Anda:

  1. Instal @blockly/block-shareable-procedures plugin, seperti yang dijelaskan pada prosedur penggunaan halaman.
  2. Gunakan sistem serialisasi JSON, seperti yang dijelaskan dalam ringkasan halaman kami.

Menambahkan model data ke ruang kerja

Blok definisi prosedur dan pemanggil prosedur mereferensikan data pendukung yang mendefinisikan tanda tangan prosedur (nama, parameter, dan kembali). Hal ini memungkinkan fleksibilitas yang lebih besar dalam mendesain aplikasi (mis. Anda dapat mengizinkan prosedur didefinisikan di satu ruang kerja, dan dirujuk di lainnya).

Ini berarti Anda perlu menambahkan model data prosedur ke ruang kerja agar blok Anda berfungsi. Ada banyak cara untuk melakukannya (mis., kustom UI).

@blockly/block-shareable-procedures melakukannya dengan memiliki blok definisi prosedur yang secara dinamis membuat model data pendukung saat dibuat instance-nya ke ruang kerja. Untuk menerapkannya sendiri, Anda buat model di init dan hapus di 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());
  }
}

Menampilkan informasi tentang blok

Blok panggilan prosedur dan definisi prosedur Anda harus menerapkan Metode getProcedureModel, isProcedureDef, dan getVarModels. Berikut adalah hook yang digunakan oleh Kode Blockly untuk mendapatkan informasi tentang blok prosedur Anda.

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

Memicu rendering ulang saat update

Blok panggilan prosedur dan definisi prosedur Anda harus menerapkan Metode doProcedureUpdate. Inilah hook panggilan model data untuk memberi tahu blok prosedur untuk merender ulang dirinya sendiri.

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

Tambahkan serialisasi kustom

Serialisasi untuk blok prosedur harus melakukan dua hal terpisah.

  1. Saat memuat dari JSON, blok Anda perlu mengambil referensi ke mendukung model data, karena blok dan model diserialisasi secara terpisah.
  2. Saat menyalin dan menempel blok prosedur, blok harus diserialisasi seluruh status model prosedurnya, sehingga dapat direplikasi.

Kedua hal ini ditangani melalui saveExtraState dan loadExtraState. Perhatikan lagi bahwa blok prosedur kustom hanya didukung saat menggunakan JSON sistem serialisasi, jadi kita hanya perlu menentukan hook serialisasi 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();
      }
    }
  }
};

Memodifikasi model prosedur (opsional)

Anda juga dapat menambahkan kemampuan bagi pengguna untuk mengubah model prosedur. Menelepon insertParameter, deleteParameter, atau setReturnTypes metode akan otomatis memicu blok Anda agar dirender ulang (melalui doProcedureUpdate).

Opsi pembuatan UI untuk memodifikasi model prosedur menggunakan mutator (yang penggunaan blok prosedur bawaan), bidang gambar dengan pengendali klik, sesuatu yang sepenuhnya eksternal ke Blockly, dll.

Tambahkan blok ke toolbox

Kategori prosedur dinamis bawaan Blockly adalah khusus untuk alat bawaan Blockly blok prosedur. Agar dapat mengakses blok, Anda perlu menentukan dinamis kustom kategori, dan menambahkannya ke kotak peralatan Anda.

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