Tạo khối quy trình tuỳ chỉnh

Việc tạo khối quy trình tuỳ chỉnh đòi hỏi bạn phải:

  1. Cài đặt trình bổ trợ @blockly/block-shareable-procedures, như mô tả trên trang quy trình sử dụng.
  2. Sử dụng hệ thống chuyển đổi tuần tự JSON, như giải thích trên trang tổng quan.

Thêm mô hình dữ liệu vào không gian làm việc

Cả khối định nghĩa quy trình và phương thức gọi quy trình đều tham chiếu đến một mô hình dữ liệu sao lưu giúp xác định chữ ký của quy trình (tên, tham số và dữ liệu trả về). Điều này giúp bạn linh hoạt hơn trong cách thiết kế ứng dụng (ví dụ: bạn có thể cho phép các quy trình được xác định trong một không gian làm việc và tham chiếu trong một không gian làm việc khác).

Điều này có nghĩa là bạn sẽ cần thêm mô hình dữ liệu quy trình vào không gian làm việc để các quy trình chặn hoạt động. Có nhiều cách để bạn làm việc này (ví dụ: giao diện người dùng tuỳ chỉnh).

@blockly/block-shareable-procedures thực hiện việc này bằng cách có các khối định nghĩa quy trình tự động tạo mô hình dữ liệu sao lưu khi các mô hình đó được tạo thực thể vào không gian làm việc. Để tự triển khai, bạn cần tạo mô hình trong init và xoá mô hình đó trong 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());
  }
}

Trả về thông tin về các khối

Các khối lệnh gọi quy trình và định nghĩa quy trình cần triển khai các phương thức getProcedureModel, isProcedureDefgetVarModels. Đây là các móc mà mã Blockly sử dụng để lấy thông tin về các khối quy trình của bạn.

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

Kích hoạt quá trình kết xuất lại trên bản cập nhật

Các khối lệnh gọi quy trình và định nghĩa quy trình của bạn cần triển khai phương thức doProcedureUpdate. Đây là thẻ chứa lệnh gọi mô hình dữ liệu để yêu cầu các khối trong quy trình của bạn tự kết xuất lại.

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

Thêm chuỗi tuần tự tuỳ chỉnh

Việc chuyển đổi tuần tự các khối quy trình phải thực hiện hai việc riêng biệt.

  1. Khi tải từ JSON, các khối của bạn sẽ cần lấy tham chiếu đến mô hình dữ liệu sao lưu của chúng, vì các khối và mô hình được chuyển đổi tuần tự riêng biệt.
  2. Khi sao chép và dán một khối quy trình, khối này sẽ cần chuyển đổi tuần tự toàn bộ trạng thái của mô hình quy trình để có thể sao chép được.

Cả hai đều được xử lý thông qua saveExtraStateloadExtraState. Xin lưu ý một lần nữa rằng các khối quy trình tuỳ chỉnh chỉ được hỗ trợ khi sử dụng hệ thống chuyển đổi tuần tự JSON, vì vậy, chúng ta chỉ cần xác định hook chuyển đổi tuần tự 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();
      }
    }
  }
};

Sửa đổi mô hình quy trình (không bắt buộc)

Bạn cũng có thể thêm người dùng có thể sửa đổi mô hình quy trình. Việc gọi phương thức insertParameter, deleteParameter hoặc setReturnTypes sẽ tự động kích hoạt các khối của bạn kết xuất lại (thông qua doProcedureUpdate).

Các tuỳ chọn tạo giao diện người dùng để sửa đổi mô hình quy trình bao gồm sử dụng biến đổi (mà quy trình tích hợp chặn sử dụng), các trường hình ảnh có trình xử lý lượt nhấp, nội dung hoàn toàn nằm ngoài Blockly, v.v.

Thêm khối vào hộp công cụ

Danh mục quy trình động tích hợp sẵn của Blockly là danh mục dành riêng cho các khối quy trình tích hợp sẵn của Blockly. Vì vậy, để có thể truy cập vào các khối, bạn cần xác định danh mục động tuỳ chỉnh của riêng mình và thêm danh mục động đó vào hộp công cụ.

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