إنشاء قوالب إجراءات مخصصة

يتطلب إنشاء وحدات إجراءات مخصّصة ما يلي:

  1. ثبِّت المكوِّن الإضافي @blockly/block-shareable-procedures كما هو موضّح في صفحة إجراءات الاستخدام.
  2. استخدِم نظام تسلسل JSON، كما هو موضّح في صفحة النظرة العامة.

إضافة نماذج بيانات إلى مساحة العمل

يشير كل من عمليات حظر المتصل وتحديد الإجراء إلى نموذج بيانات احتياطية يحدد توقيع الإجراء (الاسم والمعلمات والرجوع). يتيح ذلك مزيدًا من المرونة في كيفية تصميم تطبيقك (على سبيل المثال، يمكنك السماح بتحديد الإجراءات في مساحة عمل، والرجوع إليها في مساحة عمل أخرى).

وهذا يعني أنك سوف تحتاج إلى إضافة نماذج بيانات الإجراءات إلى مساحة العمل حتى تعمل الكتل. وهناك العديد من الطرق التي يمكنك من خلالها القيام بذلك (على سبيل المثال، واجهات المستخدم المخصصة).

تؤدي @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.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...
  }
};

إضافة تسلسل مخصّص

يجب أن يؤدي تسلسل كتل الإجراءات إلى شيئين منفصلين.

  1. عند التحميل من JSON، يجب أن تأخذ القوالب مرجعًا في نموذج بيانات النسخ الاحتياطي الخاص بها، لأنّه يتم تسلسل القوالب والنماذج على نحو تسلسلي.
  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).

تتضمن خيارات إنشاء واجهات المستخدم لتعديل نموذج الإجراء استخدام mutator (التي تستخدمها مجموعات الإجراءات المضمنة) وحقول الصور مع معالجات النقرات أو شيء خارجي تمامًا عن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);