এক্সটেনশন এবং মিউটেটর

এক্সটেনশন হল ফাংশন যা ব্লক তৈরি হওয়ার সাথে সাথে প্রদত্ত ধরণের প্রতিটি ব্লকে চলে। এগুলি প্রায়শই একটি ব্লকে কিছু কাস্টম কনফিগারেশন বা আচরণ যুক্ত করে।

একটি মিউটেটর হল একটি বিশেষ ধরনের এক্সটেনশন যা কাস্টম সিরিয়ালাইজেশন , এবং কখনও কখনও 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;
      });
    });

এক্সটেনশনগুলিকে "নিবন্ধিত" করতে হবে যাতে তারা একটি স্ট্রিং কী এর সাথে যুক্ত হতে পারে। তারপর আপনি ব্লকে এক্সটেনশনটি প্রয়োগ করতে আপনার ব্লক প্রকারের JSON সংজ্ঞার extensions বৈশিষ্ট্যে এই স্ট্রিং কীটি বরাদ্দ করতে পারেন।

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

আপনি একবারে একাধিক এক্সটেনশন যোগ করতে পারেন। মনে রাখবেন যে extensions সম্পত্তি অবশ্যই একটি অ্যারে হতে হবে, এমনকি যদি আপনি শুধুমাত্র একটি এক্সটেনশন প্রয়োগ করেন।

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

মিক্সিং

ব্লকলি এমন পরিস্থিতিগুলির জন্য একটি সুবিধার পদ্ধতিও প্রদান করে যেখানে আপনি একটি ব্লকে কিছু বৈশিষ্ট্য/হেল্পার ফাংশন যোগ করতে চান, কিন্তু অবিলম্বে সেগুলি চালান না। এটি আপনাকে একটি মিক্সিন অবজেক্ট রেজিস্টার করার অনুমতি দিয়ে কাজ করে যাতে আপনার সমস্ত অতিরিক্ত বৈশিষ্ট্য/পদ্ধতি রয়েছে। তারপরে মিক্সিন অবজেক্টটি একটি ফাংশনে মোড়ানো হয় যা প্রদত্ত ব্লক টাইপের একটি উদাহরণ তৈরি করা হলে প্রতিবার মিক্সিন প্রয়োগ করে।

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 ব্লক আকৃতি পরিবর্তন করে, কিন্তু এটি একটি ড্রপডাউন ক্ষেত্রের উপর ভিত্তি করে করে, যার মান ইতিমধ্যেই ক্রমিক করা হয়েছে। যেমন, এটি শুধুমাত্র একটি ক্ষেত্র যাচাইকারী ব্যবহার করতে পারে, এবং একটি মিউটেটরের প্রয়োজন নেই।

আপনার কখন মিউটেটরের প্রয়োজন এবং কখন লাগবে না সে সম্পর্কে আরও তথ্যের জন্য সিরিয়ালাইজেশন পৃষ্ঠাটি দেখুন।

আপনি কিছু ঐচ্ছিক পদ্ধতি প্রদান করলে মিউটেটররা ব্যবহারকারীদের ব্লকের আকার পরিবর্তন করতে একটি অন্তর্নির্মিত UI প্রদান করে।

সিরিয়ালাইজেশন হুক

মিউটেটরদের দুটি জোড়া সিরিয়ালাইজেশন হুক থাকে যার সাথে তারা কাজ করে। এক জোড়া হুক নতুন JSON সিরিয়ালাইজেশন সিস্টেমের সাথে কাজ করে এবং অন্য জোড়া পুরানো XML সিরিয়ালাইজেশন সিস্টেমের সাথে কাজ করে। আপনাকে এই জোড়াগুলির মধ্যে অন্তত একটি প্রদান করতে হবে।

ExtraState সংরক্ষণ করুন এবং ExtraState লোড করুন

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 দেয় তাহলে JSON-এ কোনো extraState প্রপার্টি যোগ করা হবে না। এটি আপনার সংরক্ষণ ফাইলের আকার ছোট রাখে।

সম্পূর্ণ সিরিয়ালাইজেশন এবং ব্যাকিং ডেটা

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 ফাংশন শূন্য দেয়, তাহলে XML-এ কোনো অতিরিক্ত উপাদান যোগ করা হবে না।

UI হুক

আপনি যদি আপনার মিউটেটরের অংশ হিসাবে নির্দিষ্ট ফাংশন প্রদান করেন, ব্লকলি আপনার ব্লকে একটি ডিফল্ট "মিউটেটার" UI যোগ করবে।

আপনি যদি অতিরিক্ত সিরিয়ালাইজেশন যোগ করতে চান তবে আপনাকে এই UI ব্যবহার করতে হবে না। আপনি একটি কাস্টম UI ব্যবহার করতে পারেন, যেমন ব্লক-প্লাস-মাইনাস প্লাগইন সরবরাহ করে, অথবা আপনি কোনও UI ব্যবহার করতে পারবেন না!

রচনা এবং পচন

ডিফল্ট UI compose এবং decompose ফাংশনের উপর নির্ভর করে।

ব্লকটিকে "বিস্ফোরিত" করে ছোট সাব-ব্লকগুলিতে decompose যা চারপাশে সরানো, যোগ করা এবং মুছে ফেলা যায়। এই ফাংশনটি একটি "শীর্ষ ব্লক" প্রদান করবে যা মিউটেটর ওয়ার্কস্পেসের প্রধান ব্লক যা সাব-ব্লকগুলির সাথে সংযুক্ত।

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 ফাংশনও সংজ্ঞায়িত করতে পারেন যা ডিফল্ট UI এর সাথে কাজ করে। এই ফাংশনটি আপনাকে আপনার প্রধান ব্লকের বাচ্চাদের (যা প্রধান ওয়ার্কস্পেসে বিদ্যমান) আপনার মিউটেটর ওয়ার্কস্পেসে বিদ্যমান সাব-ব্লকের সাথে যুক্ত করার সুযোগ দেয়। আপনার সাব-ব্লকগুলি পুনর্গঠিত হলে আপনার 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 : মিউটেটরের সাথে যুক্ত করার জন্য একটি স্ট্রিং যাতে আপনি এটি JSON-এ ব্যবহার করতে পারেন।
  • mixinObj : বিভিন্ন মিউটেশন পদ্ধতি সম্বলিত একটি বস্তু। যেমন saveExtraState এবং loadExtraState
  • opt_helperFn : একটি ঐচ্ছিক সাহায্যকারী ফাংশন যা মিক্সিন মিশ্রিত হওয়ার পরে ব্লকে চলবে।
  • opt_blockList : ব্লক প্রকারের একটি ঐচ্ছিক অ্যারে (স্ট্রিং হিসাবে) যা ডিফল্ট মিউটেটর UI-তে ফ্লাইআউটে যোগ করা হবে, যদি UI পদ্ধতিগুলিও সংজ্ঞায়িত করা হয়।

মনে রাখবেন যে এক্সটেনশনের বিপরীতে, প্রতিটি ব্লকের শুধুমাত্র একটি মিউটেটর থাকতে পারে।

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

হেল্পার ফাংশন

মিক্সিনের সাথে, একজন মিউটেটর একটি সহায়ক ফাংশন নিবন্ধন করতে পারে। এই ফাংশনটি তৈরি হওয়ার পরে এবং mixinObj যোগ করার পরে প্রদত্ত ধরণের প্রতিটি ব্লকে চালানো হয়। এটি একটি মিউটেশনে অতিরিক্ত ট্রিগার বা প্রভাব যুক্ত করতে ব্যবহার করা যেতে পারে।

উদাহরণস্বরূপ, আপনি আপনার তালিকার মতো ব্লকে একটি সহায়ক যোগ করতে পারেন যা আইটেমগুলির প্রাথমিক সংখ্যা সেট করে:

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