افزونه ها و جهش دهنده ها

پسوندها توابعی هستند که با ایجاد بلوک روی هر بلوک از یک نوع مشخص اجرا می شوند. اینها اغلب پیکربندی یا رفتار سفارشی را به یک بلوک اضافه می کنند.

جهش‌دهنده نوع خاصی از پسوند است که سریال‌سازی سفارشی و گاهی UI را به یک بلوک اضافه می‌کند.

برنامه های افزودنی

پسوندها توابعی هستند که با ایجاد بلوک روی هر بلوک از یک نوع مشخص اجرا می شوند. آنها ممکن است پیکربندی سفارشی (مثلاً تنظیم راهنمای ابزار بلوک) یا رفتار سفارشی (مثلاً افزودن شنونده رویداد به بلوک) را اضافه کنند.

// This extension sets the block's tooltip to be a function which displays
// the parent block's tooltip (if it exists).
Blockly.Extensions.register(
    'parent_tooltip_extension',
    function() { // this refers to the block that the extension is being run on
      var thisBlock = this;
      this.setTooltip(function() {
        var parent = thisBlock.getParent();
        return (parent && parent.getInputsInline() && parent.tooltip) ||
            Blockly.Msg.MATH_NUMBER_TOOLTIP;
      });
    });

برنامه های افزودنی باید "ثبت نام" شوند تا بتوان آنها را با یک کلید رشته ای مرتبط کرد. سپس می‌توانید این کلید رشته‌ای را به ویژگی extensions تعریف JSON نوع بلوک خود اختصاص دهید تا پسوند را در بلوک اعمال کنید.

{
 //...,
 "extensions": ["parent_tooltip_extension",]
}

همچنین می توانید چندین افزونه را به طور همزمان اضافه کنید. توجه داشته باشید که ویژگی extensions باید یک آرایه باشد، حتی اگر فقط یک پسوند را اعمال کنید.

{
  //...,
  "extensions": ["parent_tooltip_extension", "break_warning_extension"],
}

مخلوط ها

Blockly همچنین یک روش راحت برای موقعیت‌هایی ارائه می‌کند که می‌خواهید برخی از ویژگی‌ها/توابع کمکی را به یک بلوک اضافه کنید، اما بلافاصله آنها را اجرا نکنید. این کار به شما امکان می دهد یک شی mixin را ثبت کنید که حاوی تمام ویژگی ها/روش های اضافی شما باشد. سپس شی mixin در تابعی پیچیده می شود که هر بار که نمونه ای از نوع بلوک داده شده ایجاد می شود، mixin را اعمال می کند.

Blockly.Extensions.registerMixin('my_mixin', {
  someProperty: 'a cool value',

  someMethod: function() {
    // Do something cool!
  }
))`

کلیدهای رشته ای مرتبط با میکسین ها را می توان در JSON مانند هر برنامه افزودنی دیگر ارجاع داد.

{
 //...,
 "extensions": ["my_mixin"],
}

جهش یافته ها

جهش‌دهنده نوع خاصی از پسوند است که سریال‌سازی اضافی (حالت اضافی که ذخیره و بارگذاری می‌شود) را به یک بلوک اضافه می‌کند. به عنوان مثال، بلوک های داخلی controls_if و list_create_with نیاز به سریال سازی اضافی دارند تا بتوانند تعداد ورودی های خود را ذخیره کنند.

توجه داشته باشید که تغییر شکل بلوک شما لزوماً به این معنی نیست که نیاز به سریال سازی اضافی دارید. به عنوان مثال، بلوک math_number_property شکل خود را تغییر می‌دهد، اما این کار را بر اساس یک فیلد کشویی انجام می‌دهد که مقدار آن قبلاً سریال‌سازی شده است. به این ترتیب، فقط می‌تواند از یک اعتبارسنجی فیلد استفاده کند، و نیازی به تغییردهنده ندارد.

برای اطلاعات بیشتر در مورد اینکه چه زمانی به جهش‌دهنده نیاز دارید و چه زمانی نیاز ندارید به صفحه سریال‌سازی مراجعه کنید.

جهش‌دهنده‌ها همچنین یک رابط کاربری داخلی برای کاربران فراهم می‌کنند تا در صورت ارائه روش‌های اختیاری، شکل بلوک‌ها را تغییر دهند.

قلاب های سریال سازی

موتاتورها دو جفت قلاب سریال سازی دارند که با آنها کار می کنند. یک جفت قلاب با سیستم جدید سریال سازی JSON کار می کند و جفت دیگر با سیستم سریال سازی XML قدیمی کار می کند. شما باید حداقل یکی از این جفت ها را تهیه کنید.

saveExtraState و loadExtraState

saveExtraState و loadExtraState قلاب های سریال سازی هستند که با سیستم سریال سازی جدید JSON کار می کنند. saveExtraState یک مقدار قابل سریال‌سازی JSON را برمی‌گرداند که نشان‌دهنده وضعیت اضافی بلوک است، و loadExtraState همان مقدار قابل سریال‌سازی JSON را می‌پذیرد و آن را روی بلوک اعمال می‌کند.

// These are the serialization hooks for the lists_create_with block.
saveExtraState: function() {
  return {
    'itemCount': this.itemCount_,
  };
},

loadExtraState: function(state) {
  this.itemCount_ = state['itemCount'];
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

JSON حاصل به صورت زیر خواهد بود:

{
  "type": "lists_create_with",
  "extraState": {
    "itemCount": 3 // or whatever the count is
  }
}
بدون ایالت

اگر بلوک شما در حالت سریالی در حالت پیش‌فرض باشد، متد saveExtraState شما می‌تواند برای نشان دادن این حالت، null برگرداند. اگر روش saveExtraState شما null برگرداند، هیچ خاصیت extraState به JSON اضافه نمی شود. این باعث می شود اندازه فایل ذخیره شما کوچک باشد.

سریال سازی کامل و داده های پشتیبان

saveExtraState همچنین یک پارامتر اختیاری doFullSerialization دریافت می کند. این مورد توسط بلوک‌هایی استفاده می‌شود که به‌وسیله یک سریال‌ساز متفاوت (مثل مدل‌های داده پشتیبان) مرتب شده‌اند. این پارامتر نشان می‌دهد که وقتی بلوک از حالت سریال خارج می‌شود، حالت ارجاع‌شده در دسترس نخواهد بود، بنابراین بلوک باید تمام حالت پشتیبان را خود سریال‌سازی کند. به عنوان مثال، زمانی که یک بلوک مجزا سریالی می شود، یا زمانی که یک بلوک کپی پیست شده است، این امر صادق است.

دو مورد استفاده رایج برای این عبارتند از:

  • هنگامی که یک بلوک منفرد در فضای کاری بارگذاری می شود که مدل داده پشتیبان وجود ندارد، اطلاعات کافی در حالت خود برای ایجاد یک مدل داده جدید دارد.
  • وقتی یک بلوک کپی پیست می شود، همیشه به جای ارجاع به مدل موجود، یک مدل داده پشتیبان جدید ایجاد می کند.

برخی از بلوک‌هایی که از این استفاده می‌کنند، بلوک‌های @blockly/block-shareable-procedures هستند. معمولاً آنها یک مرجع به یک مدل داده پشتیبان را سریال می کنند که وضعیت آنها را ذخیره می کند. اما اگر پارامتر doFullSerialization درست باشد، تمام حالت خود را سریال می کنند. بلوک‌های رویه قابل اشتراک‌گذاری از این مورد استفاده می‌کنند تا مطمئن شوند که وقتی کپی پیست می‌شوند، به جای ارجاع به مدل موجود، یک مدل داده پشتیبان جدید ایجاد می‌کنند.

mutationToDom و domToMutation

mutationToDom و domToMutation قلاب های سریال سازی هستند که با سیستم قدیمی سریال سازی XML کار می کنند. فقط در صورت لزوم از این قلاب ها استفاده کنید (مثلاً روی یک کد-پایه قدیمی کار می کنید که هنوز مهاجرت نکرده است)، در غیر این صورت از saveExtraState و loadExtraState استفاده کنید.

mutationToDom یک گره XML را برمی گرداند که نشان دهنده وضعیت اضافی بلوک است، و domToMutation همان گره XML را می پذیرد و حالت را به بلوک اعمال می کند.

// These are the old XML serialization hooks for the lists_create_with block.
mutationToDom: function() {
  // You *must* create a <mutation></mutation> element.
  // This element can have children.
  var container = Blockly.utils.xml.createElement('mutation');
  container.setAttribute('items', this.itemCount_);
  return container;
},

domToMutation: function(xmlElement) {
  this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
  // This is a helper function which adds or removes inputs from the block.
  this.updateShape_();
},

XML حاصل به صورت زیر خواهد بود:

<block type="lists_create_with">
  <mutation items="3"></mutation>
</block>

اگر تابع mutationToDom شما null را برگرداند، هیچ عنصر اضافی به XML اضافه نخواهد شد.

قلاب های رابط کاربری

اگر عملکردهای خاصی را به عنوان بخشی از mutator خود ارائه دهید، Blockly یک رابط کاربری پیش فرض "mutator" را به بلوک شما اضافه می کند.

اگر می‌خواهید سریال‌سازی اضافی اضافه کنید، نیازی به استفاده از این رابط کاربری ندارید. می‌توانید از یک رابط کاربری سفارشی استفاده کنید، مانند پلاگین blocks-plus-minus ارائه می‌کند، یا اصلاً نمی‌توانید از رابط کاربری استفاده کنید!

تالیف و تجزیه کنند

رابط کاربری پیش‌فرض به توابع compose و decompose متکی است.

"انفجار" بلوک را به بلوک های فرعی کوچکتر decompose که می توان آنها را جابجا کرد، اضافه کرد و حذف کرد. این تابع باید یک "بلوک بالا" را برگرداند که بلوک اصلی در فضای کاری mutator است که بلوک های فرعی به آن متصل می شوند.

compose سپس پیکربندی بلوک‌های فرعی را تفسیر می‌کند و از آنها برای اصلاح بلوک اصلی استفاده می‌کند. این تابع باید "بلوک بالا" را که با decompose برگردانده شده است به عنوان پارامتر بپذیرد.

توجه داشته باشید که این توابع با بلوک در حال "جهش" "مخلوط" می شوند، بنابراین می توان this برای اشاره به آن بلوک استفاده کرد.

// These are the decompose and compose functions for the lists_create_with block.
decompose: function(workspace) {
  // This is a special sub-block that only gets created in the mutator UI.
  // It acts as our "top block"
  var topBlock = workspace.newBlock('lists_create_with_container');
  topBlock.initSvg();

  // Then we add one sub-block for each item in the list.
  var connection = topBlock.getInput('STACK').connection;
  for (var i = 0; i < this.itemCount_; i++) {
    var itemBlock = workspace.newBlock('lists_create_with_item');
    itemBlock.initSvg();
    connection.connect(itemBlock.previousConnection);
    connection = itemBlock.nextConnection;
  }

  // And finally we have to return the top-block.
  return topBlock;
},

// The container block is the top-block returned by decompose.
compose: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we collect up all of the connections of on our main block that are
  // referenced by our sub-blocks.
  // This relates to the saveConnections hook (explained below).
  var connections = [];
  while (itemBlock && !itemBlock.isInsertionMarker()) {  // Ignore insertion markers!
    connections.push(itemBlock.valueConnection_);
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }

  // Then we disconnect any children where the sub-block associated with that
  // child has been deleted/removed from the stack.
  for (var i = 0; i < this.itemCount_; i++) {
    var connection = this.getInput('ADD' + i).connection.targetConnection;
    if (connection && connections.indexOf(connection) == -1) {
      connection.disconnect();
    }
  }

  // Then we update the shape of our block (removing or adding iputs as necessary).
  // `this` refers to the main block.
  this.itemCount_ = connections.length;
  this.updateShape_();

  // And finally we reconnect any child blocks.
  for (var i = 0; i < this.itemCount_; i++) {
    connections[i].reconnect(this, 'ADD' + i);
  }
},

saveConnections

به صورت اختیاری، می‌توانید تابع saveConnections را نیز تعریف کنید که با رابط کاربری پیش‌فرض کار می‌کند. این تابع به شما فرصتی می دهد تا فرزندان بلوک اصلی خود (که در فضای کاری اصلی وجود دارد) را با بلوک های فرعی که در فضای کاری mutator شما وجود دارند مرتبط کنید. سپس می‌توانید از این داده‌ها استفاده کنید تا مطمئن شوید که عملکرد compose شما به درستی فرزندان بلوک اصلی شما را دوباره به هم متصل می‌کند، وقتی بلوک‌های فرعی شما سازماندهی مجدد می‌شوند.

saveConnections باید "بلوک بالا" را که توسط تابع decompose شما برگردانده شده است به عنوان یک پارامتر بپذیرد. اگر تابع saveConnections تعریف شده باشد، Blockly آن را قبل از فراخوانی compose فراخوانی می کند.

saveConnections: function(topBlock) {
  // First we get the first sub-block (which represents an input on our main block).
  var itemBlock = topBlock.getInputTargetBlock('STACK');

  // Then we go through and assign references to connections on our main block
  // (input.connection.targetConnection) to properties on our sub blocks
  // (itemBlock.valueConnection_).
  var i = 0;
  while (itemBlock) {
    // `this` refers to the main block (which is being "mutated").
    var input = this.getInput('ADD' + i);
    // This is the important line of this function!
    itemBlock.valueConnection_ = input && input.connection.targetConnection;
    i++;
    itemBlock = itemBlock.nextConnection &&
        itemBlock.nextConnection.targetBlock();
  }
},

ثبت نام

جهش‌دهنده‌ها فقط نوع خاصی از پسوند هستند، بنابراین قبل از اینکه بتوانید از آنها در تعریف JSON نوع بلوک خود استفاده کنید، باید ثبت شوند.

// Function signature.
Blockly.Extensions.registerMutator(name, mixinObj, opt_helperFn, opt_blockList);

// Example call.
Blockly.Extensions.registerMutator(
    'controls_if_mutator',
    { /* mutator methods */ },
    undefined,
    ['controls_if_elseif', 'controls_if_else']);
  • name : رشته ای برای ارتباط با mutator تا بتوانید از آن در JSON استفاده کنید.
  • mixinObj : یک شی حاوی روش های مختلف جهش. به عنوان مثال saveExtraState و loadExtraState .
  • opt_helperFn : یک تابع کمکی اختیاری که پس از مخلوط شدن میکس در بلوک اجرا می شود.
  • opt_blockList : یک آرایه اختیاری از انواع بلوک (به عنوان رشته) که در صورتی که متدهای UI نیز تعریف شده باشند، به flyout در رابط کاربری پیش فرض mutator اضافه می شود.

توجه داشته باشید که برخلاف پسوندها، هر نوع بلوک ممکن است فقط یک جهش دهنده داشته باشد.

{
  //...
  "mutator": "controls_if_mutator"
}

عملکرد کمک کننده

همراه با mixin، یک جهش دهنده ممکن است یک تابع کمکی را ثبت کند. این تابع پس از ایجاد و اضافه شدن mixinObj روی هر بلوک از نوع داده شده اجرا می شود. می توان از آن برای افزودن محرک ها یا اثرات اضافی به یک جهش استفاده کرد.

به عنوان مثال، می توانید یک راهنما به بلوک لیست مانند خود اضافه کنید که تعداد اولیه موارد را تنظیم می کند:

var helper = function() {
  this.itemCount_ = 5;
  this.updateShape();
}