뮤테이터는 블록에 추가 직렬화 (저장되고 로드되는 추가 상태)를 추가하는 믹스인입니다. 예를 들어 내장된 controls_if
및 list_create_with
블록은 입력 개수를 저장할 수 있도록 추가 직렬화가 필요합니다. 사용자가 블록의 모양을 변경할 수 있도록 UI를 추가할 수도 있습니다.
블록의 모양을 변경한다고 해서 반드시 추가 직렬화가 필요한 것은 아닙니다. 예를 들어 math_number_property
블록은 모양이 변경되지만, 값은 이미 직렬화된 드롭다운 필드를 기반으로 변경됩니다. 따라서 필드 유효성 검사기를 사용하면 되고 변경자는 필요하지 않습니다.
뮤테이터가 필요한 경우와 필요하지 않은 경우에 관한 자세한 내용은 직렬화 페이지를 참고하세요.
선택적 메서드를 제공하는 경우 뮤테이터는 사용자가 블록의 모양을 변경할 수 있는 내장 UI도 제공합니다.
직렬화 후크
뮤테이터에는 함께 작동하는 두 쌍의 직렬화 후크가 있습니다. 한 쌍의 후크는 새로운 JSON 직렬화 시스템과 작동하고 다른 쌍은 기존 XML 직렬화 시스템과 작동합니다. 이러한 쌍 중 하나 이상을 제공해야 합니다.
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
매개변수도 수신합니다. 이는 다른 직렬화기 (예: 지원 데이터 모델)에 의해 직렬화된 상태를 참조하는 블록에서 사용됩니다. 이 매개변수는 블록이 역직렬화될 때 참조된 상태를 사용할 수 없음을 나타내므로 블록은 지원 상태를 모두 직렬화해야 합니다. 예를 들어 개별 블록이 직렬화되거나 블록이 복사하여 붙여넣기되는 경우에 해당합니다.
이에 대한 두 가지 일반적인 사용 사례는 다음과 같습니다.
- 개별 블록이 지원 데이터 모델이 없는 워크스페이스에 로드되면 새 데이터 모델을 만들기에 충분한 정보가 자체 상태에 있습니다.
- 블록을 복사하여 붙여넣으면 기존 블록을 참조하는 대신 항상 새로운 지원 데이터 모델이 생성됩니다.
이를 사용하는 블록의 예로는 @blockly/block-shareable-procedures 블록이 있습니다. 일반적으로 상태를 저장하는 지원 데이터 모델에 대한 참조를 직렬화합니다.
하지만 doFullSerialization
매개변수가 true이면 모든 상태를 직렬화합니다. 공유 가능한 절차 블록은 이를 사용하여 복사 후 붙여넣기할 때 기존 모델을 참조하는 대신 새 지원 데이터 모델을 생성하도록 합니다.
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 후크
뮤테이터의 일부로 특정 함수를 제공하면 Blockly가 블록에 기본 '뮤테이터' UI를 추가합니다.
추가 직렬화를 추가하려면 이 UI를 사용하지 않아도 됩니다. blocks-plus-minus 플러그인에서 제공하는 것과 같은 맞춤 UI를 사용하거나 UI를 전혀 사용하지 않을 수도 있습니다.
구성 및 분해
기본 UI는 compose
및 decompose
함수를 사용합니다.
decompose
는 블록을 이동, 추가, 삭제할 수 있는 더 작은 하위 블록으로 '분해'합니다. 이 함수는 하위 블록이 연결되는 변형기 작업공간의 기본 블록인 '상위 블록'을 반환해야 합니다.
그런 다음 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
원하는 경우 기본 UI와 함께 작동하는 saveConnections
함수를 정의할 수도 있습니다. 이 함수를 사용하면 기본 작업 공간에 있는 기본 블록의 하위 요소를 mutator 작업 공간에 있는 하위 블록과 연결할 수 있습니다. 그런 다음 이 데이터를 사용하여 하위 블록이 재구성될 때 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();
}
},
등록 중
뮤테이터는 특수한 종류의 믹스인이므로 블록 유형의 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
: JSON에서 사용할 수 있도록 변이원과 연결할 문자열입니다.mixinObj
: 다양한 변이 메서드가 포함된 객체입니다. 예:saveExtraState
및loadExtraState
opt_helperFn
: 믹스인이 혼합된 후 블록에서 실행되는 선택적 도우미 함수입니다.opt_blockList
: UI 메서드도 정의된 경우 기본 뮤테이터 UI의 플라이아웃에 추가될 블록 유형 (문자열)의 선택적 배열입니다.
확장 프로그램과 달리 각 블록 유형에는 하나의 뮤테이터만 있을 수 있습니다.
{
//...
"mutator": "controls_if_mutator"
}
도우미 함수
믹신과 함께 뮤데이터는 도우미 함수를 등록할 수 있습니다. 이 함수는 생성되고 mixinObj
이 추가된 후 지정된 유형의 각 블록에서 실행됩니다. 이를 사용하여 변이에 트리거나 효과를 추가할 수 있습니다.
예를 들어 초기 항목 수를 설정하는 도우미를 목록과 유사한 블록에 추가할 수 있습니다.
var helper = function() {
this.itemCount_ = 5;
this.updateShape();
}