الإضافات ومفاتيح التبديل

الإضافات هي دوال تعمل على كل كتلة من نوع معين مثل الجزء إنشاء. وغالبًا ما تضيف هذه الإعدادات بعض الضبط أو السلوك المخصّص إلى الحظر.

المُبدل هو نوع خاص من الإضافات يضيف تسلسلاً مخصصًا، وأحيانًا واجهة المستخدم، إلى الكتلة.

الإضافات

الإضافات هي دوال تعمل على كل كتلة من نوع معين مثل الجزء إنشاء. ويمكنهم إضافة إعدادات مخصّصة (مثل ضبط تلميح أداة الحظر) أو سلوك مخصّص (مثل إضافة أداة معالجة حدث إلى المجموعة).

// 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 ثم يتم التفافها في دالة تطبق المزيج في كل مرة يكون فيها مثيل يتم إنشاء نوع الكتلة المحدد.

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 القديم. ويجب تقديم واحد على الأقل من هذه الأزواج.

saveraState و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 اختيارية. هذا النمط تُستخدم في الكتل التي تشير إلى حالة تسلسلية بواسطة serializer (مثل النسخ الاحتياطي لنماذج البيانات). تشير المعلمة إلى أن ولن تتوفر الحالة المشار إليها عند إلغاء تسلسل الحظر، وبالتالي كتلة النص يجب أن يجتاز جميع حالة الدعم نفسها. على سبيل المثال، هذه هي عندما يتم تنفيذ كتلة فردية بشكل تسلسلي أو عند نسخ جزء من الكتلة ولصقه.

في ما يلي حالتا استخدام شائعتان لذلك:

  • عند تحميل وحدة فردية في مساحة عمل يتم فيها تحميل البيانات الاحتياطية غير موجود، فهذا يعني أنه يحتوي على معلومات كافية في حالته الخاصة لإنشاء نموذج بيانات جديد.
  • عندما يتم نسخ الجزء ولصقه، يتم دائمًا إنشاء خلفية جديدة نموذج بيانات بدلاً من الإشارة إلى نموذج حالي.

بعض الأجزاء التي تستخدم هذه هي عمليات الحظر @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.

عناصر الجذب في واجهة المستخدم

إذا كنت تقدم دوال معينة كجزء من المتغير الخاص بك، ستضيف Blockly الخيار التلقائي "المغيّر" واجهة المستخدم للقطعة.

ليس من الضروري استخدام واجهة المستخدم هذه إذا كنت تريد إضافة تسلسل إضافي. يمكنك استخدام واجهة مستخدم مخصصة، مثل علامة blocks-plus-minus المكوّن الإضافي ، أو قد لا تستخدم أي واجهة مستخدم على الإطلاق!

إنشاء وفك

تعتمد واجهة المستخدم التلقائية على الدالتَين 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

يمكنك اختياريًا تحديد دالة saveConnections التي تتوافق مع واجهة المستخدم الافتراضية. تمنحك هذه الدالة فرصة لربط العناصر الثانوية الجزء الرئيسي (الموجود في مساحة العمل الرئيسية) مع كتل فرعية موجودة في ومساحة العمل المتغيرة لديك. يمكنك بعد ذلك استخدام هذه البيانات للتأكّد من أنّ 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: مصفوفة اختيارية من أنواع الكتل (كسلاسل) التي سيتم مضافة إلى القائمة المنبثقة في واجهة المستخدم الافتراضية للتبديل، إذا كانت طرق واجهة المستخدم محددة.

تجدر الإشارة إلى أنّه على عكس الإضافات، قد يحتوي كل نوع حظر على رمز تغيير واحد فقط.

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

الدالة المساعدة

وإلى جانب المزيج، قد يسجل المبدل دالة مساعدة. هذه الدالة هي تشغيل في كل كتلة من النوع المحدد بعد إنشائها، ويكون MixinObj تمت إضافتها. ويمكن استخدامها لإضافة مشغِّلات أو تأثيرات إضافية إلى أي طفرة.

على سبيل المثال، يمكنك إضافة عنصر مساعد إلى مجموعة شبيهة بالقائمة تحدد العدد الأولي للعناصر:

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