diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 58bc6b5c5..d877f6cab 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -156,6 +156,20 @@ Blockly.FieldDropdown.fromJson = function(options) { return new Blockly.FieldDropdown(options['options'], undefined, options); }; +/** + * Sets the field's value based on the given XML element. Should only be + * called by Blockly.Xml. + * @param {!Element} fieldElement The element containing info about the + * field's state. + * @package + */ +Blockly.FieldDropdown.prototype.fromXml = function(fieldElement) { + if (this.isOptionListDynamic()) { + this.getOptions(false); + } + this.setValue(fieldElement.textContent); +}; + /** * Serializable fields are saved by the XML renderer, non-serializable fields * are not. Editable fields should also be serializable. diff --git a/core/xml.js b/core/xml.js index cb497f236..7a887a29e 100644 --- a/core/xml.js +++ b/core/xml.js @@ -741,6 +741,7 @@ Blockly.Xml.applyDataTagNodes_ = function(xmlChildren, block) { block.data = xmlChild.textContent; } }; + /** * Applies field tag child nodes to the given block. * @param {Array} xmlChildren Child nodes. @@ -796,17 +797,11 @@ Blockly.Xml.applyInputTagNodes_ = function(xmlChildren, workspace, block, } var childBlockInfo = Blockly.Xml.findChildBlocks_(xmlChild); if (childBlockInfo.childBlockElement) { - // Create child block. - var blockChild = Blockly.Xml.domToBlockHeadless_( - childBlockInfo.childBlockElement, workspace); - if (blockChild.outputConnection) { - input.connection.connect(blockChild.outputConnection); - } else if (blockChild.previousConnection) { - input.connection.connect(blockChild.previousConnection); - } else { - throw TypeError( - 'Child block does not have output or previous statement.'); + if (!input.connection) { + throw TypeError('Input connection does not exist.'); } + Blockly.Xml.domToBlockHeadless_(childBlockInfo.childBlockElement, + workspace, input.connection, false); } // Set shadow after so we don't create a shadow we delete immediately. if (childBlockInfo.childShadowElement) { @@ -834,12 +829,10 @@ Blockly.Xml.applyNextTagNodes_ = function(xmlChildren, workspace, block) { if (block.nextConnection.isConnected()) { throw TypeError('Next statement is already connected.'); } - var blockChild = Blockly.Xml.domToBlockHeadless_( - childBlockInfo.childBlockElement, workspace); - if (!blockChild.previousConnection) { - throw TypeError('Next block does not have previous statement.'); - } - block.nextConnection.connect(blockChild.previousConnection); + // Create child block. + Blockly.Xml.domToBlockHeadless_(childBlockInfo.childBlockElement, + workspace, block.nextConnection, + true); } // Set shadow after so we don't create a shadow we delete immediately. if (childBlockInfo.childShadowElement && block.nextConnection) { @@ -854,10 +847,15 @@ Blockly.Xml.applyNextTagNodes_ = function(xmlChildren, workspace, block) { * workspace. * @param {!Element} xmlBlock XML block element. * @param {!Blockly.Workspace} workspace The workspace. + * @param {!Blockly.Connection=} parentConnection The parent connection to + * to connect this block to after instantiating. + * @param {boolean=} connectedToParentNext Whether the provided parent connection + * is a next connection, rather than output or statement. * @return {!Blockly.Block} The root block created. * @private */ -Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { +Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace, + parentConnection, connectedToParentNext) { var block = null; var prototypeName = xmlBlock.getAttribute('type'); if (!prototypeName) { @@ -873,6 +871,28 @@ Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { Blockly.Xml.applyMutationTagNodes_(xmlChildNameMap.mutation, block); Blockly.Xml.applyCommentTagNodes_(xmlChildNameMap.comment, block); Blockly.Xml.applyDataTagNodes_(xmlChildNameMap.data, block); + + // Connect parent after processing mutation and before setting fields. + if (parentConnection) { + if (connectedToParentNext) { + if (block.previousConnection) { + parentConnection.connect(block.previousConnection); + } else { + throw TypeError( + 'Next block does not have previous statement.'); + } + } else { + if (block.outputConnection) { + parentConnection.connect(block.outputConnection); + } else if (block.previousConnection) { + parentConnection.connect(block.previousConnection); + } else { + throw TypeError( + 'Child block does not have output or previous statement.'); + } + } + } + Blockly.Xml.applyFieldTagNodes_(xmlChildNameMap.field, block); Blockly.Xml.applyInputTagNodes_( xmlChildNameMap.input, workspace, block, prototypeName);