أدوات إنشاء الرموز الكتلية

أداة إنشاء الرموز البرمجية للكتلة هي دالة تنشئ الرمز البرمجي للكتلة وتُعيده كسلسلة. يعتمد الرمز الذي تنشئه الكتلة على نوعها:

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

كيفية كتابة أداة إنشاء رموز الكتل

لكلّ مجموعة مخصّصة تنشئها، عليك كتابة أداة إنشاء رموز مجموعات لكلّ لغة تريد إتاحتها. يُرجى العِلم أنّ جميع أدوات إنشاء الرموز البرمجية المكوّنة من وحدات مكتوبة بلغة JavaScript، حتى إذا كانت تُنشئ رمزًا بلغة أخرى.

تُنفِّذ جميع أدوات إنشاء الرموز البرمجية المجمّعة الخطوات التالية:

  1. استورِد أداة إنشاء رموز اللغات.
  2. الحصول على قيمة كل حقل وتحويلها إلى سلسلة رموز
  3. الحصول على سلاسل الرموز التي تم إنشاؤها بواسطة الكتل الداخلية، وهي كتل مرفقة ب inputs للقيمة والعبارة
  4. إنشاء سلسلة رمز العنصر وإعادتها

أمثلة على الكتل

على سبيل المثال، سنكتب أدوات إنشاء رموز JavaScript للكتل التالية.

  • custom_compare هو كتلة قيمة تحتوي على إدخال قيمة باسم LEFT، وأحد الحقول المنسدلة باسم OPERATOR، وحقل رقمي باسم RIGHT. ويقوم بإنشاء سلسلة تعبير من النوع '0 = 0'.

    عنصر قيمة مخصّص لمقارنة

  • custom_if هو عبارة عن كتلة عبارة تحتوي على حقل مربّع اختيار باسم NOT وأحد مربعات إدخال القيمة باسم CONDITION ومربع إدخال عبارة باسم THEN. وهي تنشئ سلسلة بيان من النوع 'if (...) {\n...\n};\n'.

    عبارة مخصّصة لعبارة if يمكن للمستخدمين استخدام مربّع اختيار لإلغاء شرط if.

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

يُرجى العِلم أنّ هذه الكتل مخصّصة فقط لتوضيح عملية إنشاء الرموز البرمجية. في تطبيق حقيقي، استخدِم الكتل المضمّنة logic_compare وcontrols_if.

استيراد أداة إنشاء رموز اللغات

يمكنك استيراد أداة إنشاء رموز اللغات باستخدام إحدى الطريقتَين التاليتَين. استخدِم أداة الإنشاء المستورَدة لتخزين أدوات إنشاء الرموز البرمجية في العنصر forBlock.

الوحدات

import {javascriptGenerator} from 'blockly/javascript';
import {pythonGenerator} from 'blockly/python';
import {phpGenerator} from 'blockly/php';
import {luaGenerator} from 'blockly/lua';
import {dartGenerator} from 'blockly/dart';

// Add block-code generators for the custom_if block.
javascriptGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
pythonGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
phpGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
luaGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
dartGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };

Unpkg

يجب تضمين أداة إنشاء المحتوى بعد تضمين Blockly.

<script src="https://unpkg.com/blockly"></script>
<script src="https://unpkg.com/blockly/javascript_compressed"></script>
<script src="https://unpkg.com/blockly/python_compressed"></script>
<script src="https://unpkg.com/blockly/php_compressed"></script>
<script src="https://unpkg.com/blockly/lua_compressed"></script>
<script src="https://unpkg.com/blockly/dart_compressed"></script>
// Add block-code generators for the custom_if block.
javascript.javascriptGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
python.pythonGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
php.phpGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
lua.luaGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
dart.dartGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };

النصوص البرمجية المحلية

يجب تضمين أداة إنشاء المحتوى بعد تضمين Blockly.

<script src="blockly_compressed.js"></script>
<script src="javascript_compressed.js"></script>
<script src="python_compressed.js"></script>
<script src="php_compressed.js"></script>
<script src="lua_compressed.js"></script>
<script src="dart_compressed.js"></script>
// Add block-code generators for the custom_if block.
javascript.javascriptGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
python.pythonGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
php.phpGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
lua.luaGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };
dart.dartGenerator.forBlock['custom_if'] = function (block, generator) { /* ... */ };

الحصول على قيم الحقول

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

استنادًا إلى الحقل، قد تحتاج إلى تحويل القيمة المعروضة قبل استخدامها في الرمز.

custom_compare

javascriptGenerator.forBlock['custom_compare'] = function (block, generator) {
  // Use the value of the OPERATOR dropdown to look up the actual operator.
  const OPERATORS = {
    EQUALS: '==',
    LESS: '<',
    GREATER: '>',
  };
  const operator = OPERATORS[block.getFieldValue('OPERATOR')];
  // The value of the RIGHT field is a number and can be used directly when
  // building the block's code string.
  const right = block.getFieldValue('RIGHT');
  ...
}

custom_if

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  // Use the value of the NOT field to get the negation operator (if any).
  const checkbox = block.getFieldValue('NOT');
  const negate = checkbox === 'TRUE' ? '!' : '';
  ...
}

لمزيد من المعلومات، يُرجى الاطّلاع على تحويل قيم الحقل.

الحصول على الرمز من الكتل الداخلية

الكتل الداخلية هي الكتل المرفقة بقيمة الكتلة ومدخلات البيان. على سبيل المثال، يحتوي العنصر custom_if على عنصر داخلي للقيمة لشرط if، وعناصر داخلية للعبارة للرمز الذي يتم تنفيذه إذا كان الشرط صحيحًا.

على عكس قيم الحقول، يكون الرمز الذي تحصل عليه من الكتل الداخلية جاهزًا للاستخدام ولا يحتاج إلى التحويل.

وحدات القيمة الداخلية

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

custom_compare

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_compare'] = function (block, generator) {
  ...
  const order = operator === '==' ? Order.EQUALITY : Order.RELATIONAL;
  const left = generator.valueToCode(block, 'LEFT', order);
  ...
}

custom_if

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  ...
  const order = checkbox === 'TRUE' ? Order.LOGICAL_NOT : Order.NONE;
  const condition = generator.valueToCode(block, 'CONDITION', order) || 'false';
  ...
}

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

على سبيل المثال، يؤدي وضع علامة في مربّع NOT في custom_if إلى تطبيق عامل حسابي منطقي للنفي (!) على الشرط. في هذه الحالة، يتم تمرير Order.LOGICAL_NOT، وهي الأولوية الخاصة بعامل التشغيل not، إلى valueToCode، ويقارن valueToCode هذه الأولوية بأولوية عامل التشغيل الأضعف في الكتلة الداخلية. ثم يلفّ الرمز البرمجي للوحدة الداخلية حسب الحاجة:

  • إذا كان CONDITION عبارة عن كتلة متغيّر، لا تضيف valueToCode قوسَين لأنّه يمكن تطبيق عامل التشغيل not مباشرةً على متغيّر (!myBoolean).
  • إذا كان CONDITION عبارة عن كتلة مقارنة، يضيف valueToCode قوسَين لكي ينطبق عامل التشغيل not على المقارنة بأكملها (!(a < b)) بدلاً من القيمة اليمنى (!a < b).

لست بحاجة إلى معرفة ما إذا كان valueToCode قد أضاف الأقواس. ما عليك سوى تمرير الأولوية إلى valueToCode وإضافة الرمز المعروض إلى سلسلة الرموز. لمزيد من المعلومات، يُرجى الاطّلاع على valueToCode precedence.

وحدات العبارة الداخلية

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

custom_compare

لا تحتوي مجموعة custom_compare على أيّ إدخالات لبيان.

custom_if

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  ...
  const statements = generator.statementToCode(block, 'THEN');
  ...
}

ما عليك سوى استدعاء statementToCode للكتلة الداخلية المرتبطة مباشرةً بإدخال عبارة. يعالج statementToCode أيّ وحدات إضافية مرفقة بالوحدة الأولى.

إنشاء سلسلة الرمز وإعادتها

بعد الحصول على رمز الحقول والكتل الداخلية، أنشئ سلسلتَي الرموز البرمجية للكتل وأرسِلَهما. يعتمد ما يمكنك إرجاعه بالضبط على نوع المحتوى الذي تم حظره:

  • كتل القيم: عرض مصفوفة تحتوي على سلسلة الرمز و الأولوية لعامل التشغيل الأضعف في الرمز يستخدم valueToCode هذا العنصر لتحديد ما إذا كان يجب تضمين الرمز البرمجي بين قوسَين عندما يتم استخدام العنصر كعنصر داخلي. لمزيد من المعلومات، يُرجى الاطّلاع على أولوية ناتج الدوالّ المتعلّقة بالسلسلة.

  • كتل العبارة: عرض سلسلة الرمز

custom_compare

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_compare'] = function (block, generator) {
  ...
  const order = operator === '==' ? Order.EQUALITY : Order.RELATIONAL;
  ...
  const code = left + ' ' + operator + ' ' + right;
  return [code, order];
}

custom_if

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  ...
  const code = 'if (' + negate + condition + ') {\n' + statements + '}\n';
  return code;
}

إذا كنت تستخدم رمزًا لبلوك قيمة داخلية عدة مرات في سلسلة الرمز، يجب تخزين الرمز من ذلك البلوك لتجنُّب الأخطاء الدقيقة والتأثيرات الجانبية غير المرغوب فيها.

أدوات إنشاء الرموز الكاملة

في ما يلي أدوات إنشاء الرموز الكاملة لكلّ قسم، وذلك للرجوع إليها:

custom_compare

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_compare'] = function (block, generator) {
  const OPERATORS = {
    EQUALS: '==',
    LESS: '<',
    GREATER: '>',
  };
  const operator = OPERATORS[block.getFieldValue('OPERATOR')];
  const order = operator === '==' ? Order.EQUALITY : Order.RELATIONAL;
  const left = generator.valueToCode(block, 'LEFT', order);
  const right = block.getFieldValue('RIGHT');
  const code = left + ' ' + operator + ' ' + right;
  return [code, order];
}

custom_if

import {javascriptGenerator, Order} from 'blockly/javascript';

javascriptGenerator.forBlock['custom_if'] = function (block, generator) {
  const checkbox = block.getFieldValue('NOT');
  const negate = checkbox === 'TRUE' ? '!' : '';
  const order = checkbox === 'TRUE' ? Order.LOGICAL_NOT : Order.NONE;
  const condition = generator.valueToCode(block, 'CONDITION', order) || 'false';
  const statements = generator.statementToCode(block, 'THEN');
  const code = 'if (' + negate + condition + ') {\n' + statements + '}\n';
  return code;
}