حقول القائمة المنسدلة

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

كتلة تحمل التصنيف "القائمة المنسدلة:"، وحقل قائمة منسدلة تم اختيار "الأول" فيه،
والتصنيف "عنصر".

الحظر نفسه مع فتح القائمة المنسدلة تحتوي القائمة المنسدلة على العنصرَين "الأول" و "الثاني".

المربّع نفسه بعد تصغيره يحتوي على التصنيف "القائمة المنسدلة: العنصر الأول"،
ويحتوي على حافة يسرى متعرجة للإشارة إلى أنّه
مصغّر.

الإنشاء

يستقبل منشئ القائمة المنسدلة منشئ قائمة وأداة التحقّق اختيارية. مولّد القائمة هو إما مصفوفة من الخيارات (حيث يحتوي كل خيار على جزء يمكن للمستخدمين قراءته وسلسلة محايدة للغة) أو دالة تنشئ مصفوفة من الخيارات. يمكن أن يكون الجزء القابل للقراءة من كل خيار سلسلة أو صورة أو عنصر HTML، ويمكن أن تحتوي المصفوفة على مجموعة من الخيارات من أنواع مختلفة.

القوائم المنسدلة التي تحتوي على نص بسيط

فتح قائمة منسدلة تتضمّن خيارَين نصيَّين

JSON

{
  "type": "example_dropdown",
  "message0": "drop down: %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "FIELDNAME",
      "options": [
        [ "first item", "ITEM1" ],
        [ "second item", "ITEM2" ]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['example_dropdown'] = {
  init: function() {
    this.appendDummyInput()
        .appendField('drop down:')
        .appendField(new Blockly.FieldDropdown([
            ['first item', 'ITEM1'],
            ['second item', 'ITEM2']
        ]), 'FIELDNAME');
  }
};

يؤدي الاحتفاظ بالمعلومات القابلة للقراءة بشكل منفصل عن المفتاح المحايد للغة إلى الحفاظ على إعداد القائمة المنسدلة بين اللغات. على سبيل المثال، قد يحدّد الإصدار الإنجليزي من أحد الأقسام القيمة [['left', 'LEFT'], ['right', 'RIGHT]]، بينما يحدّد الإصدار الألماني من القسم نفسه القيمة [['links', 'LEFT'], ['rechts', 'RIGHT]].

القوائم المنسدلة للصور

قد تكون الخيارات في القائمة المنسدلة عبارة عن صور، ويتم تمثيلها كعناصر تتضمّن السمات src وwidth وheight وalt.

حقل القائمة المنسدلة الذي يحتوي على صور ونصوص

JSON

{
  "type": "image_dropdown",
  "message0": "flag %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "FLAG",
      "options": [
        ["none", "NONE"],
        [{"src": "canada.png", "width": 50, "height": 25, "alt": "Canada"}, "CANADA"],
        [{"src": "usa.png", "width": 50, "height": 25, "alt": "USA"}, "USA"],
        [{"src": "mexico.png", "width": 50, "height": 25, "alt": "Mexico"}, "MEXICO"]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['image_dropdown'] = {
  init: function() {
    var input = this.appendDummyInput()
        .appendField('flag');
    var options = [
        ['none', 'NONE'],
        [{'src': 'canada.png', 'width': 50, 'height': 25, 'alt': 'Canada'}, 'CANADA'],
        [{'src': 'usa.png', 'width': 50, 'height': 25, 'alt': 'USA'}, 'USA'],
        [{'src': 'mexico.png', 'width': 50, 'height': 25, 'alt': 'Mexico'}, 'MEXICO']
    ];
    input.appendField(new Blockly.FieldDropdown(options), 'FLAG');
  }
};

القوائم المنسدلة بتنسيق HTML

يمكن أن يكون الخيار أي عنصر HTML، شرط ألا يكون كبيرًا جدًا وألا يحاول التعامل مع أحداث الماوس أو لوحة المفاتيح. (تقع على عاتقك مسؤولية اتّباع هذه القواعد، إذ لا يفرضها Blockly).

عند فتح القائمة المنسدلة، تعرض القائمة عنصر HTML. عندما تكون القائمة مغلقة وكان العنصر هو الخيار المحدّد، تعرض القائمة (بترتيب تنازلي حسب التفضيل) السمة title الخاصة بالعنصر أو السمة aria-label أو الخاصية innerText.

حقل القائمة المنسدلة الذي يحتوي على عناصر نصية وعناصر HTML

JSON

{
  "type": "flags_with_text_dropdown",
  "message0": "flag with text %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "FLAG_WITH_TEXT",
      "options": [
        ["x", "X"], // Placeholder. An empty array throws an exception.
      ]
    }
  ],
  // Use an extension to add the HTML element options.
  "extensions": ["flag_with_text_extension"]
}
Blockly.Extensions.register('flag_with_text_extension',
  function() {
    function createFlagWithTextDiv(text, src) {
      const div = document.createElement('div');
      div.setAttribute('style', 'width: 75px;');
      div.setAttribute('title', text);
      const img = document.createElement('img');
      img.setAttribute('src', src);
      img.setAttribute('style', 'height: 25px; display: block; margin: auto;');
      div.appendChild(img);
      const para = document.createElement('p');
      para.innerText = text;
      para.setAttribute('style', 'text-align: center; margin: 5px;');
      div.appendChild(para);
      return div;
    }

    const canadaDiv = createFlagWithTextDiv('Canada', 'canada.png');
    const usaDiv = createFlagWithTextDiv('USA', 'usa.png');
    const mexicoDiv = createFlagWithTextDiv('Mexico', 'mexico.png');
    const options = [
      ['none', 'NONE'],
      [canadaDiv, 'CANADA'],
      [usaDiv, 'USA'],
      [mexicoDiv, 'MEXICO']
    ];
    this.getField('FLAG_WITH_TEXT').setOptions(options);
  });

يتم ذلك باستخدام إضافة JSON.

JavaScript

function createFlagWithTextDiv(text, src) {
  const div = document.createElement('div');
  div.setAttribute('style', 'width: 75px;');
  div.setAttribute('title', text);
  const img = document.createElement('img');
  img.setAttribute('src', src);
  img.setAttribute('style', 'height: 25px; display: block; margin: auto;');
  div.appendChild(img);
  const para = document.createElement('p');
  para.innerText = text;
  para.setAttribute('style', 'text-align: center; margin: 5px;');
  div.appendChild(para);
  return div;
}

const canadaDiv = createFlagWithTextDiv('Canada', 'canada.png');
const usaDiv = createFlagWithTextDiv('USA', 'usa.png');
const mexicoDiv = createFlagWithTextDiv('Mexico', 'mexico.png');

Blockly.Blocks['flags_with_text_dropdown'] = {
  init: function() {
    const input = this.appendDummyInput()
        .appendField('flag with text');
    const options = [
        ['none', 'NONE'],
        [canadaDiv, 'CANADA'],
        [usaDiv, 'USA'],
        [mexicoDiv, 'MEXICO']
    ];
    input.appendField(new Blockly.FieldDropdown(options), 'FLAG_WITH_TEXT');
  }
};

القوائم المنسدلة الديناميكية

حقل قائمة منسدلة يتضمّن أيام الأسبوع

JSON

{
  "type": "dynamic_dropdown",
  "message0": "day %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "DAY",
      "options": [
        ["x", "X"], // Placeholder. An empty array throws an exception.
      ]
     }
  ],
  // Use an extension to set the menu function.
  "extensions": ["dynamic_menu_extension"]
}
Blockly.Extensions.register('dynamic_menu_extension',
  function() {
    this.getField('DAY').setOptions(
      function() {
        var options = [];
        var now = Date.now();
        for(var i = 0; i < 7; i++) {
          var dateString = String(new Date(now)).substring(0, 3);
          options.push([dateString, dateString.toUpperCase()]);
          now += 24 * 60 * 60 * 1000;
        }
        return options;
      });
  });

يتم ذلك باستخدام إضافة JSON.

JavaScript

Blockly.Blocks['dynamic_dropdown'] = {
  init: function() {
    var input = this.appendDummyInput()
      .appendField('day')
      .appendField(new Blockly.FieldDropdown(
        this.generateOptions), 'DAY');
  },

  generateOptions: function() {
    var options = [];
    var now = Date.now();
    for(var i = 0; i < 7; i++) {
      var dateString = String(new Date(now)).substring(0, 3);
      options.push([dateString, dateString.toUpperCase()]);
      now += 24 * 60 * 60 * 1000;
    }
    return options;
  }
};

يمكن أيضًا توفير قائمة منسدلة مع دالة بدلاً من قائمة بالخيارات الثابتة، ما يسمح بأن تكون الخيارات ديناميكية. يجب أن تعرض الدالة مصفوفة من الخيارات بالتنسيق نفسه [human-readable-value, language-neutral-key] المستخدَم مع الخيارات الثابتة. في كل مرة يتم فيها النقر على القائمة المنسدلة، يتم تشغيل الدالة وإعادة احتساب الخيارات.

الفواصل

استخدِم السلسلة 'separator' لإضافة سطر بين الخيارات في قائمة منسدلة.

حقل قائمة منسدلة يتضمّن خطًا بين الخيارَين الثاني والثالث

JSON

{
  "type": "separator_dropdown",
  "message0": "food %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "FOOD",
      "options": [
        ["water", "WATER"],
        ["juice", "JUICE"],
        "separator",
        ["salad", "SALAD"],
        ["soup", "SOUP"],
      ]
    }
  ]
}

JavaScript

Blockly.Blocks["separator_dropdown"] = {
  init: function() {
    var input = this.appendDummyInput()
        .appendField("food1");
    var options = [
        ["water", "WATER"],
        ["juice", "JUICE"],
        "separator",
        ["salad", "SALAD"],
        ["soup", "SOUP"],
    ];
    input.appendField(new Blockly.FieldDropdown(options), "FOOD");
  }
};

نشر الحلقات على نحو متسلسِل

JSON

يبدو رمز JSON الخاص بحقل القائمة المنسدلة على النحو التالي:

{
  "fields": {
    "FIELDNAME": "LANGUAGE-NEUTRAL-KEY"
  }
}

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

XML

يبدو تنسيق XML لحقل القائمة المنسدلة على النحو التالي:

<field name="FIELDNAME">LANGUAGE-NEUTRAL-KEY</field>

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

التخصيص

يمكن استخدام السمة Blockly.FieldDropdown.ARROW_CHAR لتغيير حرف Unicode الذي يمثّل سهم القائمة المنسدلة.

حقل قائمة منسدلة مع سهم مخصّص

تكون القيمة التلقائية للسمة ARROW_CHAR هي \u25BC (▼) على أجهزة Android و\u25BE (▾) في الحالات الأخرى.

هذه سمة عامة، لذا ستعدّل جميع حقول القائمة المنسدلة عند ضبطها.

يمكن استخدام السمة Blockly.FieldDropdown.MAX_MENU_HEIGHT_VH لتغيير الحد الأقصى لارتفاع القائمة. ويتم تحديدها كنسبة مئوية من ارتفاع إطار العرض، وإطار العرض هو النافذة.

القيمة التلقائية للسمة MAX_MENU_HEIGHT_VH هي 0.45.

هذه سمة عامة، لذا ستعدّل جميع حقول القائمة المنسدلة عند ضبطها.

مطابقة البادئة/اللاحقة

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

بدون مطابقة اللاحقة:

JSON

{
  "type": "dropdown_no_matching",
  "message0": "hello %1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "MODE",
      "options": [
        ["world", "WORLD"],
        ["computer", "CPU"]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['dropdown_no_matching'] = {
  init: function() {
    var options = [
      ['world', 'WORLD'],
      ['computer', 'CPU']
    ];

    this.appendDummyInput()
        .appendField('hello')
        .appendField(new Blockly.FieldDropdown(options), 'MODE');
  }
};

باستخدام مطابقة اللاحقة:

JSON

{
  "type": "dropdown_with_matching",
  "message0": "%1",
  "args0": [
    {
      "type": "field_dropdown",
      "name": "MODE",
      "options": [
        ["hello world", "WORLD"],
        ["hello computer", "CPU"]
      ]
    }
  ]
}

JavaScript

Blockly.Blocks['dropdown_with_matching'] = {
  init: function() {
    var options = [
      ['hello world', 'WORLD'],
      ['hello computer', 'CPU']
    ];

    this.appendDummyInput()
        .appendField(new Blockly.FieldDropdown(options), 'MODE');
  }
};

حقل القائمة المنسدلة مع

إحدى مزايا هذا الأسلوب هي سهولة ترجمة الكتلة إلى لغات أخرى. يتضمّن الرمز السابق السلاسل 'hello' و'world' و'computer'، بينما يتضمّن الرمز المعدّل السلسلتين 'hello world' و'hello computer'. يسهل على المترجمين ترجمة العبارات أكثر من ترجمة الكلمات بشكل منفصل.

من المزايا الأخرى لهذا الأسلوب أنّ ترتيب الكلمات يختلف غالبًا بين اللغات. تخيَّل لغة تستخدم 'world hello' و'computer hello'. ستكتشف خوارزمية مطابقة اللاحقة 'hello' الشائعة وتعرضها بعد القائمة المنسدلة.

ومع ذلك، قد لا يتم أحيانًا العثور على تطابق بين البادئة/اللاحقة. في بعض الحالات، يجب أن تسير كلمتان معًا دائمًا، ويجب عدم استبعاد البادئة. على سبيل المثال، يجب أن يتم استبعاد 'drive' فقط من 'drive red car' و'drive red truck'، وليس 'drive red'. يمكن استخدام مسافة Unicode غير الفاصلة '\u00A0' بدلاً من مسافة عادية لإيقاف أداة مطابقة البادئة/اللاحقة. وبالتالي، يمكن إصلاح المثال أعلاه باستخدام 'drive red\u00A0car' و'drive red\u00A0truck'.

هناك موضع آخر لا ينجح فيه البحث عن البادئة أو اللاحقة، وهو اللغات التي لا تفصل بين الكلمات الفردية بمسافات. اللغة الصينية هي مثال جيد على ذلك. تعني السلسلة '訪問中國' 'visit China'، لاحظ عدم وجود مسافات بين الكلمات. تشير آخر علامتَين ('中國') بشكل جماعي إلى كلمة 'China'، ولكن إذا تم فصلهما، ستشير العلامة الأولى إلى 'centre' والثانية إلى 'country'. لإتاحة مطابقة البادئات واللاحقات في لغات مثل الصينية، ما عليك سوى إدراج مسافة في المكان الذي يجب أن يحدث فيه الفاصل. على سبيل المثال، يؤدي الجمع بين '訪問 中國' و'訪問 美國' إلى "visit [China/USA]"، بينما يؤدي الجمع بين '訪問 中 國' و'訪問 美 國' إلى "visit [centre/beautiful] country".

إنشاء أداة التحقّق من صحة القائمة المنسدلة

قيمة حقل القائمة المنسدلة هي سلسلة مستقلة عن اللغة، لذا يجب أن تقبل أي أدوات التحقّق سلسلة وتعرض سلسلة تمثّل خيارًا متاحًا أو null أو undefined.

إذا عرضت أداة التحقّق أي شيء آخر، سيكون سلوك Blockly غير محدّد وقد يتعطّل برنامجك.

على سبيل المثال، يمكنك تحديد حقل قائمة منسدلة يتضمّن ثلاثة خيارات وأداة التحقّق من الصحة على النحو التالي:

validate: function(newValue) {
  this.getSourceBlock().updateConnections(newValue);
  return newValue;
},

init: function() {
  var options = [
   ['has neither', 'NEITHER'],
   ['has statement', 'STATEMENT'],
   ['has value', 'VALUE'],
  ];

  this.appendDummyInput()
  // Pass the field constructor the options list, the validator, and the name.
      .appendField(new Blockly.FieldDropdown(options, this.validate), 'MODE');
}

تعرض الدالة validate دائمًا القيمة التي تم تمريرها إليها، ولكنها تستدعي الدالة المساعدة updateConnection التي تضيف أو تزيل المدخلات استنادًا إلى قيمة القائمة المنسدلة:

updateConnections: function(newValue) {
  this.removeInput('STATEMENT', /* no error */ true);
  this.removeInput('VALUE', /* no error */ true);
  if (newValue == 'STATEMENT') {
    this.appendStatementInput('STATEMENT');
  } else if (newValue == 'VALUE') {
    this.appendValueInput('VALUE');
  }
}

صورة GIF متحركة تعرض حقل قائمة منسدلة يتضمّن ثلاثة عناصر: &quot;لا شيء&quot; و&quot;عبارة&quot; و &quot;قيمة&quot;. عند اختيار &quot;كلاهما&quot;، لن يكون هناك أي مدخلات. عند اختيار &quot;عبارة&quot;، يكون لها إدخال عبارة. عندما تكون &quot;القيمة&quot; مرتبطة، يكون لديها إدخال &quot;القيمة&quot;.