ฟิลด์แบบเลื่อนลงจะจัดเก็บสตริงเป็นค่าและสตริงเป็นข้อความ ค่านี้เป็นคีย์ที่ไม่ขึ้นอยู่กับภาษาซึ่งจะใช้สำหรับการเข้าถึงข้อความและ จะไม่ได้รับการแปลเมื่อ 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
ซึ่งเป็นพร็อพเพอร์ตี้ส่วนกลาง ดังนั้นจึงจะแก้ไขฟิลด์แบบเลื่อนลงทั้งหมดเมื่อตั้งค่า
การจับคู่คำนำหน้า/คำต่อท้าย
หากตัวเลือกทั้งหมดในเมนูแบบเลื่อนลงมีคำนำหน้าและ/หรือคำต่อท้ายร่วมกัน ระบบจะแยกคำเหล่านี้ออกโดยอัตโนมัติและแทรกเป็นข้อความแบบคงที่ ตัวอย่างเช่น วิธีสร้างบล็อกเดียวกันมี 2 วิธีดังนี้ (วิธีแรกไม่มี การจับคู่คำต่อท้าย และวิธีที่ 2 มีการจับคู่คำต่อท้าย)
หากไม่มีการจับคู่คำต่อท้าย
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'
และแสดงคำต่อท้ายนั้น
หลังจากเมนูแบบเลื่อนลง
อย่างไรก็ตาม บางครั้งการจับคู่คำนำหน้า/คำต่อท้ายอาจไม่สำเร็จ มีบางกรณีที่
คำ 2 คำควรอยู่ด้วยกันเสมอและไม่ควรแยกคำนำหน้าออก
ตัวอย่างเช่น 'drive red car'
และ 'drive red truck'
ควรมีเพียง 'drive'
เท่านั้นที่แยกออกมา ไม่ใช่ 'drive red'
คุณอาจใช้ช่องว่างที่ไม่ตัดคำของ Unicode '\u00A0'
แทนช่องว่างปกติเพื่อระงับตัวจับคู่คำนำหน้า/คำต่อท้าย ดังนั้น ตัวอย่างข้างต้นจึงแก้ไขได้ด้วย
'drive red\u00A0car'
และ 'drive red\u00A0truck'
อีกกรณีที่การจับคู่คำนำหน้า/คำต่อท้ายไม่สำเร็จคือในภาษาที่ไม่ได้
แยกคำแต่ละคำด้วยการเว้นวรรค ภาษาจีนเป็นตัวอย่างที่ดี สตริง
'訪問中國'
หมายถึง 'visit China'
โปรดสังเกตว่าไม่มีการเว้นวรรคระหว่างคำ
เมื่อรวมกันแล้ว อักขระ 2 ตัวสุดท้าย ('中國'
) คือคำสำหรับ 'China'
แต่หากแยกกัน อักขระทั้งสองจะหมายถึง 'centre'
และ 'country'
ตามลำดับ หากต้องการให้การจับคู่คำนำหน้า/คำต่อท้ายทำงานในภาษาต่างๆ เช่น จีน
เพียงแทรกช่องว่างในตำแหน่งที่ควรมีการเว้นวรรค เช่น '訪問 中國'
และ '訪問 美國'
จะได้ผลลัพธ์เป็น "visit [China/USA]"
ส่วน '訪問 中 國'
และ '訪問 美 國'
จะได้ผลลัพธ์เป็น "visit [centre/beautiful] country"
การสร้างเครื่องมือตรวจสอบแบบเลื่อนลง
ค่าของฟิลด์แบบเลื่อนลงคือสตริงที่เป็นกลางทางภาษา ดังนั้นเครื่องมือตรวจสอบใดๆ จะต้อง
ยอมรับสตริงและส่งคืนสตริงที่เป็นตัวเลือกที่ใช้ได้ null
หรือ
undefined
หากโปรแกรมตรวจสอบแสดงผลอย่างอื่น พฤติกรรมของ Blockly จะไม่แน่นอนและ โปรแกรมอาจขัดข้อง
เช่น คุณอาจกำหนดฟิลด์เมนูแบบเลื่อนลงที่มี 3 ตัวเลือกและตัวตรวจสอบความถูกต้องดังนี้
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');
}
}