يخزّن حقل القائمة المنسدلة سلسلة كقيمة وسلسلة كنص. القيمة هي مفتاح محايد للغة سيتم استخدامه للوصول إلى النص ولن تتم ترجمته عند التبديل بين اللغات في 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
.
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');
}
}