יצירת חסימות של הליכים בהתאמה אישית

כדי ליצור בלוקים של תהליכי עבודה בהתאמה אישית צריך:

  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. אלה קטעי ה-hooks שבהם קוד חסימת תוכן מאפשר לכם לקבל מידע על בלוקים של התהליכים שלכם.

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, ולכן אנחנו צריכים רק להגדיר קטעי הוק (hooks) של סריאליזציה של 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).

האפשרויות ליצירת ממשקי משתמש לשינוי מודל התהליך כוללות שימוש במוטרים (שבהם הבלוקים של התהליך המובנה), שדות תמונה עם רכיבי handler של קליקים, שימוש חיצוני לחלוטין ל-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);