ส่วนขยายคือฟังก์ชันที่ทำงานในแต่ละบล็อกของประเภทที่กำหนด สร้าง แล้ว พฤติกรรมเหล่านี้มักจะเพิ่มการกำหนดค่าหรือลักษณะการทำงานที่กำหนดเองบางอย่างลงในบล็อก
Mutator คือส่วนขยายชนิดพิเศษที่เพิ่มการเรียงอันดับแบบกำหนดเอง และ นั่นคือ UI เพื่อบล็อก
ส่วนขยาย
ส่วนขยายคือฟังก์ชันที่ทำงานในแต่ละบล็อกของประเภทที่กำหนด สร้าง แล้ว ผู้ใช้อาจเพิ่มการกำหนดค่าที่กำหนดเอง (เช่น ตั้งค่าเคล็ดลับเครื่องมือของบล็อก) หรือ ลักษณะการทำงานที่กำหนดเอง (เช่น การเพิ่ม Listener เหตุการณ์ลงในบล็อก)
// This extension sets the block's tooltip to be a function which displays
// the parent block's tooltip (if it exists).
Blockly.Extensions.register(
'parent_tooltip_extension',
function() { // this refers to the block that the extension is being run on
var thisBlock = this;
this.setTooltip(function() {
var parent = thisBlock.getParent();
return (parent && parent.getInputsInline() && parent.tooltip) ||
Blockly.Msg.MATH_NUMBER_TOOLTIP;
});
});
ส่วนขยายต้อง "ลงทะเบียน" เพื่อให้เชื่อมโยงกับสตริงได้
จากนั้นกำหนดคีย์สตริงนี้ให้กับพร็อพเพอร์ตี้ extensions
ของ
JSON ของประเภทการบล็อก
เพื่อใช้
ลงในบล็อก
{
//...,
"extensions": ["parent_tooltip_extension",]
}
นอกจากนี้ คุณยังสามารถเพิ่มส่วนขยายได้หลายรายการพร้อมกัน โปรดทราบว่าextensions
ต้องเป็นอาร์เรย์ แม้คุณจะใช้ส่วนขยายเพียง 1 รายการก็ตาม
{
//...,
"extensions": ["parent_tooltip_extension", "break_warning_extension"],
}
มิกซ์กิน
Blockly ยังมอบวิธีที่สะดวกสำหรับสถานการณ์ที่คุณต้องการเพิ่ม พร็อพเพอร์ตี้/ผู้ช่วยบางอย่างจะทำงานร่วมกับบล็อก แต่ไม่สามารถเรียกใช้โดยทันที ช่วงเวลานี้ ให้คุณลงทะเบียน mixin ได้ ที่มีพร็อพเพอร์ตี้/เมธอดเพิ่มเติมทั้งหมดของคุณ ออบเจ็กต์มิกซ์อิน จะรวมไว้ในฟังก์ชันที่ใช้การผสมทุกครั้งที่อินสแตนซ์ของ ระบบจะสร้างประเภทการบล็อกที่กำหนดขึ้น
Blockly.Extensions.registerMixin('my_mixin', {
someProperty: 'a cool value',
someMethod: function() {
// Do something cool!
}
))`
คีย์สตริงที่เชื่อมโยงกับมิกซ์อินสามารถอ้างอิงได้ใน JSON ได้เช่นเดียวกับอื่นๆ ส่วนขยาย
{
//...,
"extensions": ["my_mixin"],
}
กลายพันธุ์
Mutator คือส่วนขยายประเภทพิเศษที่เพิ่มการเรียงอันดับเพิ่มเติม (Extra
ที่ระบบบันทึกและโหลดแล้ว) ไปยังบล็อก ตัวอย่างเช่น แอปและบริการ
บล็อก controls_if
และ list_create_with
ต้องมีอนุกรมเพิ่มเติมเพื่อให้
พวกเขาสามารถบันทึกจำนวนอินพุตที่มี
โปรดทราบว่าการเปลี่ยนรูปร่างของบล็อกไม่ได้หมายความว่าคุณจะต้อง
การเรียงอันดับเพิ่มเติม เช่น การเปลี่ยนแปลงการบล็อก math_number_property
แต่มีรูปแบบขึ้นอยู่กับช่องแบบเลื่อนลง ซึ่งมีค่าอยู่แล้ว
เรียงต่อกัน ดังนั้น จึงสามารถใช้ฟิลด์
โปรแกรมตรวจสอบ และไม่
ก็ต้องการตัวกลายพันธุ์
ดูการแปลงอนุกรม page สำหรับ ซึ่งเป็นข้อมูลเพิ่มเติมเกี่ยวกับเวลาที่คุณต้องการเปลี่ยนแปลงและเวลาที่คุณไม่ต้องการ
Mutator ยังมี UI ในตัวเพื่อให้ผู้ใช้เปลี่ยนรูปร่างของบล็อกได้ คุณมีวิธีการที่ไม่บังคับบางอย่าง
ฮุกการทำให้เป็นอนุกรม
Mutator มีฮุกการเรียงอันดับ 2 คู่ที่ใช้งานได้ ตะขอ 1 คู่ จะทำงานร่วมกับระบบการเรียงอันดับ JSON ใหม่ และอีกคู่หนึ่งจะทำงานร่วมกับ ระบบการเรียงอันดับ XML เก่า คุณต้องระบุคู่เหล่านี้อย่างน้อย 1 คู่
SaveExtraState และloadExtraState
saveExtraState
และ loadExtraState
เป็นฮุกการเรียงอันดับที่ใช้งานได้กับ
ระบบการเรียงอันดับ JSON ใหม่ saveExtraState
แสดงผล JSON ที่ทำให้อนุกรมได้
ค่าที่แสดงถึงสถานะเพิ่มเติมของการบล็อก และ loadExtraState
ยอมรับค่าที่ทำให้เป็นอนุกรม JSON เดียวกันได้และนำไปใช้กับการบล็อก
// These are the serialization hooks for the lists_create_with block.
saveExtraState: function() {
return {
'itemCount': this.itemCount_,
};
},
loadExtraState: function(state) {
this.itemCount_ = state['itemCount'];
// This is a helper function which adds or removes inputs from the block.
this.updateShape_();
},
JSON ที่ได้จะมีลักษณะดังนี้
{
"type": "lists_create_with",
"extraState": {
"itemCount": 3 // or whatever the count is
}
}
ไม่มีสถานะ
หากการบล็อกอยู่ในสถานะเริ่มต้นขณะมีการต่อเนื่องกัน
เมธอด saveExtraState
จะส่งกลับ null
เพื่อระบุได้ หาก
เมธอด saveExtraState
แสดงผล null
จึงไม่มีการเพิ่มพร็อพเพอร์ตี้ extraState
ลงใน
JSON ซึ่งจะทำให้ไฟล์บันทึกมีขนาดเล็ก
การทำให้เป็นอนุกรมและการสำรองข้อมูลแบบเต็มรูปแบบ
saveExtraState
จะได้รับพารามิเตอร์ doFullSerialization
ที่ไม่บังคับด้วย ช่วงเวลานี้
จะใช้โดยบล็อกสถานะการอ้างอิงที่เรียงลำดับโดย
serializer (เช่น การสำรองข้อมูลโมเดลข้อมูล) พารามิเตอร์จะส่งสัญญาณว่า
สถานะที่อ้างอิงจะใช้ไม่ได้เมื่อบล็อกมีการดีซีเรียลไลซ์ ดังนั้น
ควรเรียงลำดับสถานะของพื้นหลังทั้งหมด ตัวอย่างเช่น นี่คือ
เป็นจริงเมื่อบล็อกหนึ่งๆ มีการเรียงลำดับ หรือเมื่อมีการคัดลอกบล็อก
กรณีการใช้งานที่พบบ่อย 2 กรณีมีดังนี้
- เมื่อโหลดบล็อกเดี่ยวลงในพื้นที่ทำงานที่มีข้อมูลสนับสนุน ไม่มีโมเดล มีข้อมูลในสถานะของตัวเองเพียงพอที่จะ สร้างโมเดลข้อมูลใหม่
- เมื่อมีการคัดลอกบล็อก จะมีการสร้างข้อมูลสำรองใหม่เสมอ แทนการอ้างอิงรูปแบบที่มีอยู่
องค์ประกอบที่ใช้ค่านี้คือ
การบล็อก @blockly/block-shareable-procedures ปกติ
โมเดลจะสร้างการอ้างอิงไปยังโมเดลข้อมูลสนับสนุน ซึ่งจัดเก็บสถานะไว้
แต่ถ้าพารามิเตอร์ doFullSerialization
เป็นจริง พารามิเตอร์จะเรียงลำดับทั้งหมด
ของรัฐของตน บล็อกกระบวนการที่แชร์ได้จะใช้วิธีนี้ เพื่อให้แน่ใจว่าเมื่อ
มีการคัดลอกและวางโมเดลข้อมูล
ในการสร้างรูปแบบข้อมูลสนับสนุนใหม่ แทนการอ้างอิง
โมเดลที่มีอยู่แล้ว
MutationToDom และ domToMutation
mutationToDom
และ domToMutation
เป็นฮุกการเรียงอันดับที่ใช้งานได้กับ
ระบบการเรียงอันดับ XML เก่า ใช้ฮุกเหล่านี้เมื่อจำเป็นเท่านั้น (เช่น คุณ
ทำงานบนฐานของโค้ดเก่าที่ยังไม่ได้ย้ายข้อมูล) มิฉะนั้น ให้ใช้
saveExtraState
และ loadExtraState
mutationToDom
แสดงผลโหนด XML ที่แสดงถึงสถานะพิเศษของ
บล็อก และ domToMutation
ยอมรับโหนด XML เดียวกันและใช้สถานะกับ
การบล็อก
// These are the old XML serialization hooks for the lists_create_with block.
mutationToDom: function() {
// You *must* create a <mutation></mutation> element.
// This element can have children.
var container = Blockly.utils.xml.createElement('mutation');
container.setAttribute('items', this.itemCount_);
return container;
},
domToMutation: function(xmlElement) {
this.itemCount_ = parseInt(xmlElement.getAttribute('items'), 10);
// This is a helper function which adds or removes inputs from the block.
this.updateShape_();
},
ไฟล์ XML ที่ได้จะมีลักษณะดังนี้
<block type="lists_create_with">
<mutation items="3"></mutation>
</block>
หากฟังก์ชัน mutationToDom
แสดงผลเป็น Null จะไม่มีองค์ประกอบเพิ่มเติม
เพิ่มลงใน XML แล้ว
ตะขอ UI
หากคุณมีฟังก์ชันบางอย่างเป็นส่วนหนึ่งของ Mutator ของคุณ Blockly จะเพิ่ม "Mutator" เป็นค่าเริ่มต้น UI ไปยังบล็อกของคุณ
คุณไม่ต้องใช้ UI นี้ ถ้าต้องการเพิ่มการเรียงลำดับเพิ่มเติม คุณสามารถ ใช้ UI ที่กำหนดเอง เช่น blocks-plus-delete ปลั๊กอิน หรือคุณไม่สามารถใช้ UI เลยก็ได้
เขียนและแยกองค์ประกอบ
UI เริ่มต้นอาศัยฟังก์ชัน compose
และ decompose
decompose
"ระเบิด" บล็อกลงในบล็อกย่อยที่เล็กลง ซึ่งสามารถย้ายได้
เพิ่ม และลบ ฟังก์ชันนี้ควรแสดง "บล็อกด้านบนสุด" ซึ่งก็คือ
บล็อกหลักในพื้นที่ทำงานของ Mutator ที่การบล็อกย่อยเชื่อมต่อกัน
จากนั้น compose
จะตีความการกำหนดค่าการบล็อกย่อยและใช้เพื่อ
แก้ไขบล็อกหลัก ฟังก์ชันนี้ควรยอมรับ "บล็อกด้านบนสุด" ซึ่งก็คือ
decompose
แสดงผลเป็นพารามิเตอร์
โปรดทราบว่าฟังก์ชันเหล่านี้จะ "ผสมผสานกัน" ให้กับการบล็อกที่ "เปลี่ยนแปลง" ดังนั้น this
เพื่ออ้างอิงการบล็อกนั้นได้
// These are the decompose and compose functions for the lists_create_with block.
decompose: function(workspace) {
// This is a special sub-block that only gets created in the mutator UI.
// It acts as our "top block"
var topBlock = workspace.newBlock('lists_create_with_container');
topBlock.initSvg();
// Then we add one sub-block for each item in the list.
var connection = topBlock.getInput('STACK').connection;
for (var i = 0; i < this.itemCount_; i++) {
var itemBlock = workspace.newBlock('lists_create_with_item');
itemBlock.initSvg();
connection.connect(itemBlock.previousConnection);
connection = itemBlock.nextConnection;
}
// And finally we have to return the top-block.
return topBlock;
},
// The container block is the top-block returned by decompose.
compose: function(topBlock) {
// First we get the first sub-block (which represents an input on our main block).
var itemBlock = topBlock.getInputTargetBlock('STACK');
// Then we collect up all of the connections of on our main block that are
// referenced by our sub-blocks.
// This relates to the saveConnections hook (explained below).
var connections = [];
while (itemBlock && !itemBlock.isInsertionMarker()) { // Ignore insertion markers!
connections.push(itemBlock.valueConnection_);
itemBlock = itemBlock.nextConnection &&
itemBlock.nextConnection.targetBlock();
}
// Then we disconnect any children where the sub-block associated with that
// child has been deleted/removed from the stack.
for (var i = 0; i < this.itemCount_; i++) {
var connection = this.getInput('ADD' + i).connection.targetConnection;
if (connection && connections.indexOf(connection) == -1) {
connection.disconnect();
}
}
// Then we update the shape of our block (removing or adding iputs as necessary).
// `this` refers to the main block.
this.itemCount_ = connections.length;
this.updateShape_();
// And finally we reconnect any child blocks.
for (var i = 0; i < this.itemCount_; i++) {
connections[i].reconnect(this, 'ADD' + i);
}
},
saveConnections
หรือคุณจะกำหนดฟังก์ชัน saveConnections
ที่จะทำงานร่วมกับ
UI เริ่มต้น ฟังก์ชันนี้ช่วยให้คุณมีโอกาสเชื่อมโยงบุตรหลานของ
บล็อกหลัก (ซึ่งมีอยู่ในพื้นที่ทำงานหลัก) ที่มีการบล็อกย่อยที่มีอยู่ใน
Mutator Workspace จากนั้นคุณสามารถใช้ข้อมูลนี้เพื่อตรวจสอบว่า compose
เชื่อมต่อรายการย่อยของบล็อกหลักอีกครั้งอย่างถูกต้องเมื่อ
บล็อกย่อยต่างๆ ได้รับการจัดระเบียบใหม่
saveConnections
ควรยอมรับ "องค์ประกอบยอดนิยม" ส่งคืนโดย decompose
ของคุณ
เป็นพารามิเตอร์ หากกำหนดฟังก์ชัน saveConnections
ไว้ Blockly
จะโทรหาหมายเลขนั้นก่อนโทรหา compose
saveConnections: function(topBlock) {
// First we get the first sub-block (which represents an input on our main block).
var itemBlock = topBlock.getInputTargetBlock('STACK');
// Then we go through and assign references to connections on our main block
// (input.connection.targetConnection) to properties on our sub blocks
// (itemBlock.valueConnection_).
var i = 0;
while (itemBlock) {
// `this` refers to the main block (which is being "mutated").
var input = this.getInput('ADD' + i);
// This is the important line of this function!
itemBlock.valueConnection_ = input && input.connection.targetConnection;
i++;
itemBlock = itemBlock.nextConnection &&
itemBlock.nextConnection.targetBlock();
}
},
กำลังลงทะเบียน
Mutator เป็นเพียงส่วนขยายพิเศษ พวกเขาจึงต้อง ลงทะเบียนก่อนที่คุณจะสามารถใช้ใน JSON ของประเภทการบล็อกของคุณ คำจำกัดความ
// Function signature.
Blockly.Extensions.registerMutator(name, mixinObj, opt_helperFn, opt_blockList);
// Example call.
Blockly.Extensions.registerMutator(
'controls_if_mutator',
{ /* mutator methods */ },
undefined,
['controls_if_elseif', 'controls_if_else']);
name
: สตริงที่จะเชื่อมโยงกับ Mutator เพื่อให้คุณใช้ใน JSON ได้mixinObj
: ออบเจ็กต์ที่มีเมธอดการเปลี่ยนแปลงต่างๆ เช่นsaveExtraState
และloadExtraState
opt_helperFn
: ฟังก์ชันผู้ช่วยที่ไม่บังคับซึ่งจะช่วย บนบล็อกหลังจากที่ผสมมิกซ์opt_blockList
: อาร์เรย์ที่ไม่บังคับของประเภทการบล็อก (เป็นสตริง) ที่จะนำไปใช้ ลงใน Flyout ใน UI ตัวกลายพันธุ์เริ่มต้น หากเมธอด UI ยัง กำหนดไว้
โปรดทราบว่าบล็อกแต่ละประเภทมี Mutator เพียงตัวเดียวเท่านั้น ซึ่งไม่เหมือนกับส่วนขยาย
{
//...
"mutator": "controls_if_mutator"
}
ฟังก์ชันตัวช่วย
นอกจากการผสมแล้ว Mutator อาจลงทะเบียนฟังก์ชันตัวช่วย ฟังก์ชันนี้คือ จะทำงานในแต่ละบล็อกของประเภทที่กำหนดหลังจากที่สร้างขึ้น และมิกซ์ของ Obj เพิ่ม แล้ว โดยสามารถใช้เพื่อเพิ่มทริกเกอร์หรือเอฟเฟกต์อื่นๆ ในการกลายพันธุ์ได้
ตัวอย่างเช่น คุณสามารถเพิ่มตัวช่วยไปยังบล็อกแบบรายการซึ่งตั้งค่า จำนวนรายการเริ่มต้น:
var helper = function() {
this.itemCount_ = 5;
this.updateShape();
}