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

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

  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.

    // Insertion markers reference the model of the original block.
    if (this.isInsertionMarker()) return;
    this.workpace.getProcedureMap().delete(model.getId());
  }
}

הצגת מידע על הבלוקים

הגדרת התהליך וחסימות הקריאה של התהליך צריכות להטמיע getProcedureModel, isProcedureDef ו-getVarModels. אלה סוגי המודלים תוכנות הוק (hooks) שבהן נעשה שימוש בקוד של 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. אנחנו צריכים להגדיר הוקים (hooks) לסריאליזציה של 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();
      }
    }
  }
};

אפשר לשנות את המודל של התהליך

אפשר גם להוסיף את היכולת של המשתמשים לשנות את המודל של התהליך. ביצוע שיחה insertParameter, deleteParameter או setReturnTypes methods יפעילו באופן אוטומטי את הבלוקים שלכם לעיבוד (דרך doProcedureUpdate).

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