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

حقل القائمة المنسدلة مع فتح المحرّر

حقل القائمة المنسدلة في كتلة مصغّرة

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

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 extension.
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 extension.
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');
}
}
