การสร้างบล็อกกระบวนการที่กําหนดเอง

หากต้องการสร้างการบล็อกขั้นตอนที่กำหนดเอง คุณต้องทำดังนี้

  1. ติดตั้งปลั๊กอิน @blockly/block-shareable-procedures ตามที่อธิบายไว้ในหน้าการใช้กระบวนการ
  2. ใช้ระบบการทำให้เป็นอนุกรม JSON ตามที่อธิบายไว้ในหน้าภาพรวม

เพิ่มโมเดลข้อมูลไปยังพื้นที่ทำงาน

ทั้งการกำหนดขั้นตอนและการบล็อกการเรียกใช้กระบวนการจะอ้างอิงโมเดลข้อมูลสำรองซึ่งจะกำหนดลายเซ็นของกระบวนการ (ชื่อ พารามิเตอร์ และ Return) วิธีนี้ช่วยให้คุณออกแบบแอปพลิเคชันได้อย่างยืดหยุ่นมากขึ้น (เช่น คุณอนุญาตให้กำหนดกระบวนการทำงานในพื้นที่ทำงานหนึ่งและอ้างอิงในอีกพื้นที่ทำงานหนึ่งได้)

ซึ่งหมายความว่าคุณจะต้องเพิ่มโมเดลข้อมูลกระบวนการลงในพื้นที่ทำงานเพื่อให้การบล็อกทำงานได้ ซึ่งทำได้หลายวิธี (เช่น UI ที่กำหนดเอง)

@blockly/block-shareable-procedures นี้โดยให้บล็อกการกำหนดขั้นตอนสร้างโมเดลข้อมูลสนับสนุนแบบไดนามิกเมื่อมีการสร้างอินสแตนซ์ข้อมูลลงในพื้นที่ทำงาน หากต้องการติดตั้งใช้งานด้วยตนเอง ให้สร้างโมเดลใน init แล้วลบออกใน 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.
    this.workpace.getProcedureMap().delete(model.getId());
  }
}

แสดงข้อมูลเกี่ยวกับการบล็อก

การกำหนดกระบวนการและการบล็อกการเรียกใช้กระบวนการจำเป็นต้องใช้เมธอด getProcedureModel, isProcedureDef และ getVarModels นี่คือฮุกที่โค้ด Blockly ใช้ในการรับข้อมูลเกี่ยวกับการบล็อกขั้นตอนของคุณ

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

ทริกเกอร์การแสดงผลอีกครั้งในการอัปเดต

การกำหนดขั้นตอนและการบล็อกการเรียกใช้กระบวนการต้องใช้เมธอด doProcedureUpdate นี่คือฮุกที่โมเดลข้อมูลเรียกใช้เพื่อบอก บล็อกกระบวนการแสดงผลตัวเองอีกครั้ง

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

เพิ่มการทำให้เป็นอนุกรมที่กำหนดเอง

การทำให้เป็นอนุกรมสำหรับบล็อกกระบวนการต้องทำ 2 สิ่งแยกกัน

  1. เมื่อโหลดจาก JSON บล็อกจะต้องดึงการอ้างอิงไปยังโมเดลข้อมูลสนับสนุน เนื่องจากบล็อกและโมเดลต่างๆ มีการเรียงลำดับแยกกัน
  2. เมื่อคัดลอกและวางบล็อกกระบวนการ บล็อกดังกล่าวจะต้องทำให้สถานะของโมเดลกระบวนการเป็นอนุกรม เพื่อที่จะจำลอง/ทำซ้ำได้

ทั้ง 2 อย่างนี้จะได้รับการจัดการผ่าน saveExtraState และ loadExtraState ขอย้ำอีกครั้งว่าระบบจะรองรับการบล็อกขั้นตอนที่กำหนดเองเฉพาะเมื่อใช้ระบบการเรียงลำดับ JSON เท่านั้น เราจึงต้องกำหนดฮุกอนุกรม JSON เท่านั้น

import {
    ObservableProcedureModel,
    ObservableParameterModel,
    isProcedureBlock
} from '@blockly/block-shareable-procedures';

Blockly.Blocks['my_procedure_def'] = {
  saveExtraState() {
    return {
      'procedureId': this.model.getId(),

      // These properties are only necessary for pasting.
      'name': this.model.getName(),
      'parameters': this.model.getParameters().map((p) => {
        return {name: p.getName(), p.getId()};
      }),
      'returnTypes': this.model.getReturnTypes(),
    };
  },

  loadExtraState(state) {
    const id = state['procedureId']
    const map = this.workspace.getProcedureMap();

    // Grab a reference to the existing procedure model.
    if (this.model.getId() != id && map.has(id) &&
        (this.isInsertionMarker || this.noBlockHasClaimedModel_(id))) {
      // Delete the 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']);
      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']));
    }
  },

  // We don't want to reference a model that some other procedure definition
  // is already referencing.
  noBlockHasClaimedModel_(procedureId) {
    const model =
      this.workspace.getProcedureMap().get(procedureId);
    return this.workspace.getAllBlocks(false).every(
      (block) =>
        !isProcedureBlock(block) ||
        !block.isProcedureDef() ||
        block.getProcedureModel() !== model);
  },
};

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

(ไม่บังคับ) แก้ไขโมเดลขั้นตอน/ลายเซ็น

นอกจากนี้คุณยังเพิ่มความสามารถให้ผู้ใช้แก้ไขโมเดล/ลายเซ็นของกระบวนการได้ด้วย การเรียกใช้เมธอด insertParameter, deleteParameter หรือ setReturnTypes จะทริกเกอร์ให้บล็อกแสดงผลอีกครั้งโดยอัตโนมัติ (ผ่าน doProcedureUpdate)

ตัวเลือกสำหรับการสร้าง UI เพื่อแก้ไขโมเดลกระบวนการ ได้แก่ การใช้การเปลี่ยนแปลง (ซึ่งเป็นวิธีที่ใช้บล็อกกระบวนการในตัว) ช่องรูปภาพที่มีแฮนเดิลการคลิก หรือสิ่งที่อยู่ภายนอก Blockly โดยสิ้นเชิง เป็นต้น

เพิ่มบล็อกในกล่องเครื่องมือ

หมวดหมู่ขั้นตอนแบบไดนามิกที่มีในตัวของ Blockly จะมีไว้สำหรับการบล็อกขั้นตอนในตัวของ Blockly โดยเฉพาะ เพื่อให้สามารถเข้าถึงการบล็อกได้ คุณจะต้องกำหนดหมวดหมู่แบบไดนามิกที่กำหนดเองของคุณเอง และเพิ่มลงในกล่องเครื่องมือ

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