*************** *** 26,31 **** goog.provide('Blockly.Xml'); // TODO(scr): Fix circular dependencies // goog.require('Blockly.Block'); --- 26,33 ---- goog.provide('Blockly.Xml'); + goog.require('Blockly.Instrument'); // lyn's instrumentation code + // TODO(scr): Fix circular dependencies // goog.require('Blockly.Block'); *************** *** 212,234 **** * @param {!Element} xml XML DOM. */ Blockly.Xml.domToWorkspace = function(workspace, xml) { - var width - if (Blockly.RTL) { - width = workspace.getMetrics().viewWidth; - } - for (var x = 0, xmlChild; xmlChild = xml.childNodes[x]; x++) { - if (xmlChild.nodeName.toLowerCase() == 'block') { - var block = Blockly.Xml.domToBlock(workspace, xmlChild); - var blockX = parseInt(xmlChild.getAttribute('x'), 10); - var blockY = parseInt(xmlChild.getAttribute('y'), 10); - if (!isNaN(blockX) && !isNaN(blockY)) { - block.moveBy(Blockly.RTL ? width - blockX : blockX, blockY); } - } - } }; /** * Decode an XML block tag and create a block (and possibly sub blocks) on the * workspace. * @param {!Blockly.Workspace} workspace The workspace. --- 214,245 ---- * @param {!Element} xml XML DOM. */ Blockly.Xml.domToWorkspace = function(workspace, xml) { + Blockly.Instrument.timer ( + function () { + var width; // Not used in LTR. + if (Blockly.RTL) { + width = workspace.getMetrics().viewWidth; + } + for (var x = 0, xmlChild; xmlChild = xml.childNodes[x]; x++) { + if (xmlChild.nodeName.toLowerCase() == 'block') { + var block = Blockly.Xml.domToBlock(workspace, xmlChild); + var blockX = parseInt(xmlChild.getAttribute('x'), 10); + var blockY = parseInt(xmlChild.getAttribute('y'), 10); + if (!isNaN(blockX) && !isNaN(blockY)) { + block.moveBy(Blockly.RTL ? width - blockX : blockX, blockY); + } + } + } + }, + function (result, timeDiff) { + Blockly.Instrument.stats.domToWorkspaceCalls++; + Blockly.Instrument.stats.domToWorkspaceTime = timeDiff; } + ); }; /** + * Wrapper for domToBlockInner that renders blocks. * Decode an XML block tag and create a block (and possibly sub blocks) on the * workspace. * @param {!Blockly.Workspace} workspace The workspace. *************** *** 239,244 **** * @private */ Blockly.Xml.domToBlock = function(workspace, xmlBlock, opt_reuseBlock) { var block = null; var prototypeName = xmlBlock.getAttribute('type'); if (!prototypeName) { --- 250,317 ---- * @private */ Blockly.Xml.domToBlock = function(workspace, xmlBlock, opt_reuseBlock) { + return Blockly.Instrument.timer ( + function () { + var block = Blockly.Xml.domToBlockInner(workspace, xmlBlock, opt_reuseBlock); + Blockly.Instrument.timer ( + function () { + if (Blockly.Instrument.useRenderDown) { + block.renderDown(); + } + }, + function (result, timeDiffInner) { + if (Blockly.Instrument.useRenderDown) { + Blockly.Instrument.stats.renderDownTime += timeDiffInner; + } + } + ); + // [lyn, 07/03/2014] Special case to handle renaming of event parameters in i8n + if (block && block.type == "component_event") { + // Create a dictionary mapping default event parameter names appearing in body + // to their possibly translated names in some source language + var eventParamDict = Blockly.LexicalVariable.eventParameterDict(block); + var sourceEventParams = []; // Event parameter names in source language + var targetEventParams = []; // Event parameter names in target language + for (var key in eventParamDict) { + var sourceEventParam = eventParamDict[key]; + var targetEventParam = window.parent.BlocklyPanel_getLocalizedParameterName(key); + if (sourceEventParam != targetEventParam) { // Only add to translation if they're different + sourceEventParams.push(sourceEventParam); + targetEventParams.push(targetEventParam); + } + } + if (sourceEventParams.length > 0) { // Do we need to translated some source event parameters? + var childBlocks = block.getChildren(); // should be at most one body block + for (var j= 0, childBlock; childBlock = childBlocks[j]; j++) { + var freeSubstitution = new Blockly.Substitution(sourceEventParams, targetEventParams); + // renameFree does the translation. + Blockly.LexicalVariable.renameFree(childBlock, freeSubstitution); + } + } + } + return block; + }, + function (block, timeDiffOuter) { + Blockly.Instrument.stats.domToBlockCalls++; + Blockly.Instrument.stats.domToBlockTime += timeDiffOuter; + return block; + } + ); + } + + /** + * Version of domToBlock that does not render blocks. + * Decode an XML block tag and create a block (and possibly sub blocks) on the + * workspace. + * @param {!Blockly.Workspace} workspace The workspace. + * @param {!Element} xmlBlock XML block element. + * @param {boolean=} opt_reuseBlock Optional arg indicating whether to + * reinitialize an existing block. + * @return {!Blockly.Block} The root block created. + * @private + */ + Blockly.Xml.domToBlockInner = function(workspace, xmlBlock, opt_reuseBlock) { + Blockly.Instrument.stats.domToBlockInnerCalls++; var block = null; var prototypeName = xmlBlock.getAttribute('type'); if (!prototypeName) { *************** *** 342,348 **** } if (firstRealGrandchild && firstRealGrandchild.nodeName.toLowerCase() == 'block') { - blockChild = Blockly.Xml.domToBlock(workspace, firstRealGrandchild, opt_reuseBlock); if (blockChild.outputConnection) { input.connection.connect(blockChild.outputConnection); --- 415,421 ---- } if (firstRealGrandchild && firstRealGrandchild.nodeName.toLowerCase() == 'block') { + blockChild = Blockly.Xml.domToBlockInner(workspace, firstRealGrandchild, opt_reuseBlock); if (blockChild.outputConnection) { input.connection.connect(blockChild.outputConnection); *************** *** 362,368 **** // This could happen if there is more than one XML 'next' tag. throw 'Next statement is already connected.'; } - blockChild = Blockly.Xml.domToBlock(workspace, firstRealGrandchild, opt_reuseBlock); if (!blockChild.previousConnection) { throw 'Next block does not have previous statement.'; --- 435,441 ---- // This could happen if there is more than one XML 'next' tag. throw 'Next statement is already connected.'; } + blockChild = Blockly.Xml.domToBlockInner(workspace, firstRealGrandchild, opt_reuseBlock); if (!blockChild.previousConnection) { throw 'Next block does not have previous statement.'; *************** *** 375,392 **** } } var collapsed = xmlBlock.getAttribute('collapsed'); if (collapsed) { block.setCollapsed(collapsed == 'true'); } - var next = block.getNextBlock(); - if (next) { - // Next block in a stack needs to square off its corners. - // Rendering a child will render its parent. - next.render(); - } else { - block.render(); - } return block; }; --- 448,491 ---- } } + // [lyn, 10/25/13] collapsing and friends need to be done *after* connections are made to sublocks. + // Otherwise, the subblocks won't be properly processed by block.setCollapsed and friends. + var inline = xmlBlock.getAttribute('inline'); + if (inline) { + block.setInputsInline(inline == 'true'); + } + var disabled = xmlBlock.getAttribute('disabled'); + if (disabled) { + block.setDisabled(disabled == 'true'); + } + var deletable = xmlBlock.getAttribute('deletable'); + if (deletable) { + block.setDeletable(deletable == 'true'); + } + var movable = xmlBlock.getAttribute('movable'); + if (movable) { + block.setMovable(movable == 'true'); + } + var editable = xmlBlock.getAttribute('editable'); + if (editable) { + block.setEditable(editable == 'true'); + } + + if (! Blockly.Instrument.useRenderDown) { + // Neil's original rendering code + var next = block.getNextBlock(); + if (next) { + // Next block in a stack needs to square off its corners. + // Rendering a child will render its parent. + next.render(); + } else { + block.render(); + } + } var collapsed = xmlBlock.getAttribute('collapsed'); if (collapsed) { block.setCollapsed(collapsed == 'true'); } return block; };