جهش یافته ها

یک mutator یک mixin است که سریال سازی اضافی (حالت اضافی که ذخیره و بارگذاری می شود) به یک بلوک اضافه می کند. به عنوان مثال، بلوک های داخلی controls_if و list_create_with نیاز به سریال سازی اضافی دارند تا بتوانند تعداد ورودی های خود را ذخیره کنند. همچنین ممکن است یک رابط کاربری اضافه کند تا کاربر بتواند شکل بلوک را تغییر دهد.

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

دو جهش بلوک if/do: if-do و if-do-else-if-do-else.

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

بلوک «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" را به بلوک شما اضافه می کند.

یک بلوک if-do که حباب جهش دهنده آن باز است. این به کاربران امکان می دهد other-if و را اضافه کنند سایر بندهای بلوک if-do.

اگر می‌خواهید سریال‌سازی اضافی اضافه کنید، نیازی به استفاده از این رابط کاربری ندارید. می‌توانید از یک رابط کاربری سفارشی استفاده کنید، مانند پلاگین 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();
  }
},

ثبت نام

جهش‌دهنده‌ها فقط نوع خاصی از mixin هستند، بنابراین قبل از اینکه بتوانید از آنها در تعریف 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();
}