ایجاد بلوک های رویه سفارشی، ایجاد بلوک های رویه سفارشی

ایجاد بلوک های رویه سفارشی مستلزم این است که:

  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 برای دریافت اطلاعات در مورد بلوک های رویه شما استفاده می کند.

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

گزینه‌های ایجاد رابط‌های کاربری برای اصلاح مدل رویه شامل استفاده از جهش‌دهنده‌ها (که بلوک‌های رویه داخلی از آن استفاده می‌کنند)، فیلدهای تصویر با کنترل‌کننده‌های کلیک، چیزی کاملاً خارجی برای 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);