From 601ea15b751f154e906246fbe283016d33b5bf43 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 4 Apr 2016 16:40:08 -0700 Subject: [PATCH 1/9] Rename JSON's 'id' to 'type'. Issue #245. --- demos/blockfactory/factory.js | 4 ++-- demos/graph/index.html | 32 ++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/demos/blockfactory/factory.js b/demos/blockfactory/factory.js index 002b438d5..246b2b555 100644 --- a/demos/blockfactory/factory.js +++ b/demos/blockfactory/factory.js @@ -99,8 +99,8 @@ function updateLanguage() { */ function formatJson_(blockType, rootBlock) { var JS = {}; - // ID is not used by Blockly, but may be used by a loader. - JS.id = blockType; + // Type is not used by Blockly, but may be used by a loader. + JS.type = blockType; // Generate inputs. var message = []; var args = []; diff --git a/demos/graph/index.html b/demos/graph/index.html index fd84a62eb..709fd502c 100644 --- a/demos/graph/index.html +++ b/demos/graph/index.html @@ -193,12 +193,13 @@ if (typeof google == 'object') { Blockly.Blocks['graph_get_x'] = { // x variable getter. init: function() { - this.setHelpUrl(Blockly.Msg.VARIABLES_GET_HELPURL); - this.setColour(330); - this.appendDummyInput() - .appendField('x'); - this.setOutput(true, 'Number'); - this.setTooltip(Blockly.Msg.VARIABLES_GET_TOOLTIP); + this.jsonInit({ + "message0": "x", + "output": "Number", + "colour": Blockly.Blocks.variables.HUE, + "tooltip": Blockly.Msg.VARIABLES_GET_TOOLTIP, + "helpUrl": Blockly.Msg.VARIABLES_GET_HELPURL + }); } }; @@ -210,12 +211,19 @@ Blockly.JavaScript['graph_get_x'] = function(block) { Blockly.Blocks['graph_set_y'] = { // y variable setter. init: function() { - this.setHelpUrl(Blockly.Msg.VARIABLES_SET_HELPURL); - this.setColour(330); - this.appendValueInput('VALUE') - .appendField('y =') - .setCheck('Number'); - this.setTooltip(Blockly.Msg.VARIABLES_SET_TOOLTIP); + this.jsonInit({ + "message0": "y = %1", + "args0": [ + { + "type": "input_value", + "name": "VALUE", + "check": "Number" + } + ], + "colour": Blockly.Blocks.variables.HUE, + "tooltip": Blockly.Msg.VARIABLES_SET_TOOLTIP, + "helpUrl": Blockly.Msg.VARIABLES_SET_HELPURL + }); } }; From 4ac12045508cde39db7e77ba5fbcdf85b657e2f0 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 4 Apr 2016 17:47:15 -0700 Subject: [PATCH 2/9] Set field.sourceBlock in headless Blockly. --- core/field.js | 17 ++++++++++++----- core/field_checkbox.js | 2 +- core/field_dropdown.js | 3 +-- core/field_image.js | 8 +++----- core/field_label.js | 9 +++------ core/field_variable.js | 2 +- core/inject.js | 4 ++-- core/input.js | 3 ++- 8 files changed, 25 insertions(+), 23 deletions(-) diff --git a/core/field.js b/core/field.js index 6db2f0c97..30078e0f3 100644 --- a/core/field.js +++ b/core/field.js @@ -118,15 +118,22 @@ Blockly.Field.NBSP = '\u00A0'; Blockly.Field.prototype.EDITABLE = true; /** - * Install this field on a block. + * Attach this field to a block. * @param {!Blockly.Block} block The block containing this field. */ -Blockly.Field.prototype.init = function(block) { - if (this.sourceBlock_) { +Blockly.Field.prototype.setSourceBlock = function(block) { + goog.asserts.assert(!this.sourceBlock_, 'Field already bound to a block.'); + this.sourceBlock_ = block; +}; + +/** + * Install this field on a block. + */ +Blockly.Field.prototype.init = function() { + if (this.fieldGroup_) { // Field has already been initialized once. return; } - this.sourceBlock_ = block; // Build the DOM. this.fieldGroup_ = Blockly.createSvgElement('g', {}, null); if (!this.visible_) { @@ -144,7 +151,7 @@ Blockly.Field.prototype.init = function(block) { this.fieldGroup_); this.updateEditable(); - block.getSvgRoot().appendChild(this.fieldGroup_); + this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); this.mouseUpWrapper_ = Blockly.bindEvent_(this.fieldGroup_, 'mouseup', this, this.onMouseUp_); // Force a render. diff --git a/core/field_checkbox.js b/core/field_checkbox.js index cdf69b29a..183e226c9 100644 --- a/core/field_checkbox.js +++ b/core/field_checkbox.js @@ -61,7 +61,7 @@ Blockly.FieldCheckbox.prototype.CURSOR = 'default'; * @param {!Blockly.Block} block The block containing this text. */ Blockly.FieldCheckbox.prototype.init = function(block) { - if (this.sourceBlock_) { + if (this.fieldGroup_) { // Checkbox has already been initialized once. return; } diff --git a/core/field_dropdown.js b/core/field_dropdown.js index 332a7b787..d715c8c72 100644 --- a/core/field_dropdown.js +++ b/core/field_dropdown.js @@ -80,11 +80,10 @@ Blockly.FieldDropdown.prototype.CURSOR = 'default'; * @param {!Blockly.Block} block The block containing this text. */ Blockly.FieldDropdown.prototype.init = function(block) { - if (this.sourceBlock_) { + if (this.fieldGroup_) { // Dropdown has already been initialized once. return; } - // Add dropdown arrow: "option ▾" (LTR) or "▾ אופציה" (RTL) this.arrow_ = Blockly.createSvgElement('tspan', {}, null); this.arrow_.appendChild(document.createTextNode( diff --git a/core/field_image.js b/core/field_image.js index b24e75c54..71d8052f9 100644 --- a/core/field_image.js +++ b/core/field_image.js @@ -67,14 +67,12 @@ Blockly.FieldImage.prototype.EDITABLE = false; /** * Install this image on a block. - * @param {!Blockly.Block} block The block containing this text. */ -Blockly.FieldImage.prototype.init = function(block) { - if (this.sourceBlock_) { +Blockly.FieldImage.prototype.init = function() { + if (this.fieldGroup_) { // Image has already been initialized once. return; } - this.sourceBlock_ = block; // Build the DOM. /** @type {SVGElement} */ this.fieldGroup_ = Blockly.createSvgElement('g', {}, null); @@ -97,7 +95,7 @@ Blockly.FieldImage.prototype.init = function(block) { 'width': this.width_ + 'px', 'fill-opacity': 0}, this.fieldGroup_); } - block.getSvgRoot().appendChild(this.fieldGroup_); + this.sourceBlock_.getSvgRoot().appendChild(this.fieldGroup_); // Configure the field to be transparent with respect to tooltips. var topElement = this.rectElement_ || this.imageElement_; diff --git a/core/field_label.js b/core/field_label.js index 5e7a6cbb9..cb5fa7d39 100644 --- a/core/field_label.js +++ b/core/field_label.js @@ -53,15 +53,12 @@ Blockly.FieldLabel.prototype.EDITABLE = false; /** * Install this text on a block. - * @param {!Blockly.Block} block The block containing this text. */ -Blockly.FieldLabel.prototype.init = function(block) { - if (this.sourceBlock_) { +Blockly.FieldLabel.prototype.init = function() { + if (this.textElement_) { // Text has already been initialized once. return; } - this.sourceBlock_ = block; - // Build the DOM. this.textElement_ = Blockly.createSvgElement('text', {'class': 'blocklyText', 'y': this.size_.height - 5}, null); @@ -71,7 +68,7 @@ Blockly.FieldLabel.prototype.init = function(block) { if (!this.visible_) { this.textElement_.style.display = 'none'; } - block.getSvgRoot().appendChild(this.textElement_); + this.sourceBlock_.getSvgRoot().appendChild(this.textElement_); // Configure the field to be transparent with respect to tooltips. this.textElement_.tooltip = this.sourceBlock_; diff --git a/core/field_variable.js b/core/field_variable.js index 3cd4c5deb..8e5bac966 100644 --- a/core/field_variable.js +++ b/core/field_variable.js @@ -82,7 +82,7 @@ Blockly.FieldVariable.prototype.setValidator = function(handler) { * @param {!Blockly.Block} block The block containing this text. */ Blockly.FieldVariable.prototype.init = function(block) { - if (this.sourceBlock_) { + if (this.fieldGroup_) { // Dropdown has already been initialized once. return; } diff --git a/core/inject.js b/core/inject.js index 2e8d93a5d..0db7594c1 100644 --- a/core/inject.js +++ b/core/inject.js @@ -326,8 +326,8 @@ Blockly.inject.bindDocumentEvents_ = function() { /** * Load sounds for the given workspace. - * @param options {string} The path to the media directory. - * @param workspace {!Blockly.Workspace} The workspace to load sounds for. + * @param {string} options The path to the media directory. + * @param {!Blockly.Workspace} workspace The workspace to load sounds for. * @private */ Blockly.inject.loadSounds_ = function(pathToMedia, workspace) { diff --git a/core/input.js b/core/input.js index b92433769..8ca265586 100644 --- a/core/input.js +++ b/core/input.js @@ -84,8 +84,9 @@ Blockly.Input.prototype.appendField = function(field, opt_name) { if (goog.isString(field)) { field = new Blockly.FieldLabel(/** @type {string} */ (field)); } + field.setSourceBlock(this.sourceBlock_); if (this.sourceBlock_.rendered) { - field.init(this.sourceBlock_); + field.init(); } field.name = opt_name; From 4e42a1b78ee7bce8f6c4ae8a6600bfc6dbcc3209 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Mon, 4 Apr 2016 18:31:41 -0700 Subject: [PATCH 3/9] Swap order of arguments on domToWorkspace. --- appengine/storage.js | 4 ++-- core/connection.js | 2 +- core/contextmenu.js | 2 +- core/events.js | 4 ++-- core/flyout.js | 4 ++-- core/workspace_svg.js | 2 +- core/xml.js | 38 ++++++++++++++++++++++++----------- demos/blockfactory/factory.js | 2 +- demos/code/code.js | 6 +++--- demos/generator/index.html | 4 ++-- demos/graph/index.html | 4 ++-- demos/headless/index.html | 2 +- demos/interpreter/index.html | 4 ++-- demos/plane/plane.js | 4 ++-- demos/rtl/index.html | 4 ++-- tests/generators/index.html | 2 +- tests/playground.html | 4 ++-- 17 files changed, 53 insertions(+), 39 deletions(-) diff --git a/appengine/storage.js b/appengine/storage.js index 87d9cae76..8141806d5 100644 --- a/appengine/storage.js +++ b/appengine/storage.js @@ -60,7 +60,7 @@ BlocklyStorage.restoreBlocks = function(opt_workspace) { if ('localStorage' in window && window.localStorage[url]) { var workspace = opt_workspace || Blockly.getMainWorkspace(); var xml = Blockly.Xml.textToDom(window.localStorage[url]); - Blockly.Xml.domToWorkspace(workspace, xml); + Blockly.Xml.domToWorkspace(xml, workspace); } }; @@ -181,7 +181,7 @@ BlocklyStorage.loadXml_ = function(xml, workspace) { } // Clear the workspace to avoid merge. workspace.clear(); - Blockly.Xml.domToWorkspace(workspace, xml); + Blockly.Xml.domToWorkspace(xml, workspace); }; /** diff --git a/core/connection.js b/core/connection.js index 434061be0..89b4aef27 100644 --- a/core/connection.js +++ b/core/connection.js @@ -535,7 +535,7 @@ Blockly.Connection.prototype.disconnect = function() { var shadow = parentConnection.getShadowDom(); if (parentBlock.workspace && shadow && Blockly.Events.recordUndo) { var blockShadow = - Blockly.Xml.domToBlock(parentBlock.workspace, shadow); + Blockly.Xml.domToBlock(shadow, parentBlock.workspace); if (blockShadow.outputConnection) { parentConnection.connect(blockShadow.outputConnection); } else if (blockShadow.previousConnection) { diff --git a/core/contextmenu.js b/core/contextmenu.js index 6bfac35c2..3a1fc6e95 100644 --- a/core/contextmenu.js +++ b/core/contextmenu.js @@ -124,7 +124,7 @@ Blockly.ContextMenu.hide = function() { Blockly.ContextMenu.callbackFactory = function(block, xml) { return function() { Blockly.Events.disable(); - var newBlock = Blockly.Xml.domToBlock(block.workspace, xml); + var newBlock = Blockly.Xml.domToBlock(xml, block.workspace); // Move the new block next to the old block. var xy = block.getRelativeToSurfaceXY(); if (block.RTL) { diff --git a/core/events.js b/core/events.js index 7570fb8e9..b3c8c4f66 100644 --- a/core/events.js +++ b/core/events.js @@ -324,7 +324,7 @@ Blockly.Events.Create.prototype.run = function(forward) { var workspace = Blockly.Workspace.getById(this.workspaceId); var xml = goog.dom.createDom('xml'); xml.appendChild(this.xml); - Blockly.Xml.domToWorkspace(workspace, xml); + Blockly.Xml.domToWorkspace(xml, workspace); } else { for (var i = 0, id; id = this.ids[i]; i++) { var block = Blockly.Block.getById(id); @@ -389,7 +389,7 @@ Blockly.Events.Delete.prototype.run = function(forward) { var workspace = Blockly.Workspace.getById(this.workspaceId); var xml = goog.dom.createDom('xml'); xml.appendChild(this.oldXml); - Blockly.Xml.domToWorkspace(workspace, xml); + Blockly.Xml.domToWorkspace(xml, workspace); } }; diff --git a/core/flyout.js b/core/flyout.js index 39d579e86..84bcbb810 100644 --- a/core/flyout.js +++ b/core/flyout.js @@ -393,7 +393,7 @@ Blockly.Flyout.prototype.show = function(xmlList) { this.permanentlyDisabled_.length = 0; for (var i = 0, xml; xml = xmlList[i]; i++) { if (xml.tagName && xml.tagName.toUpperCase() == 'BLOCK') { - var block = Blockly.Xml.domToBlock(this.workspace_, xml); + var block = Blockly.Xml.domToBlock(xml, this.workspace_); if (block.disabled) { // Record blocks that were initially disabled. // Do not enable these blocks as a result of capacity filtering. @@ -636,7 +636,7 @@ Blockly.Flyout.prototype.createBlockFunc_ = function(originBlock) { Blockly.Events.disable(); // Create the new block by cloning the block in the flyout (via XML). var xml = Blockly.Xml.blockToDom(originBlock); - var block = Blockly.Xml.domToBlock(workspace, xml); + var block = Blockly.Xml.domToBlock(xml, workspace); // Place it in the same spot as the flyout copy. var svgRootOld = originBlock.getSvgRoot(); if (!svgRootOld) { diff --git a/core/workspace_svg.js b/core/workspace_svg.js index aa4261185..13818fd9a 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -468,7 +468,7 @@ Blockly.WorkspaceSvg.prototype.paste = function(xmlBlock) { } Blockly.terminateDrag_(); // Dragging while pasting? No. Blockly.Events.disable(); - var block = Blockly.Xml.domToBlock(this, xmlBlock); + var block = Blockly.Xml.domToBlock(xmlBlock, this); // Move the duplicate to original position. var blockX = parseInt(xmlBlock.getAttribute('x'), 10); var blockY = parseInt(xmlBlock.getAttribute('y'), 10); diff --git a/core/xml.js b/core/xml.js index 3cfe3663c..e6e3a1c5a 100644 --- a/core/xml.js +++ b/core/xml.js @@ -268,10 +268,17 @@ Blockly.Xml.textToDom = function(text) { /** * Decode an XML DOM and create blocks on the workspace. - * @param {!Blockly.Workspace} workspace The workspace. * @param {!Element} xml XML DOM. + * @param {!Blockly.Workspace} workspace The workspace. */ -Blockly.Xml.domToWorkspace = function(workspace, xml) { +Blockly.Xml.domToWorkspace = function(xml, workspace) { + if (xml instanceof Blockly.Workspace) { + var swap = xml; + xml = workspace; + workspace = swap; + console.warn('Deprecated call to Blockly.Xml.domToWorkspace, ' + + 'swap the arguments.'); + } var width; // Not used in LTR. if (workspace.RTL) { width = workspace.getWidth(); @@ -289,7 +296,7 @@ Blockly.Xml.domToWorkspace = function(workspace, xml) { var xmlChild = xml.childNodes[i]; var name = xmlChild.nodeName.toLowerCase(); if (name == 'block' || name == 'shadow') { - var block = Blockly.Xml.domToBlock(workspace, xmlChild); + var block = Blockly.Xml.domToBlock(xmlChild, workspace); var blockX = parseInt(xmlChild.getAttribute('x'), 10); var blockY = parseInt(xmlChild.getAttribute('y'), 10); if (!isNaN(blockX) && !isNaN(blockY)) { @@ -306,14 +313,21 @@ Blockly.Xml.domToWorkspace = function(workspace, xml) { /** * 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 {!Blockly.Workspace} workspace The workspace. * @return {!Blockly.Block} The root block created. */ -Blockly.Xml.domToBlock = function(workspace, xmlBlock) { +Blockly.Xml.domToBlock = function(xmlBlock, workspace) { + if (xmlBlock instanceof Blockly.Workspace) { + var swap = xmlBlock; + xmlBlock = workspace; + workspace = swap; + console.warn('Deprecated call to Blockly.Xml.domToBlock, ' + + 'swap the arguments.'); + } // Create top-level block. Blockly.Events.disable(); - var topBlock = Blockly.Xml.domToBlockHeadless_(workspace, xmlBlock); + var topBlock = Blockly.Xml.domToBlockHeadless_(xmlBlock, workspace); if (workspace.rendered) { // Hide connections to speed up assembly. topBlock.setConnectionsHidden(true); @@ -347,12 +361,12 @@ Blockly.Xml.domToBlock = function(workspace, xmlBlock) { /** * 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 {!Blockly.Workspace} workspace The workspace. * @return {!Blockly.Block} The root block created. * @private */ -Blockly.Xml.domToBlockHeadless_ = function(workspace, xmlBlock) { +Blockly.Xml.domToBlockHeadless_ = function(xmlBlock, workspace) { var block = null; var prototypeName = xmlBlock.getAttribute('type'); if (!prototypeName) { @@ -447,8 +461,8 @@ Blockly.Xml.domToBlockHeadless_ = function(workspace, xmlBlock) { input.connection.setShadowDom(childShadowNode); } if (childBlockNode) { - blockChild = Blockly.Xml.domToBlockHeadless_(workspace, - childBlockNode); + blockChild = Blockly.Xml.domToBlockHeadless_(childBlockNode, + workspace); if (blockChild.outputConnection) { input.connection.connect(blockChild.outputConnection); } else if (blockChild.previousConnection) { @@ -469,8 +483,8 @@ Blockly.Xml.domToBlockHeadless_ = function(workspace, xmlBlock) { // This could happen if there is more than one XML 'next' tag. throw 'Next statement is already connected.'; } - blockChild = Blockly.Xml.domToBlockHeadless_(workspace, - childBlockNode); + blockChild = Blockly.Xml.domToBlockHeadless_(childBlockNode, + workspace); if (!blockChild.previousConnection) { throw 'Next block does not have previous statement.'; } diff --git a/demos/blockfactory/factory.js b/demos/blockfactory/factory.js index 246b2b555..375ad1386 100644 --- a/demos/blockfactory/factory.js +++ b/demos/blockfactory/factory.js @@ -786,7 +786,7 @@ function init() { mainWorkspace); } else { var xml = ''; - Blockly.Xml.domToWorkspace(mainWorkspace, Blockly.Xml.textToDom(xml)); + Blockly.Xml.domToWorkspace(Blockly.Xml.textToDom(xml), mainWorkspace); } mainWorkspace.clearUndo(); diff --git a/demos/code/code.js b/demos/code/code.js index 5380cdf9b..5668dfe31 100644 --- a/demos/code/code.js +++ b/demos/code/code.js @@ -139,11 +139,11 @@ Code.loadBlocks = function(defaultXml) { // Language switching stores the blocks during the reload. delete window.sessionStorage.loadOnceBlocks; var xml = Blockly.Xml.textToDom(loadOnce); - Blockly.Xml.domToWorkspace(Code.workspace, xml); + Blockly.Xml.domToWorkspace(xml, Code.workspace); } else if (defaultXml) { // Load the editor with default starting blocks. var xml = Blockly.Xml.textToDom(defaultXml); - Blockly.Xml.domToWorkspace(Code.workspace, xml); + Blockly.Xml.domToWorkspace(xml, Code.workspace); } else if ('BlocklyStorage' in window) { // Restore saved blocks in a separate thread so that subsequent // initialization is not affected from a failed load. @@ -270,7 +270,7 @@ Code.tabClick = function(clickedName) { } if (xmlDom) { Code.workspace.clear(); - Blockly.Xml.domToWorkspace(Code.workspace, xmlDom); + Blockly.Xml.domToWorkspace(xmlDom, Code.workspace); } } diff --git a/demos/generator/index.html b/demos/generator/index.html index 31890a665..0687e963e 100644 --- a/demos/generator/index.html +++ b/demos/generator/index.html @@ -116,8 +116,8 @@ var workspace = Blockly.inject('blocklyDiv', {media: '../../media/', toolbox: document.getElementById('toolbox')}); - Blockly.Xml.domToWorkspace(workspace, - document.getElementById('startBlocks')); + Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'), + workspace); function showCode() { // Generate JavaScript code and display it. diff --git a/demos/graph/index.html b/demos/graph/index.html index 709fd502c..7e9daf2dd 100644 --- a/demos/graph/index.html +++ b/demos/graph/index.html @@ -338,8 +338,8 @@ Graph.init = function() { {collapse: false, media: '../../media/', toolbox: document.getElementById('toolbox')}); - Blockly.Xml.domToWorkspace(Graph.workspace, - document.getElementById('startBlocks')); + Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'), + Graph.workspace); Graph.workspace.clearUndo(); // When Blockly changes, update the graph. diff --git a/demos/headless/index.html b/demos/headless/index.html index 9df0dc806..62d49fdfa 100644 --- a/demos/headless/index.html +++ b/demos/headless/index.html @@ -110,7 +110,7 @@ } // Create a headless workspace. var workspace = new Blockly.Workspace(); - Blockly.Xml.domToWorkspace(workspace, xml); + Blockly.Xml.domToWorkspace(xml, workspace); var code = Blockly.Python.workspaceToCode(workspace); document.getElementById('code_output').value = code; } diff --git a/demos/interpreter/index.html b/demos/interpreter/index.html index a4fadc9d0..ba481f1af 100644 --- a/demos/interpreter/index.html +++ b/demos/interpreter/index.html @@ -124,8 +124,8 @@ var workspace = Blockly.inject('blocklyDiv', {media: '../../media/', toolbox: document.getElementById('toolbox')}); - Blockly.Xml.domToWorkspace(workspace, - document.getElementById('startBlocks')); + Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'), + workspace); var myInterpreter = null; diff --git a/demos/plane/plane.js b/demos/plane/plane.js index e19f8a46f..3b05eee01 100644 --- a/demos/plane/plane.js +++ b/demos/plane/plane.js @@ -143,11 +143,11 @@ Plane.loadBlocks = function(defaultXml) { // Language switching stores the blocks during the reload. delete window.sessionStorage.loadOnceBlocks; var xml = Blockly.Xml.textToDom(loadOnce); - Blockly.Xml.domToWorkspace(Plane.workspace, xml); + Blockly.Xml.domToWorkspace(xml, Plane.workspace); } else if (defaultXml) { // Load the editor with default starting blocks. var xml = Blockly.Xml.textToDom(defaultXml); - Blockly.Xml.domToWorkspace(Plane.workspace, xml); + Blockly.Xml.domToWorkspace(xml, Plane.workspace); } Plane.workspace.clearUndo(); }; diff --git a/demos/rtl/index.html b/demos/rtl/index.html index a88026132..f2ae162f4 100644 --- a/demos/rtl/index.html +++ b/demos/rtl/index.html @@ -27,8 +27,8 @@ {media: '../../media/', rtl: true, toolbox: document.getElementById('toolbox')}); - Blockly.Xml.domToWorkspace(workspace, - document.getElementById('startBlocks')); + Blockly.Xml.domToWorkspace(document.getElementById('startBlocks'), + workspace); //window.onbeforeunload = function() { // return 'Leaving this page will result in the loss of your work.'; //}; diff --git a/tests/generators/index.html b/tests/generators/index.html index 4e2ef54d6..e168a326a 100644 --- a/tests/generators/index.html +++ b/tests/generators/index.html @@ -128,7 +128,7 @@ function fromXml(xmlText) { alert('Error parsing XML:\n' + e); return; } - Blockly.Xml.domToWorkspace(workspace, xmlDoc); + Blockly.Xml.domToWorkspace(xmlDoc, workspace); } function setOutput(text) { diff --git a/tests/playground.html b/tests/playground.html index 0d7b053cb..c41c12db2 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -118,7 +118,7 @@ function toXml() { function fromXml() { var input = document.getElementById('importExport'); var xml = Blockly.Xml.textToDom(input.value); - Blockly.Xml.domToWorkspace(workspace, xml); + Blockly.Xml.domToWorkspace(xml, workspace); taChange(); } @@ -188,7 +188,7 @@ function spaghetti(n) { xml = '' + xml + ''; var dom = Blockly.Xml.textToDom(xml); console.time('Spaghetti domToWorkspace'); - Blockly.Xml.domToWorkspace(workspace, dom); + Blockly.Xml.domToWorkspace(dom, workspace); console.timeEnd('Spaghetti domToWorkspace'); } var spaghettiXml = [ From 61b3fbfe11ad6bc130dd1065b5c54c23fe90eca8 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Tue, 5 Apr 2016 18:43:39 -0700 Subject: [PATCH 4/9] Move block database to workspace. --- core/block.js | 23 ++++------------------- core/connection_db.js | 6 +++--- core/events.js | 17 ++++++++++------- core/workspace.js | 11 +++++++++++ core/workspace_svg.js | 2 +- 5 files changed, 29 insertions(+), 30 deletions(-) diff --git a/core/block.js b/core/block.js index 2286e78ca..604c5a0d6 100644 --- a/core/block.js +++ b/core/block.js @@ -52,9 +52,9 @@ goog.require('goog.string'); */ Blockly.Block = function(workspace, prototypeName, opt_id) { /** @type {string} */ - this.id = (opt_id && !Blockly.Block.getById(opt_id)) ? + this.id = (opt_id && !workspace.getBlockById(opt_id)) ? opt_id : Blockly.genUid(); - Blockly.Block.BlockDB_[this.id] = this; + workspace.blockDB_[this.id] = this; /** @type {Blockly.Connection} */ this.outputConnection = null; /** @type {Blockly.Connection} */ @@ -178,6 +178,8 @@ Blockly.Block.prototype.dispose = function(healStack) { // Remove this block from the workspace's list of top-most blocks. if (this.workspace) { this.workspace.removeTopBlock(this); + // Remove from block database. + delete this.workspace.blockDB_[this.id]; this.workspace = null; } @@ -204,8 +206,6 @@ Blockly.Block.prototype.dispose = function(healStack) { } connections[i].dispose(); } - // Remove from block database. - delete Blockly.Block.BlockDB_[this.id]; Blockly.Events.enable(); }; @@ -1294,18 +1294,3 @@ Blockly.Block.prototype.moveBy = function(dx, dy) { event.recordNew(); Blockly.Events.fire(event); }; - -/** - * Database of all blocks. - * @private - */ -Blockly.Block.BlockDB_ = Object.create(null); - -/** - * Find the block with the specified ID. - * @param {string} id ID of block to find. - * @return {Blockly.Block} The sought after block or null if not found. - */ -Blockly.Block.getById = function(id) { - return Blockly.Block.BlockDB_[id] || null; -}; diff --git a/core/connection_db.js b/core/connection_db.js index 61a2ae952..580ae353d 100644 --- a/core/connection_db.js +++ b/core/connection_db.js @@ -66,7 +66,7 @@ Blockly.ConnectionDB.prototype.addConnection = function(connection) { * Find the given connection. * Starts by doing a binary search to find the approximate location, then * linearly searches nearby for the exact connection. - * @param {Blockly.Connection} conn The connection to find. + * @param {!Blockly.Connection} conn The connection to find. * @return {number} The index of the connection, or -1 if the connection was * not found. */ @@ -105,7 +105,7 @@ Blockly.ConnectionDB.prototype.findConnection = function(conn) { * Finds a candidate position for inserting this connection into the list. * This will be in the correct y order but makes no guarantees about ordering in * the x axis. - * @param {Blockly.Connection} connection The connection to insert. + * @param {!Blockly.Connection} connection The connection to insert. * @return {number} The candidate index. * @private */ @@ -223,7 +223,7 @@ Blockly.ConnectionDB.prototype.isInYRange_ = function(index, baseY, maxRadius) { /** * Find the closest compatible connection to this connection. - * @param {Blockly.Connection} conn The connection searching for a compatible + * @param {!Blockly.Connection} conn The connection searching for a compatible * mate. * @param {number} maxRadius The maximum radius to another connection. * @param {number} dx Horizontal offset between this connection's location diff --git a/core/events.js b/core/events.js index b3c8c4f66..8aafdfdb1 100644 --- a/core/events.js +++ b/core/events.js @@ -327,7 +327,7 @@ Blockly.Events.Create.prototype.run = function(forward) { Blockly.Xml.domToWorkspace(xml, workspace); } else { for (var i = 0, id; id = this.ids[i]; i++) { - var block = Blockly.Block.getById(id); + var block = workspace.getBlockById(id); if (block) { block.dispose(false, true); } else if (id == this.blockId) { @@ -375,9 +375,10 @@ Blockly.Events.Delete.prototype.toJson = function() { * @param {boolean} forward True if run forward, false if run backward (undo). */ Blockly.Events.Delete.prototype.run = function(forward) { + var workspace = Blockly.Workspace.getById(this.workspaceId); if (forward) { for (var i = 0, id; id = this.ids[i]; i++) { - var block = Blockly.Block.getById(id); + var block = workspace.getBlockById(id); if (block) { block.dispose(false, true); } else if (id == this.blockId) { @@ -386,7 +387,6 @@ Blockly.Events.Delete.prototype.run = function(forward) { } } } else { - var workspace = Blockly.Workspace.getById(this.workspaceId); var xml = goog.dom.createDom('xml'); xml.appendChild(this.oldXml); Blockly.Xml.domToWorkspace(xml, workspace); @@ -445,7 +445,8 @@ Blockly.Events.Change.prototype.isNull = function() { * @param {boolean} forward True if run forward, false if run backward (undo). */ Blockly.Events.Change.prototype.run = function(forward) { - var block = Blockly.Block.getById(this.blockId); + var workspace = Blockly.Workspace.getById(this.workspaceId); + var block = workspace.getBlockById(this.blockId); if (!block) { console.warn("Can't change non-existant block: " + this.blockId); return; @@ -552,7 +553,8 @@ Blockly.Events.Move.prototype.recordNew = function() { * @private */ Blockly.Events.Move.prototype.currentLocation_ = function() { - var block = Blockly.Block.getById(this.blockId); + var workspace = Blockly.Workspace.getById(this.workspaceId); + var block = workspace.getBlockById(this.blockId); var location = {}; var parent = block.getParent(); if (parent) { @@ -582,7 +584,8 @@ Blockly.Events.Move.prototype.isNull = function() { * @param {boolean} forward True if run forward, false if run backward (undo). */ Blockly.Events.Move.prototype.run = function(forward) { - var block = Blockly.Block.getById(this.blockId); + var workspace = Blockly.Workspace.getById(this.workspaceId); + var block = workspace.getBlockById(this.blockId); if (!block) { console.warn("Can't move non-existant block: " + this.blockId); return; @@ -592,7 +595,7 @@ Blockly.Events.Move.prototype.run = function(forward) { var coordinate = forward ? this.newCoordinate : this.oldCoordinate; var parentBlock = null; if (parentId) { - parentBlock = Blockly.Block.getById(parentId); + parentBlock = workspace.getBlockById(parentId); if (!parentBlock) { console.warn("Can't connect to non-existant block: " + parentId); return; diff --git a/core/workspace.js b/core/workspace.js index e08403f1c..47d6ac7c3 100644 --- a/core/workspace.js +++ b/core/workspace.js @@ -51,6 +51,8 @@ Blockly.Workspace = function(opt_options) { this.undoStack_ = []; /** @type {!Array.} */ this.redoStack_ = []; + /** @type {!Object} */ + this.blockDB_ = Object.create(null); }; /** @@ -289,6 +291,15 @@ Blockly.Workspace.prototype.fireChangeListener = function(event) { } }; +/** + * Find the block on this workspace with the specified ID. + * @param {string} id ID of block to find. + * @return {Blockly.Block} The sought after block or null if not found. + */ +Blockly.Workspace.prototype.getBlockById = function(id) { + return this.blockDB_[id] || null; +}; + /** * Database of all workspaces. * @private diff --git a/core/workspace_svg.js b/core/workspace_svg.js index 13818fd9a..311126e30 100644 --- a/core/workspace_svg.js +++ b/core/workspace_svg.js @@ -438,7 +438,7 @@ Blockly.WorkspaceSvg.prototype.highlightBlock = function(id) { } var block = null; if (id) { - block = Blockly.Block.getById(id); + block = this.getBlockById(id); if (!block) { return; } From effa81f6225a54e933623de24c30df60b4211537 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 6 Apr 2016 14:27:15 -0700 Subject: [PATCH 5/9] Create fromJson for events. Add master-slave demo. --- core/blockly.js | 3 +- core/events.js | 120 +++++++++++++++++++++++++++++++++++++--- demos/index.html | 12 ++++ demos/mirror/icon.png | Bin 0 -> 2464 bytes demos/mirror/index.html | 76 +++++++++++++++++++++++++ 5 files changed, 203 insertions(+), 8 deletions(-) create mode 100644 demos/mirror/icon.png create mode 100644 demos/mirror/index.html diff --git a/core/blockly.js b/core/blockly.js index 85d311e6d..365255099 100644 --- a/core/blockly.js +++ b/core/blockly.js @@ -222,7 +222,8 @@ Blockly.onMouseMove_ = function(e) { * @private */ Blockly.onKeyDown_ = function(e) { - if (Blockly.isTargetInput_(e)) { + if (Blockly.mainWorkspace.options.readOnly || Blockly.isTargetInput_(e)) { + // No key actions on readonly workspaces. // When focused on an HTML text input widget, don't trap any keys. return; } diff --git a/core/events.js b/core/events.js index 8aafdfdb1..f890d85cb 100644 --- a/core/events.js +++ b/core/events.js @@ -239,6 +239,37 @@ Blockly.Events.getDescendantIds_ = function(block) { return ids; }; +/** + * Decode the JSON into an event. + * @param {!Object} json JSON representation. + * @param {!Blockly.Workspace} workspace Target workspace for event. + */ +Blockly.Events.fromJson = function(json, workspace) { + var event; + switch (json.type) { + case Blockly.Events.CREATE: + event = new Blockly.Events.Create(null); + break; + case Blockly.Events.DELETE: + event = new Blockly.Events.Delete(null); + break; + case Blockly.Events.CHANGE: + event = new Blockly.Events.Change(null); + break; + case Blockly.Events.MOVE: + event = new Blockly.Events.Move(null); + break; + case Blockly.Events.UI: + event = new Blockly.Events.Ui(null); + break; + default: + throw 'Unknown event type.' + } + event.fromJson(json); + event.workspaceId = workspace.id; + return event; +}; + /** * Abstract class for an event. * @param {Blockly.Block} block The block. @@ -260,8 +291,7 @@ Blockly.Events.Abstract = function(block) { Blockly.Events.Abstract.prototype.toJson = function() { var json = { 'type': this.type, - 'blockId': this.blockId, - 'workspaceId': this.workspaceId + 'blockId': this.blockId }; if (this.group) { json['group'] = this.group; @@ -269,6 +299,15 @@ Blockly.Events.Abstract.prototype.toJson = function() { return json; }; +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +Blockly.Events.Abstract.prototype.fromJson = function(json) { + this.blockId = json['blockId']; + this.group = json['group']; +}; + /** * Does this event record any change of state? * @return {boolean} True if null, false if something changed. @@ -287,11 +326,14 @@ Blockly.Events.Abstract.prototype.run = function(forward) { /** * Class for a block creation event. - * @param {!Blockly.Block} block The created block. + * @param {Blockly.Block} block The created block. Null for a blank event. * @extends {Blockly.Events.Abstract} * @constructor */ Blockly.Events.Create = function(block) { + if (!block) { + return; // Blank event to be populated by fromJson. + } Blockly.Events.Create.superClass_.constructor.call(this, block); this.xml = Blockly.Xml.blockToDomWithXY(block); this.ids = Blockly.Events.getDescendantIds_(block); @@ -315,13 +357,23 @@ Blockly.Events.Create.prototype.toJson = function() { return json; }; +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +Blockly.Events.Create.prototype.fromJson = function(json) { + Blockly.Events.Create.superClass_.fromJson.call(this, json); + this.xml = Blockly.Xml.textToDom('' + json['xml'] + '').firstChild; + this.ids = json['ids']; +}; + /** * Run a creation event. * @param {boolean} forward True if run forward, false if run backward (undo). */ Blockly.Events.Create.prototype.run = function(forward) { + var workspace = Blockly.Workspace.getById(this.workspaceId); if (forward) { - var workspace = Blockly.Workspace.getById(this.workspaceId); var xml = goog.dom.createDom('xml'); xml.appendChild(this.xml); Blockly.Xml.domToWorkspace(xml, workspace); @@ -340,11 +392,14 @@ Blockly.Events.Create.prototype.run = function(forward) { /** * Class for a block deletion event. - * @param {!Blockly.Block} block The deleted block. + * @param {Blockly.Block} block The deleted block. Null for a blank event. * @extends {Blockly.Events.Abstract} * @constructor */ Blockly.Events.Delete = function(block) { + if (!block) { + return; // Blank event to be populated by fromJson. + } if (block.getParent()) { throw 'Connected blocks cannot be deleted.'; } @@ -370,6 +425,15 @@ Blockly.Events.Delete.prototype.toJson = function() { return json; }; +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +Blockly.Events.Delete.prototype.fromJson = function(json) { + Blockly.Events.Delete.superClass_.fromJson.call(this, json); + this.ids = json['ids']; +}; + /** * Run a deletion event. * @param {boolean} forward True if run forward, false if run backward (undo). @@ -395,7 +459,7 @@ Blockly.Events.Delete.prototype.run = function(forward) { /** * Class for a block change event. - * @param {!Blockly.Block} block The changed block. + * @param {Blockly.Block} block The changed block. Null for a blank event. * @param {string} element One of 'field', 'comment', 'disabled', etc. * @param {?string} name Name of input or field affected, or null. * @param {string} oldValue Previous value of element. @@ -404,6 +468,9 @@ Blockly.Events.Delete.prototype.run = function(forward) { * @constructor */ Blockly.Events.Change = function(block, element, name, oldValue, newValue) { + if (!block) { + return; // Blank event to be populated by fromJson. + } Blockly.Events.Change.superClass_.constructor.call(this, block); this.element = element; this.name = name; @@ -432,6 +499,17 @@ Blockly.Events.Change.prototype.toJson = function() { return json; }; +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +Blockly.Events.Change.prototype.fromJson = function(json) { + Blockly.Events.Change.superClass_.fromJson.call(this, json); + this.element = json['element']; + this.name = json['name']; + this.newValue = json['newValue']; +}; + /** * Does this event record any change of state? * @return {boolean} True if something changed. @@ -498,11 +576,14 @@ Blockly.Events.Change.prototype.run = function(forward) { /** * Class for a block move event. Created before the move. - * @param {!Blockly.Block} block The moved block. + * @param {Blockly.Block} block The moved block. Null for a blank event. * @extends {Blockly.Events.Abstract} * @constructor */ Blockly.Events.Move = function(block) { + if (!block) { + return; // Blank event to be populated by fromJson. + } Blockly.Events.Move.superClass_.constructor.call(this, block); var location = this.currentLocation_(); this.oldParentId = location.parentId; @@ -536,6 +617,21 @@ Blockly.Events.Move.prototype.toJson = function() { return json; }; +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +Blockly.Events.Move.prototype.fromJson = function(json) { + Blockly.Events.Move.superClass_.fromJson.call(this, json); + this.newParentId = json['newParentId']; + this.newInputName = json['newInputName']; + if (json['newCoordinate']) { + var xy = json['newCoordinate'].split(','); + this.newCoordinate = + new goog.math.Coordinate(parseFloat(xy[0]), parseFloat(xy[1])); + } +}; + /** * Record the block's new location. Called after the move. */ @@ -662,3 +758,13 @@ Blockly.Events.Ui.prototype.toJson = function() { } return json; }; + +/** + * Decode the JSON event. + * @param {!Object} json JSON representation. + */ +Blockly.Events.Ui.prototype.fromJson = function(json) { + Blockly.Events.Ui.superClass_.fromJson.call(this, json); + this.element = json['element']; + this.newValue = json['newValue']; +}; diff --git a/demos/index.html b/demos/index.html index 3fe46a780..f9f9833e7 100644 --- a/demos/index.html +++ b/demos/index.html @@ -160,6 +160,18 @@ + + + + + + + + +
Two Blockly instances connected as master-slave.
+ + + diff --git a/demos/mirror/icon.png b/demos/mirror/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..45e2a9a290cd7378b3c933f5e5e9e1dbf0df4a16 GIT binary patch literal 2464 zcmV;R319Y!P)SWDViciOhs!Nf*@2;7Uj*#qV5X2ymq<$<1Wi87#Ef} zYdD{o{eye%o_qFu&-tC-?|uP+Kp+qZ1OkCTAP@)y0)apv5C{YUfj}Ub>`1_rU>V5g zvi;36S?J{-8EFTP)n zv$r2-Z@(X1sZf4)A6AwK%QFv2cP@#h<4hGAl}vo})WCO$af4F znMa;KHe7kmS<0U_&LrGuBpaEY(W=vwWH!!=B7{NOYRlPYR*%>X-&!4mPCbaVrJg;N z$|4%@G&_Cj+q9Hekeru&Js~9)z2v0Ye95QJDAG(CZ1onJ{rFwZ?hDLGnMLUp*M|gZ zZSRn0#6?R13!+jftEk^K_=UvX!P-7$;#_X*NQ7R|zHRnmcV;*9n?GI=PUTrV`FIv4E%aMX@k0C1_4#bMCxhuY`QWJ{c6-Eo z_(#jhGD?`s_VDz6r(eHi(ZV@bZJP)&zK|>{G$Mwr_uZj<9>`>&uEHC6Sj~H#{I;GtO;l^3qm8tAtTy6&B85DTLa9A3+ zzwo%vLrzfJ4xl4F->7ILFJ!J!0&E=F?+C6eYr=cfMlvrca>V5jZPe$zL2d}M*CNU|2^tDC|fTQIkKYODFfLe7P1xpRYCq*ecPaVMz9={!f795s( z9xALD@tj>X7s!d5N@7wnaGs=9aZ10IbCe)`$px`BvGw<-F{Ee!h&P$YUmAxYX)aq= z)Kly$QkaqiwECPGa=QZu5Dw_oN;tK5p7XXh7ME~Ou@a&R76NE6Xg#kl8k$BAn`I5O zAS4S-YWw-60-(|Gos`$LOsGZ*_6I?hT%hh z@!i>MS)0wK9Q}|S{Oow%L;3T?=7yglVdcHzUpp%YCOrwfjI75 zI!!rODvxsf%x%~*O&F3Ev2Bxq<2_M)JxvSrapI7j`E!+i5|Mei@Fa_#o`=Dh#FHz| zQgr3Usx)I>9gRt=?8=izYXScYMqR|!Ym5_T&&l(XV^l!Esj515S|puzCt6Jic1JI6 z*8rA=6FBWwW+bMdGba06%X)eYCEj>>C~(-Uy!-Y?>_f$3pL-jNODK+A&C28m(wAhA zK6Fmhl(YS4C~%BjC3=3CH=TIXY~nrNZLB%LtClGgc(N=f5|UKIE5~NCB{LFJ)-5Df z`-}-dYUSwJ9!&GXptpm6j^6QJyOT3dp>hpZ9M=7 z$1BE$jzaAb}fjAbVlw>xf>IuP3 zV`UX(mMJ3&!*66q5F)v0Dl?BrpZ#U!ch|5fHI&B6gZ$zj*0JX+mNP8-TK2)%so~37 ztd~%GYB-nM&Hs)cCx2xQ%^lt279>o*q~v_|u5Nkl_qGC%zv6Zt*qDz#GD3o33-?Ag zs1nj|Wm9Gp2}ydwv9a^1eUt@|?xxI~N~BJU%k9Q`(TUa8MMq0L>sROSaaG&61Q{~8 z)PQ&L0ZMoOfkz+wa=oRUZi;1Il9C%YmRAKN20&}aCG-&kSZ!Sl`kWer&htT7hXf&? z{k@DGHF~h0p~4b)Hrd_i@Z%rs%`9es>J&mWys(PU6A8_PSL=ufDNwBwt5n$soDALW4WVdZtWeV zGvcCi13p89!8Kt9S8hxPmTZO?HDTU_pez6=apVFu45V z8U|PC{N$L4$+BXnDF?7t6XLB%Tg_E8)*Qy!d3G#&&9g*8i8n@iKjCV{;Cj7q4|}}_ zsE@&Qwj0opz9fV1ER7)?AA_so7`sZWIDmN5Y*wX35$a=b4W-k=2AA@}(3EuxiN0e3 zufe6f=NP}ib=j^vP+j_~7e6Z9d!&vJ{#{cF1fC+aS?#65;PNwHv7Di3=g)I%>f1|; z4xb)ja6S9zw + + + + Blockly Demo: Mirrored Blockly + + + + + + +

Blockly > + Demos > Mirrored Blockly

+ +

This is a simple demo of a master Blockly that controls a slave Blockly. + Open the JavaScript console to see the event passing.

+ +

→ More info on events

+ + + + + + +
+
+
+
+
+ + + + + + + From 194341f2e501c1a6d481c7bd0a4d4afbf7f042d6 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Wed, 6 Apr 2016 16:27:25 -0700 Subject: [PATCH 6/9] Allow use of setOutput (and friends) to change checks. Issue #315. --- core/block.js | 65 ++++++++++++++++++++++++++++--------------------- core/options.js | 5 ---- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/core/block.js b/core/block.js index 604c5a0d6..8cdcdf7df 100644 --- a/core/block.js +++ b/core/block.js @@ -709,21 +709,24 @@ Blockly.Block.prototype.setTitleValue = function(newValue, name) { * list of statement types. Null/undefined if any type could be connected. */ Blockly.Block.prototype.setPreviousStatement = function(newBoolean, opt_check) { - if (this.previousConnection) { - goog.asserts.assert(!this.previousConnection.isConnected(), - 'Must disconnect previous statement before removing connection.'); - this.previousConnection.dispose(); - this.previousConnection = null; - } if (newBoolean) { - goog.asserts.assert(!this.outputConnection, - 'Remove output connection prior to adding previous connection.'); if (opt_check === undefined) { opt_check = null; } - this.previousConnection = - new Blockly.Connection(this, Blockly.PREVIOUS_STATEMENT); + if (!this.previousConnection) { + goog.asserts.assert(!this.outputConnection, + 'Remove output connection prior to adding previous connection.'); + this.previousConnection = + new Blockly.Connection(this, Blockly.PREVIOUS_STATEMENT); + } this.previousConnection.setCheck(opt_check); + } else { + if (this.previousConnection) { + goog.asserts.assert(!this.previousConnection.isConnected(), + 'Must disconnect previous statement before removing connection.'); + this.previousConnection.dispose(); + this.previousConnection = null; + } } }; @@ -734,19 +737,22 @@ Blockly.Block.prototype.setPreviousStatement = function(newBoolean, opt_check) { * list of statement types. Null/undefined if any type could be connected. */ Blockly.Block.prototype.setNextStatement = function(newBoolean, opt_check) { - if (this.nextConnection) { - goog.asserts.assert(!this.nextConnection.isConnected(), - 'Must disconnect next statement before removing connection.'); - this.nextConnection.dispose(); - this.nextConnection = null; - } if (newBoolean) { if (opt_check === undefined) { opt_check = null; } - this.nextConnection = - new Blockly.Connection(this, Blockly.NEXT_STATEMENT); + if (!this.nextConnection) { + this.nextConnection = + new Blockly.Connection(this, Blockly.NEXT_STATEMENT); + } this.nextConnection.setCheck(opt_check); + } else { + if (this.nextConnection) { + goog.asserts.assert(!this.nextConnection.isConnected(), + 'Must disconnect next statement before removing connection.'); + this.nextConnection.dispose(); + this.nextConnection = null; + } } }; @@ -758,21 +764,24 @@ Blockly.Block.prototype.setNextStatement = function(newBoolean, opt_check) { * (e.g. variable get). */ Blockly.Block.prototype.setOutput = function(newBoolean, opt_check) { - if (this.outputConnection) { - goog.asserts.assert(!this.outputConnection.isConnected(), - 'Must disconnect output value before removing connection.'); - this.outputConnection.dispose(); - this.outputConnection = null; - } if (newBoolean) { - goog.asserts.assert(!this.previousConnection, - 'Remove previous connection prior to adding output connection.'); if (opt_check === undefined) { opt_check = null; } - this.outputConnection = - new Blockly.Connection(this, Blockly.OUTPUT_VALUE); + if (!this.outputConnection) { + goog.asserts.assert(!this.previousConnection, + 'Remove previous connection prior to adding output connection.'); + this.outputConnection = + new Blockly.Connection(this, Blockly.OUTPUT_VALUE); + } this.outputConnection.setCheck(opt_check); + } else { + if (this.outputConnection) { + goog.asserts.assert(!this.outputConnection.isConnected(), + 'Must disconnect output value before removing connection.'); + this.outputConnection.dispose(); + this.outputConnection = null; + } } }; diff --git a/core/options.js b/core/options.js index 83c084511..91a927497 100644 --- a/core/options.js +++ b/core/options.js @@ -85,9 +85,6 @@ Blockly.Options = function(options) { pathToMedia = options['path'] + 'media/'; } - var enableRealtime = !!options['realtime']; - var realtimeOptions = enableRealtime ? options['realtimeOptions'] : undefined; - this.RTL = !!options['rtl']; this.collapse = hasCollapse; this.comments = hasComments; @@ -103,8 +100,6 @@ Blockly.Options = function(options) { this.languageTree = languageTree; this.gridOptions = Blockly.Options.parseGridOptions_(options); this.zoomOptions = Blockly.Options.parseZoomOptions_(options); - this.enableRealtime = enableRealtime; - this.realtimeOptions = realtimeOptions; }; /** From 99f332f74997841b80d62c25db77343f29604494 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 7 Apr 2016 14:35:01 -0700 Subject: [PATCH 7/9] Fix getBlockById unit test. Issue #323 --- tests/jsunit/block_test.js | 35 ---------------------------------- tests/jsunit/index.html | 1 - tests/jsunit/workspace_test.js | 15 +++++++++++++++ tests/playground.html | 3 +-- 4 files changed, 16 insertions(+), 38 deletions(-) delete mode 100644 tests/jsunit/block_test.js diff --git a/tests/jsunit/block_test.js b/tests/jsunit/block_test.js deleted file mode 100644 index de4f36ffd..000000000 --- a/tests/jsunit/block_test.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * @license - * Blockly Tests - * - * Copyright 2015 Google Inc. - * https://developers.google.com/blockly/ - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -'use strict'; - -function test_getBlockById() { - var workspace = new Blockly.Workspace(); - var blockA = workspace.newBlock(''); - var blockB = workspace.newBlock(''); - assertEquals('Find blockA.', blockA, Blockly.Block.getById(blockA.id)); - assertEquals('Find blockB.', blockB, Blockly.Block.getById(blockB.id)); - assertEquals('No block found.', null, - Blockly.Block.getById('I do not exist.')); - blockA.dispose(); - assertEquals('Can\'t find blockA.', null, Blockly.Block.getById(blockA.id)); - assertEquals('BlockB exists.', blockB, Blockly.Block.getById(blockB.id)); - workspace.clear(); - assertEquals('Can\'t find blockB.', null, Blockly.Block.getById(blockB.id)); -} diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html index 48f134e89..a60459169 100644 --- a/tests/jsunit/index.html +++ b/tests/jsunit/index.html @@ -8,7 +8,6 @@ - diff --git a/tests/jsunit/workspace_test.js b/tests/jsunit/workspace_test.js index 2033b9ae0..87ff3bb98 100644 --- a/tests/jsunit/workspace_test.js +++ b/tests/jsunit/workspace_test.js @@ -82,3 +82,18 @@ function test_getWorkspaceById() { assertEquals('WorkspaceB exists.', workspaceB, Blockly.Workspace.getById(workspaceB.id)); } + +function test_getBlockById() { + var workspace = new Blockly.Workspace(); + var blockA = workspace.newBlock(''); + var blockB = workspace.newBlock(''); + assertEquals('Find blockA.', blockA, workspace.getBlockById(blockA.id)); + assertEquals('Find blockB.', blockB, workspace.getBlockById(blockB.id)); + assertEquals('No block found.', null, + workspace.getBlockById('I do not exist.')); + blockA.dispose(); + assertEquals('Can\'t find blockA.', null, workspace.getBlockById(blockA.id)); + assertEquals('BlockB exists.', blockB, workspace.getBlockById(blockB.id)); + workspace.clear(); + assertEquals('Can\'t find blockB.', null, workspace.getBlockById(blockB.id)); +} diff --git a/tests/playground.html b/tests/playground.html index c41c12db2..3e5863deb 100644 --- a/tests/playground.html +++ b/tests/playground.html @@ -87,8 +87,7 @@ function start() { startScale: 1.0, maxScale: 4, minScale: .25, - scaleSpeed: 1.1 - }, + scaleSpeed: 1.1} }); // Restore previously displayed text. if (sessionStorage) { From 1af4edd8611bc09c919d05a19cf4754ef5efa3b7 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 7 Apr 2016 14:39:39 -0700 Subject: [PATCH 8/9] Prevent events on different workspaces from merging. --- core/events.js | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/core/events.js b/core/events.js index f890d85cb..bc301ddbe 100644 --- a/core/events.js +++ b/core/events.js @@ -128,24 +128,24 @@ Blockly.Events.filter = function(queueIn, forward) { // Merge duplicates. O(n^2), but n should be very small. for (var i = 0, event1; event1 = queue[i]; i++) { for (var j = i + 1, event2; event2 = queue[j]; j++) { - if (event1.type == Blockly.Events.MOVE && - event2.type == Blockly.Events.MOVE && - event1.blockId == event2.blockId) { - // Merge move events. - event1.newParentId = event2.newParentId; - event1.newInputName = event2.newInputName; - event1.newCoordinate = event2.newCoordinate; - queue.splice(j, 1); - j--; - } else if (event1.type == Blockly.Events.CHANGE && - event2.type == Blockly.Events.CHANGE && + if (event1.type == event2.type && event1.blockId == event2.blockId && - event1.element == event2.element && - event1.name == event2.name) { - // Merge change events. - event1.newValue = event2.newValue; - queue.splice(j, 1); - j--; + event1.workspaceId == event2.workspaceId) { + if (event1.type == Blockly.Events.MOVE) { + // Merge move events. + event1.newParentId = event2.newParentId; + event1.newInputName = event2.newInputName; + event1.newCoordinate = event2.newCoordinate; + queue.splice(j, 1); + j--; + } else if (event1.type == Blockly.Events.CHANGE && + event1.element == event2.element && + event1.name == event2.name) { + // Merge change events. + event1.newValue = event2.newValue; + queue.splice(j, 1); + j--; + } } } } From dd219d6f9ae861a56ebe3bdf0c3d0bacc3a83a74 Mon Sep 17 00:00:00 2001 From: Neil Fraser Date: Thu, 7 Apr 2016 14:40:51 -0700 Subject: [PATCH 9/9] Routine recompile. --- blockly_compressed.js | 136 +++++++++++++++++++++------------------- blockly_uncompressed.js | 2 +- msg/js/ba.js | 6 +- 3 files changed, 75 insertions(+), 69 deletions(-) diff --git a/blockly_compressed.js b/blockly_compressed.js index bb3ffa92c..ca3644a9f 100644 --- a/blockly_compressed.js +++ b/blockly_compressed.js @@ -856,14 +856,15 @@ goog.ui.tree.TreeControl.prototype.createNode=function(a){return new goog.ui.tre // Copyright 2013 Google Inc. Apache License 2.0 var Blockly={Blocks:{}}; // Copyright 2012 Google Inc. Apache License 2.0 -Blockly.Workspace=function(a){this.id=Blockly.genUid();Blockly.Workspace.WorkspaceDB_[this.id]=this;this.options=a||{};this.RTL=!!this.options.RTL;this.topBlocks_=[];this.listeners_=[];this.undoStack_=[];this.redoStack_=[]};Blockly.Workspace.prototype.rendered=!1;Blockly.Workspace.prototype.MAX_UNDO=1024;Blockly.Workspace.prototype.dispose=function(){this.listeners_.length=0;this.clear();delete Blockly.Workspace.WorkspaceDB_[this.id]};Blockly.Workspace.SCAN_ANGLE=3; -Blockly.Workspace.prototype.addTopBlock=function(a){this.topBlocks_.push(a)};Blockly.Workspace.prototype.removeTopBlock=function(a){for(var b=!1,c,d=0;c=this.topBlocks_[d];d++)if(c==a){this.topBlocks_.splice(d,1);b=!0;break}if(!b)throw"Block not present in workspace's list of top-most blocks.";}; +Blockly.Workspace=function(a){this.id=Blockly.genUid();Blockly.Workspace.WorkspaceDB_[this.id]=this;this.options=a||{};this.RTL=!!this.options.RTL;this.topBlocks_=[];this.listeners_=[];this.undoStack_=[];this.redoStack_=[];this.blockDB_=Object.create(null)};Blockly.Workspace.prototype.rendered=!1;Blockly.Workspace.prototype.MAX_UNDO=1024;Blockly.Workspace.prototype.dispose=function(){this.listeners_.length=0;this.clear();delete Blockly.Workspace.WorkspaceDB_[this.id]}; +Blockly.Workspace.SCAN_ANGLE=3;Blockly.Workspace.prototype.addTopBlock=function(a){this.topBlocks_.push(a)};Blockly.Workspace.prototype.removeTopBlock=function(a){for(var b=!1,c,d=0;c=this.topBlocks_[d];d++)if(c==a){this.topBlocks_.splice(d,1);b=!0;break}if(!b)throw"Block not present in workspace's list of top-most blocks.";}; Blockly.Workspace.prototype.getTopBlocks=function(a){var b=[].concat(this.topBlocks_);if(a&&1this.MAX_UNDO&&this.undoStack_.unshift());for(var b=0,c;c=this.listeners_[b];b++)c(a)};Blockly.Workspace.WorkspaceDB_=Object.create(null); -Blockly.Workspace.getById=function(a){return Blockly.Workspace.WorkspaceDB_[a]||null};Blockly.Workspace.prototype.clear=Blockly.Workspace.prototype.clear;Blockly.Workspace.prototype.clearUndo=Blockly.Workspace.prototype.clearUndo;Blockly.Workspace.prototype.addChangeListener=Blockly.Workspace.prototype.addChangeListener;Blockly.Workspace.prototype.removeChangeListener=Blockly.Workspace.prototype.removeChangeListener;Blockly.Bubble=function(a,b,c,d,e,f,g){this.workspace_=a;this.content_=b;this.shape_=c;c=Blockly.Bubble.ARROW_ANGLE;this.workspace_.RTL&&(c=-c);this.arrow_radians_=goog.math.toRadians(c);a.getBubbleCanvas().appendChild(this.createDom_(b,!(!f||!g)));this.setAnchorLocation(d,e);f&&g||(b=this.content_.getBBox(),f=b.width+2*Blockly.Bubble.BORDER_WIDTH,g=b.height+2*Blockly.Bubble.BORDER_WIDTH);this.setBubbleSize(f,g);this.positionBubble_();this.renderArrow_();this.rendered_=!0;a.options.readOnly||(Blockly.bindEvent_(this.bubbleBack_, +Blockly.Workspace.prototype.addChangeListener=function(a){this.listeners_.push(a);return a};Blockly.Workspace.prototype.removeChangeListener=function(a){a=this.listeners_.indexOf(a);-1!=a&&this.listeners_.splice(a,1)};Blockly.Workspace.prototype.fireChangeListener=function(a){a.recordUndo&&(this.undoStack_.push(a),this.redoStack_.length=0,this.undoStack_.length>this.MAX_UNDO&&this.undoStack_.unshift());for(var b=0,c;c=this.listeners_[b];b++)c(a)}; +Blockly.Workspace.prototype.getBlockById=function(a){return this.blockDB_[a]||null};Blockly.Workspace.WorkspaceDB_=Object.create(null);Blockly.Workspace.getById=function(a){return Blockly.Workspace.WorkspaceDB_[a]||null};Blockly.Workspace.prototype.clear=Blockly.Workspace.prototype.clear;Blockly.Workspace.prototype.clearUndo=Blockly.Workspace.prototype.clearUndo;Blockly.Workspace.prototype.addChangeListener=Blockly.Workspace.prototype.addChangeListener; +Blockly.Workspace.prototype.removeChangeListener=Blockly.Workspace.prototype.removeChangeListener;Blockly.Bubble=function(a,b,c,d,e,f,g){this.workspace_=a;this.content_=b;this.shape_=c;c=Blockly.Bubble.ARROW_ANGLE;this.workspace_.RTL&&(c=-c);this.arrow_radians_=goog.math.toRadians(c);a.getBubbleCanvas().appendChild(this.createDom_(b,!(!f||!g)));this.setAnchorLocation(d,e);f&&g||(b=this.content_.getBBox(),f=b.width+2*Blockly.Bubble.BORDER_WIDTH,g=b.height+2*Blockly.Bubble.BORDER_WIDTH);this.setBubbleSize(f,g);this.positionBubble_();this.renderArrow_();this.rendered_=!0;a.options.readOnly||(Blockly.bindEvent_(this.bubbleBack_, "mousedown",this,this.bubbleMouseDown_),this.resizeGroup_&&Blockly.bindEvent_(this.resizeGroup_,"mousedown",this,this.resizeMouseDown_))};Blockly.Bubble.BORDER_WIDTH=6;Blockly.Bubble.ARROW_THICKNESS=10;Blockly.Bubble.ARROW_ANGLE=20;Blockly.Bubble.ARROW_BEND=4;Blockly.Bubble.ANCHOR_RADIUS=8;Blockly.Bubble.onMouseUpWrapper_=null;Blockly.Bubble.onMouseMoveWrapper_=null; Blockly.Bubble.unbindDragEvents_=function(){Blockly.Bubble.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Bubble.onMouseUpWrapper_),Blockly.Bubble.onMouseUpWrapper_=null);Blockly.Bubble.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Bubble.onMouseMoveWrapper_),Blockly.Bubble.onMouseMoveWrapper_=null)};Blockly.Bubble.prototype.rendered_=!1;Blockly.Bubble.prototype.anchorX_=0;Blockly.Bubble.prototype.anchorY_=0;Blockly.Bubble.prototype.relativeLeft_=0;Blockly.Bubble.prototype.relativeTop_=0; Blockly.Bubble.prototype.width_=0;Blockly.Bubble.prototype.height_=0;Blockly.Bubble.prototype.autoLayout_=!0; @@ -912,7 +913,7 @@ Blockly.Connection.prototype.isConnectionAllowed=function(a,b){if(this.distanceF !this.sourceBlock_.nextConnection)return!1;var c=a.getSourceBlock(),d=this.sourceBlock_;if(c&&d){do{if(d==c)return!1;c=c.getParent()}while(c)}return!0};Blockly.Connection.prototype.connect=function(a){this.targetConnection!=a&&(this.checkConnection_(a),this.isSuperior()?Blockly.Connection.connect_(this,a):Blockly.Connection.connect_(a,this))};Blockly.Connection.connectReciprocally_=function(a,b){goog.asserts.assert(a&&b,"Cannot connect null connections.");a.targetConnection=b;b.targetConnection=a}; Blockly.Connection.singleConnection_=function(a,b){for(var c=!1,d=0;db&&(b=c[d].length);var e,d=-Infinity,f,g=1;do{e=d;f=a;for(var h=[],k=c.length/g,l=1,d=0;de);return f}; Blockly.Tooltip.wrapScore_=function(a,b,c){for(var d=[0],e=[],f=0;fd&&(d=h,e=g)}return e?Blockly.Tooltip.wrapMutate_(a,e,c):b};Blockly.Tooltip.wrapToText_=function(a,b){for(var c=[],d=0;da.y_)c=d;else{b=d;break}}return b};Blockly.ConnectionDB.prototype.removeConnection_=function(a){if(!a.inDB_)throw"Connection not in database.";var b=this.findConnection(a);if(-1==b)throw"Unable to find connection in connectionDB.";a.inDB_=!1;this.splice(b,1)}; Blockly.ConnectionDB.prototype.getNeighbours=function(a,b){function c(a){var c=e-d[a].x_,g=f-d[a].y_;Math.sqrt(c*c+g*g)<=b&&l.push(d[a]);return g"!=d.slice(-2)&&(b+=" ")}a=a.join("\n");a=a.replace(/(<(\w+)\b[^>]*>[^\n]*)\n *<\/\2>/g,"$1");return a.replace(/^\n/,"")}; Blockly.Xml.textToDom=function(a){a=(new DOMParser).parseFromString(a,"text/xml");if(!a||!a.firstChild||"xml"!=a.firstChild.nodeName.toLowerCase()||a.firstChild!==a.lastChild)throw"Blockly.Xml.textToDom did not obtain a valid XML tree.";return a.firstChild}; -Blockly.Xml.domToWorkspace=function(a,b){var c;a.RTL&&(c=a.getWidth());Blockly.Field.startCache();var d=b.childNodes.length,e=Blockly.Events.getGroup();e||Blockly.Events.setGroup(!0);for(var f=0;f=this.remainingCapacity())){Blockly.terminateDrag_();Blockly.Events.disable();var b=Blockly.Xml.domToBlock(this,a),c=parseInt(a.getAttribute("x"),10);a=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(a)){this.RTL&&(c=-c);do{for(var d=!1,e=this.getAllBlocks(),f=0,g;g=e[f];f++)if(g=g.getRelativeToSurfaceXY(),1>=Math.abs(c-g.x)&&1>=Math.abs(a-g.y)){d=!0;break}if(!d)for(e=b.getConnections_(!1), +Blockly.WorkspaceSvg.prototype.highlightBlock=function(a){this.traceOn_&&Blockly.dragMode_!=Blockly.DRAG_NONE&&this.traceOn(!1);if(this.traceOn_){var b=null;if(a&&(b=this.getBlockById(a),!b))return;this.traceOn(!1);b?b.select():Blockly.selected&&Blockly.selected.unselect();var c=this;setTimeout(function(){c.traceOn(!0)},1)}}; +Blockly.WorkspaceSvg.prototype.paste=function(a){if(this.rendered&&!(a.getElementsByTagName("block").length>=this.remainingCapacity())){Blockly.terminateDrag_();Blockly.Events.disable();var b=Blockly.Xml.domToBlock(a,this),c=parseInt(a.getAttribute("x"),10);a=parseInt(a.getAttribute("y"),10);if(!isNaN(c)&&!isNaN(a)){this.RTL&&(c=-c);do{for(var d=!1,e=this.getAllBlocks(),f=0,g;g=e[f];f++)if(g=g.getRelativeToSurfaceXY(),1>=Math.abs(c-g.x)&&1>=Math.abs(a-g.y)){d=!0;break}if(!d)for(e=b.getConnections_(!1), f=0;g=e[f];f++)if(g.closest(Blockly.SNAP_RADIUS,c,a).connection){d=!0;break}d&&(c=this.RTL?c-Blockly.SNAP_RADIUS:c+Blockly.SNAP_RADIUS,a+=2*Blockly.SNAP_RADIUS)}while(d);b.moveBy(c,a)}Blockly.Events.enable();Blockly.Events.isEnabled()&&!b.isShadow()&&Blockly.Events.fire(new Blockly.Events.Create(b));b.select()}}; Blockly.WorkspaceSvg.prototype.recordDeleteAreas=function(){this.deleteAreaTrash_=this.trashcan?this.trashcan.getClientRect():null;this.deleteAreaToolbox_=this.flyout_?this.flyout_.getClientRect():this.toolbox_?this.toolbox_.getClientRect():null}; Blockly.WorkspaceSvg.prototype.isDeleteArea=function(a){a=new goog.math.Coordinate(a.clientX,a.clientY);if(this.deleteAreaTrash_){if(this.deleteAreaTrash_.contains(a))return this.trashcan.setOpen_(!0),Blockly.Css.setCursor(Blockly.Css.Cursor.DELETE),!0;this.trashcan.setOpen_(!1)}if(this.deleteAreaToolbox_&&this.deleteAreaToolbox_.contains(a))return Blockly.Css.setCursor(Blockly.Css.Cursor.DELETE),!0;Blockly.Css.setCursor(Blockly.Css.Cursor.CLOSED);return!1}; @@ -1036,8 +1045,8 @@ Blockly.WorkspaceSvg.prototype.showContextMenu_=function(a){function b(a){if(a.i h.text=Blockly.Msg.COLLAPSE_ALL;h.callback=function(){q(!0)};d.push(h);g={enabled:g};g.text=Blockly.Msg.EXPAND_ALL;g.callback=function(){q(!1)};d.push(g)}for(var m=[],k=0;km.length||window.confirm(Blockly.Msg.DELETE_ALL_BLOCKS.replace("%1",String(m.length))))&&c()}};d.push(g);Blockly.ContextMenu.show(a,d,this.RTL)}}; Blockly.WorkspaceSvg.prototype.loadAudio_=function(a,b){if(a.length){try{var c=new window.Audio}catch(h){return}for(var d,e=0;ethis.options.zoomOptions.maxScale?c=this.options.zoomOptions.maxScale/this.scale:dthis.options.zoomOptions.maxScale?c=this.options.zoomOptions.maxScale:c=b.height&&(k-=g.height);c?g.width>=a.clientX&&(e+=g.width):a.clientX+g.width>=b.width&&(e-=g.width);Blockly.WidgetDiv.position(e,k,b,f,c);d.setAllowAutoFocus(!0);setTimeout(function(){h.focus()},1);Blockly.ContextMenu.currentBlock=null}else Blockly.ContextMenu.hide()}; Blockly.ContextMenu.hide=function(){Blockly.WidgetDiv.hideIfOwner(Blockly.ContextMenu);Blockly.ContextMenu.currentBlock=null}; -Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();var c=Blockly.Xml.domToBlock(a.workspace,b),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y);Blockly.Events.enable();Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.Create(c));c.select()}};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.createSvgElement("g",{},null);this.svgPathDark_=Blockly.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;Blockly.Tooltip.bindMouseEvents(this.svgPath_);Blockly.BlockSvg.superClass_.constructor.call(this, +Blockly.ContextMenu.callbackFactory=function(a,b){return function(){Blockly.Events.disable();var c=Blockly.Xml.domToBlock(b,a.workspace),d=a.getRelativeToSurfaceXY();d.x=a.RTL?d.x-Blockly.SNAP_RADIUS:d.x+Blockly.SNAP_RADIUS;d.y+=2*Blockly.SNAP_RADIUS;c.moveBy(d.x,d.y);Blockly.Events.enable();Blockly.Events.isEnabled()&&!c.isShadow()&&Blockly.Events.fire(new Blockly.Events.Create(c));c.select()}};Blockly.BlockSvg=function(a,b,c){this.svgGroup_=Blockly.createSvgElement("g",{},null);this.svgPathDark_=Blockly.createSvgElement("path",{"class":"blocklyPathDark",transform:"translate(1,1)"},this.svgGroup_);this.svgPath_=Blockly.createSvgElement("path",{"class":"blocklyPath"},this.svgGroup_);this.svgPathLight_=Blockly.createSvgElement("path",{"class":"blocklyPathLight"},this.svgGroup_);this.svgPath_.tooltip=this;this.rendered=!1;Blockly.Tooltip.bindMouseEvents(this.svgPath_);Blockly.BlockSvg.superClass_.constructor.call(this, a,b,c)};goog.inherits(Blockly.BlockSvg,Blockly.Block);Blockly.BlockSvg.prototype.height=0;Blockly.BlockSvg.prototype.width=0;Blockly.BlockSvg.prototype.dragStartXY_=null;Blockly.BlockSvg.INLINE=-1; Blockly.BlockSvg.prototype.initSvg=function(){goog.asserts.assert(this.workspace.rendered,"Workspace is headless.");for(var a=0,b;b=this.inputList[a];a++)b.init();b=this.getIcons();for(a=0;a";var d=Blockly.Xml.textToDom(""+a+"");b.domToMutation(d.firstChild)}Blockly.Events.fire(new Blockly.Events.Change(b,"mutation",null,c,a));break;default:console.warn("Unknown change type: "+this.element)}else console.warn("Can't change non-existant block: "+this.blockId)}; -Blockly.Events.Move=function(a){Blockly.Events.Move.superClass_.constructor.call(this,a);a=this.currentLocation_();this.oldParentId=a.parentId;this.oldInputName=a.inputName;this.oldCoordinate=a.coordinate};goog.inherits(Blockly.Events.Move,Blockly.Events.Abstract);Blockly.Events.Move.prototype.type=Blockly.Events.MOVE; -Blockly.Events.Move.prototype.toJson=function(){var a=Blockly.Events.Move.superClass_.toJson.call(this);this.newParentId&&(a.newParentId=this.newParentId);this.newInputName&&(a.newInputName=this.newInputName);this.newCoordinate&&(a.newCoordinate=Math.round(this.newCoordinate.x)+","+Math.round(this.newCoordinate.y));return a};Blockly.Events.Move.prototype.recordNew=function(){var a=this.currentLocation_();this.newParentId=a.parentId;this.newInputName=a.inputName;this.newCoordinate=a.coordinate}; -Blockly.Events.Move.prototype.currentLocation_=function(){var a=Blockly.Block.getById(this.blockId),b={},c=a.getParent();if(c){if(b.parentId=c.id,a=c.getInputWithBlock(a))b.inputName=a.name}else b.coordinate=a.getRelativeToSurfaceXY();return b};Blockly.Events.Move.prototype.isNull=function(){return this.oldParentId==this.newParentId&&this.oldInputName==this.newInputName&&goog.math.Coordinate.equals(this.oldCoordinate,this.newCoordinate)}; -Blockly.Events.Move.prototype.run=function(a){var b=Blockly.Block.getById(this.blockId);if(b){var c=a?this.newParentId:this.oldParentId,d=a?this.newInputName:this.oldInputName;a=a?this.newCoordinate:this.oldCoordinate;var e=null;if(c&&(e=Blockly.Block.getById(c),!e)){console.warn("Can't connect to non-existant block: "+c);return}b.getParent()&&b.unplug();if(a)d=b.getRelativeToSurfaceXY(),b.moveBy(a.x-d.x,a.y-d.y);else{var b=b.outputConnection||b.previousConnection,f;if(d){if(c=e.getInput(d))f=c.connection}else b.type== -Blockly.PREVIOUS_STATEMENT&&(f=e.nextConnection);f?b.connect(f):console.warn("Can't connect to non-existant input: "+d)}}else console.warn("Can't move non-existant block: "+this.blockId)};Blockly.Events.Ui=function(a,b,c,d){Blockly.Events.Ui.superClass_.constructor.call(this,a);this.element=b;this.oldValue=c;this.newValue=d;this.recordUndo=!1};goog.inherits(Blockly.Events.Ui,Blockly.Events.Abstract);Blockly.Events.Ui.prototype.type=Blockly.Events.UI; -Blockly.Events.Ui.prototype.toJson=function(){var a=Blockly.Events.Ui.superClass_.toJson.call(this);a.element=this.element;void 0!==this.newValue&&(a.newValue=this.newValue);return a};Blockly.Msg={};goog.getMsgOrig=goog.getMsg;goog.getMsg=function(a,b){var c=goog.getMsg.blocklyMsgMap[a];c&&(a=Blockly.Msg[c]);return goog.getMsgOrig(a,b)};goog.getMsg.blocklyMsgMap={Today:"TODAY"};Blockly.FieldTextInput=function(a,b){Blockly.FieldTextInput.superClass_.constructor.call(this,a,b)};goog.inherits(Blockly.FieldTextInput,Blockly.Field);Blockly.FieldTextInput.FONTSIZE=11;Blockly.FieldTextInput.prototype.CURSOR="text";Blockly.FieldTextInput.prototype.spellcheck_=!0;Blockly.FieldTextInput.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldTextInput.superClass_.dispose.call(this)}; +Blockly.Events.filter=function(a,b){var c=goog.array.clone(a);b||c.reverse();for(var d=0,e;e=c[d];d++)for(var f=d+1,g;g=c[f];f++)e.type==g.type&&e.blockId==g.blockId&&e.workspaceId==g.workspaceId&&(e.type==Blockly.Events.MOVE?(e.newParentId=g.newParentId,e.newInputName=g.newInputName,e.newCoordinate=g.newCoordinate,c.splice(f,1),f--):e.type==Blockly.Events.CHANGE&&e.element==g.element&&e.name==g.name&&(e.newValue=g.newValue,c.splice(f,1),f--));for(d=c.length-1;0<=d;d--)c[d].isNull()&&c.splice(d,1); +b||c.reverse();for(d=1;e=c[d];d++)e.type==Blockly.Events.CHANGE&&"mutation"==e.element&&c.unshift(c.splice(d,1)[0]);return c};Blockly.Events.clearPendingUndo=function(){for(var a=0,b;b=Blockly.Events.FIRE_QUEUE_[a];a++)b.recordUndo=!1};Blockly.Events.disable=function(){Blockly.Events.disabled_++};Blockly.Events.enable=function(){Blockly.Events.disabled_--};Blockly.Events.isEnabled=function(){return 0==Blockly.Events.disabled_};Blockly.Events.getGroup=function(){return Blockly.Events.group_}; +Blockly.Events.setGroup=function(a){Blockly.Events.group_="boolean"==typeof a?a?Blockly.genUid():"":a};Blockly.Events.getDescendantIds_=function(a){var b=[];a=a.getDescendants();for(var c=0,d;d=a[c];c++)b[c]=d.id;return b}; +Blockly.Events.fromJson=function(a,b){var c;switch(a.type){case Blockly.Events.CREATE:c=new Blockly.Events.Create(null);break;case Blockly.Events.DELETE:c=new Blockly.Events.Delete(null);break;case Blockly.Events.CHANGE:c=new Blockly.Events.Change(null);break;case Blockly.Events.MOVE:c=new Blockly.Events.Move(null);break;case Blockly.Events.UI:c=new Blockly.Events.Ui(null);break;default:throw"Unknown event type.";}c.fromJson(a);c.workspaceId=b.id;return c}; +Blockly.Events.Abstract=function(a){a&&(this.blockId=a.id,this.workspaceId=a.workspace.id);this.group=Blockly.Events.group_;this.recordUndo=Blockly.Events.recordUndo};Blockly.Events.Abstract.prototype.toJson=function(){var a={type:this.type,blockId:this.blockId};this.group&&(a.group=this.group);return a};Blockly.Events.Abstract.prototype.fromJson=function(a){this.blockId=a.blockId;this.group=a.group};Blockly.Events.Abstract.prototype.isNull=function(){return!1}; +Blockly.Events.Abstract.prototype.run=function(a){};Blockly.Events.Create=function(a){a&&(Blockly.Events.Create.superClass_.constructor.call(this,a),this.xml=Blockly.Xml.blockToDomWithXY(a),this.ids=Blockly.Events.getDescendantIds_(a))};goog.inherits(Blockly.Events.Create,Blockly.Events.Abstract);Blockly.Events.Create.prototype.type=Blockly.Events.CREATE; +Blockly.Events.Create.prototype.toJson=function(){var a=Blockly.Events.Create.superClass_.toJson.call(this);a.xml=Blockly.Xml.domToText(this.xml);a.ids=this.ids;return a};Blockly.Events.Create.prototype.fromJson=function(a){Blockly.Events.Create.superClass_.fromJson.call(this,a);this.xml=Blockly.Xml.textToDom(""+a.xml+"").firstChild;this.ids=a.ids}; +Blockly.Events.Create.prototype.run=function(a){var b=Blockly.Workspace.getById(this.workspaceId);if(a)a=goog.dom.createDom("xml"),a.appendChild(this.xml),Blockly.Xml.domToWorkspace(a,b);else{a=0;for(var c;c=this.ids[a];a++){var d=b.getBlockById(c);d?d.dispose(!1,!0):c==this.blockId&&console.warn("Can't uncreate non-existant block: "+c)}}}; +Blockly.Events.Delete=function(a){if(a){if(a.getParent())throw"Connected blocks cannot be deleted.";Blockly.Events.Delete.superClass_.constructor.call(this,a);this.oldXml=Blockly.Xml.blockToDomWithXY(a);this.ids=Blockly.Events.getDescendantIds_(a)}};goog.inherits(Blockly.Events.Delete,Blockly.Events.Abstract);Blockly.Events.Delete.prototype.type=Blockly.Events.DELETE;Blockly.Events.Delete.prototype.toJson=function(){var a=Blockly.Events.Delete.superClass_.toJson.call(this);a.ids=this.ids;return a}; +Blockly.Events.Delete.prototype.fromJson=function(a){Blockly.Events.Delete.superClass_.fromJson.call(this,a);this.ids=a.ids};Blockly.Events.Delete.prototype.run=function(a){var b=Blockly.Workspace.getById(this.workspaceId);if(a){a=0;for(var c;c=this.ids[a];a++){var d=b.getBlockById(c);d?d.dispose(!1,!0):c==this.blockId&&console.warn("Can't delete non-existant block: "+c)}}else a=goog.dom.createDom("xml"),a.appendChild(this.oldXml),Blockly.Xml.domToWorkspace(a,b)}; +Blockly.Events.Change=function(a,b,c,d,e){a&&(Blockly.Events.Change.superClass_.constructor.call(this,a),this.element=b,this.name=c,this.oldValue=d,this.newValue=e)};goog.inherits(Blockly.Events.Change,Blockly.Events.Abstract);Blockly.Events.Change.prototype.type=Blockly.Events.CHANGE;Blockly.Events.Change.prototype.toJson=function(){var a=Blockly.Events.Change.superClass_.toJson.call(this);a.element=this.element;this.name&&(a.name=this.name);a.newValue=this.newValue;return a}; +Blockly.Events.Change.prototype.fromJson=function(a){Blockly.Events.Change.superClass_.fromJson.call(this,a);this.element=a.element;this.name=a.name;this.newValue=a.newValue};Blockly.Events.Change.prototype.isNull=function(){return this.oldValue==this.newValue}; +Blockly.Events.Change.prototype.run=function(a){var b=Blockly.Workspace.getById(this.workspaceId).getBlockById(this.blockId);if(b)switch(b.mutator&&b.mutator.setVisible(!1),a=a?this.newValue:this.oldValue,this.element){case "field":(b=b.getField(this.name))?b.setValue(a):console.warn("Can't set non-existant field: "+this.name);break;case "comment":b.setCommentText(a||null);break;case "collapsed":b.setCollapsed(a);break;case "disabled":b.setDisabled(a);break;case "inline":b.setInputsInline(a);break; +case "mutation":var c="";b.mutationToDom&&(c=(c=b.mutationToDom())&&Blockly.Xml.domToText(c));if(b.domToMutation){a=a||"";var d=Blockly.Xml.textToDom(""+a+"");b.domToMutation(d.firstChild)}Blockly.Events.fire(new Blockly.Events.Change(b,"mutation",null,c,a));break;default:console.warn("Unknown change type: "+this.element)}else console.warn("Can't change non-existant block: "+this.blockId)}; +Blockly.Events.Move=function(a){a&&(Blockly.Events.Move.superClass_.constructor.call(this,a),a=this.currentLocation_(),this.oldParentId=a.parentId,this.oldInputName=a.inputName,this.oldCoordinate=a.coordinate)};goog.inherits(Blockly.Events.Move,Blockly.Events.Abstract);Blockly.Events.Move.prototype.type=Blockly.Events.MOVE; +Blockly.Events.Move.prototype.toJson=function(){var a=Blockly.Events.Move.superClass_.toJson.call(this);this.newParentId&&(a.newParentId=this.newParentId);this.newInputName&&(a.newInputName=this.newInputName);this.newCoordinate&&(a.newCoordinate=Math.round(this.newCoordinate.x)+","+Math.round(this.newCoordinate.y));return a}; +Blockly.Events.Move.prototype.fromJson=function(a){Blockly.Events.Move.superClass_.fromJson.call(this,a);this.newParentId=a.newParentId;this.newInputName=a.newInputName;a.newCoordinate&&(a=a.newCoordinate.split(","),this.newCoordinate=new goog.math.Coordinate(parseFloat(a[0]),parseFloat(a[1])))};Blockly.Events.Move.prototype.recordNew=function(){var a=this.currentLocation_();this.newParentId=a.parentId;this.newInputName=a.inputName;this.newCoordinate=a.coordinate}; +Blockly.Events.Move.prototype.currentLocation_=function(){var a=Blockly.Workspace.getById(this.workspaceId).getBlockById(this.blockId),b={},c=a.getParent();if(c){if(b.parentId=c.id,a=c.getInputWithBlock(a))b.inputName=a.name}else b.coordinate=a.getRelativeToSurfaceXY();return b};Blockly.Events.Move.prototype.isNull=function(){return this.oldParentId==this.newParentId&&this.oldInputName==this.newInputName&&goog.math.Coordinate.equals(this.oldCoordinate,this.newCoordinate)}; +Blockly.Events.Move.prototype.run=function(a){var b=Blockly.Workspace.getById(this.workspaceId),c=b.getBlockById(this.blockId);if(c){var d=a?this.newParentId:this.oldParentId,e=a?this.newInputName:this.oldInputName;a=a?this.newCoordinate:this.oldCoordinate;var f=null;if(d&&(f=b.getBlockById(d),!f)){console.warn("Can't connect to non-existant block: "+d);return}c.getParent()&&c.unplug();if(a)e=c.getRelativeToSurfaceXY(),c.moveBy(a.x-e.x,a.y-e.y);else{var c=c.outputConnection||c.previousConnection, +g;if(e){if(b=f.getInput(e))g=b.connection}else c.type==Blockly.PREVIOUS_STATEMENT&&(g=f.nextConnection);g?c.connect(g):console.warn("Can't connect to non-existant input: "+e)}}else console.warn("Can't move non-existant block: "+this.blockId)};Blockly.Events.Ui=function(a,b,c,d){Blockly.Events.Ui.superClass_.constructor.call(this,a);this.element=b;this.oldValue=c;this.newValue=d;this.recordUndo=!1};goog.inherits(Blockly.Events.Ui,Blockly.Events.Abstract);Blockly.Events.Ui.prototype.type=Blockly.Events.UI; +Blockly.Events.Ui.prototype.toJson=function(){var a=Blockly.Events.Ui.superClass_.toJson.call(this);a.element=this.element;void 0!==this.newValue&&(a.newValue=this.newValue);return a};Blockly.Events.Ui.prototype.fromJson=function(a){Blockly.Events.Ui.superClass_.fromJson.call(this,a);this.element=a.element;this.newValue=a.newValue};Blockly.Msg={};goog.getMsgOrig=goog.getMsg;goog.getMsg=function(a,b){var c=goog.getMsg.blocklyMsgMap[a];c&&(a=Blockly.Msg[c]);return goog.getMsgOrig(a,b)};goog.getMsg.blocklyMsgMap={Today:"TODAY"};Blockly.FieldTextInput=function(a,b){Blockly.FieldTextInput.superClass_.constructor.call(this,a,b)};goog.inherits(Blockly.FieldTextInput,Blockly.Field);Blockly.FieldTextInput.FONTSIZE=11;Blockly.FieldTextInput.prototype.CURSOR="text";Blockly.FieldTextInput.prototype.spellcheck_=!0;Blockly.FieldTextInput.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldTextInput.superClass_.dispose.call(this)}; Blockly.FieldTextInput.prototype.setValue=function(a){if(null!==a){if(this.sourceBlock_&&this.validator_){var b=this.validator_(a);null!==b&&void 0!==b&&(a=b)}Blockly.Field.prototype.setValue.call(this,a)}};Blockly.FieldTextInput.prototype.setSpellcheck=function(a){this.spellcheck_=a}; Blockly.FieldTextInput.prototype.showEditor_=function(a){this.workspace_=this.sourceBlock_.workspace;a=a||!1;if(!a&&(goog.userAgent.MOBILE||goog.userAgent.ANDROID||goog.userAgent.IPAD)){a=window.prompt(Blockly.Msg.CHANGE_VALUE_TITLE,this.text_);if(this.sourceBlock_&&this.validator_){var b=this.validator_(a);void 0!==b&&(a=b)}this.setValue(a)}else{Blockly.WidgetDiv.show(this,this.sourceBlock_.RTL,this.widgetDispose_());var b=Blockly.WidgetDiv.DIV,c=goog.dom.createDom("input","blocklyHtmlInput");c.setAttribute("spellcheck", this.spellcheck_);var d=Blockly.FieldTextInput.FONTSIZE*this.workspace_.scale+"pt";b.style.fontSize=d;c.style.fontSize=d;Blockly.FieldTextInput.htmlInput_=c;b.appendChild(c);c.value=c.defaultValue=this.text_;c.oldValue_=null;this.validate_();this.resizeEditor_();a||(c.focus(),c.select());c.onKeyDownWrapper_=Blockly.bindEvent_(c,"keydown",this,this.onHtmlInputKeyDown_);c.onKeyUpWrapper_=Blockly.bindEvent_(c,"keyup",this,this.onHtmlInputChange_);c.onKeyPressWrapper_=Blockly.bindEvent_(c,"keypress", @@ -1225,7 +1235,7 @@ b,this.setValue(b),this.validate_(),this.resizeEditor_())};Blockly.FieldAngle.pr Blockly.FieldAngle.prototype.updateGraph_=function(){if(this.gauge_){var a=Number(this.getText())+Blockly.FieldAngle.OFFSET,b=goog.math.toRadians(a),a=["M ",Blockly.FieldAngle.HALF,",",Blockly.FieldAngle.HALF],c=Blockly.FieldAngle.HALF,d=Blockly.FieldAngle.HALF;if(!isNaN(b)){var e=goog.math.toRadians(Blockly.FieldAngle.OFFSET),f=Math.cos(e)*Blockly.FieldAngle.RADIUS,g=Math.sin(e)*-Blockly.FieldAngle.RADIUS;Blockly.FieldAngle.CLOCKWISE&&(b=2*e-b);c+=Math.cos(b)*Blockly.FieldAngle.RADIUS;d-=Math.sin(b)* Blockly.FieldAngle.RADIUS;b=Math.abs(Math.floor((b-e)/Math.PI)%2);Blockly.FieldAngle.CLOCKWISE&&(b=1-b);a.push(" l ",f,",",g," A ",Blockly.FieldAngle.RADIUS,",",Blockly.FieldAngle.RADIUS," 0 ",b," ",Number(Blockly.FieldAngle.CLOCKWISE)," ",c,",",d," z")}this.gauge_.setAttribute("d",a.join(""));this.line_.setAttribute("x2",c);this.line_.setAttribute("y2",d)}}; Blockly.FieldAngle.angleValidator=function(a){a=Blockly.FieldTextInput.numberValidator(a);null!==a&&(a%=360,0>a&&(a+=360),a>Blockly.FieldAngle.WRAP&&(a-=360),a=String(a));return a};Blockly.FieldCheckbox=function(a,b){Blockly.FieldCheckbox.superClass_.constructor.call(this,"",b);this.setValue(a)};goog.inherits(Blockly.FieldCheckbox,Blockly.Field);Blockly.FieldCheckbox.CHECK_CHAR="\u2713";Blockly.FieldCheckbox.prototype.CURSOR="default"; -Blockly.FieldCheckbox.prototype.init=function(a){this.sourceBlock_||(Blockly.FieldCheckbox.superClass_.init.call(this,a),this.checkElement_=Blockly.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_),a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR),this.checkElement_.appendChild(a),this.checkElement_.style.display=this.state_?"block":"none")};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()}; +Blockly.FieldCheckbox.prototype.init=function(a){this.fieldGroup_||(Blockly.FieldCheckbox.superClass_.init.call(this,a),this.checkElement_=Blockly.createSvgElement("text",{"class":"blocklyText blocklyCheckbox",x:-3,y:14},this.fieldGroup_),a=document.createTextNode(Blockly.FieldCheckbox.CHECK_CHAR),this.checkElement_.appendChild(a),this.checkElement_.style.display=this.state_?"block":"none")};Blockly.FieldCheckbox.prototype.getValue=function(){return String(this.state_).toUpperCase()}; Blockly.FieldCheckbox.prototype.setValue=function(a){a="TRUE"==a;this.state_!==a&&(this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.Change(this.sourceBlock_,"field",this.name,this.state_,a)),this.state_=a,this.checkElement_&&(this.checkElement_.style.display=a?"block":"none"))};Blockly.FieldCheckbox.prototype.showEditor_=function(){var a=!this.state_;if(this.sourceBlock_&&this.validator_){var b=this.validator_(a);void 0!==b&&(a=b)}null!==a&&this.setValue(String(a).toUpperCase())};Blockly.FieldColour=function(a,b){Blockly.FieldColour.superClass_.constructor.call(this,a,b);this.setText(Blockly.Field.NBSP+Blockly.Field.NBSP+Blockly.Field.NBSP)};goog.inherits(Blockly.FieldColour,Blockly.Field);Blockly.FieldColour.prototype.colours_=null;Blockly.FieldColour.prototype.columns_=0;Blockly.FieldColour.prototype.init=function(a){Blockly.FieldColour.superClass_.init.call(this,a);this.borderRect_.style.fillOpacity=1;this.setValue(this.getValue())}; Blockly.FieldColour.prototype.CURSOR="default";Blockly.FieldColour.prototype.dispose=function(){Blockly.WidgetDiv.hideIfOwner(this);Blockly.FieldColour.superClass_.dispose.call(this)};Blockly.FieldColour.prototype.getValue=function(){return this.colour_}; Blockly.FieldColour.prototype.setValue=function(a){this.sourceBlock_&&Blockly.Events.isEnabled()&&this.colour_!=a&&Blockly.Events.fire(new Blockly.Events.Change(this.sourceBlock_,"field",this.name,this.colour_,a));this.colour_=a;this.borderRect_&&(this.borderRect_.style.fill=a)};Blockly.FieldColour.prototype.getText=function(){var a=this.colour_,b=a.match(/^#(.)\1(.)\2(.)\3$/);b&&(a="#"+b[1]+b[2]+b[3]);return a};Blockly.FieldColour.COLOURS=goog.ui.ColorPicker.SIMPLE_GRID_COLORS; @@ -1233,7 +1243,7 @@ Blockly.FieldColour.COLUMNS=7;Blockly.FieldColour.prototype.setColours=function( Blockly.FieldColour.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,this.sourceBlock_.RTL,Blockly.FieldColour.widgetDispose_);var a=new goog.ui.ColorPicker;a.setSize(this.columns_||Blockly.FieldColour.COLUMNS);a.setColors(this.colours_||Blockly.FieldColour.COLOURS);var b=goog.dom.getViewportSize(),c=goog.style.getViewportPageOffset(document),d=this.getAbsoluteXY_(),e=this.getScaledBBox_();a.render(Blockly.WidgetDiv.DIV);a.setSelectedColor(this.getValue());var f=goog.style.getSize(a.getElement()); d.y=d.y+f.height+e.height>=b.height+c.y?d.y-(f.height-1):d.y+(e.height-1);this.sourceBlock_.RTL?(d.x+=e.width,d.x-=f.width,d.xb.width+c.x-f.width&&(d.x=b.width+c.x-f.width);Blockly.WidgetDiv.position(d.x,d.y,b,c,this.sourceBlock_.RTL);var g=this;Blockly.FieldColour.changeEventKey_=goog.events.listen(a,goog.ui.ColorPicker.EventType.CHANGE,function(a){a=a.target.getSelectedColor()||"#000000";Blockly.WidgetDiv.hide();if(g.sourceBlock_&&g.validator_){var b=g.validator_(a);void 0!== b&&(a=b)}null!==a&&g.setValue(a)})};Blockly.FieldColour.widgetDispose_=function(){Blockly.FieldColour.changeEventKey_&&goog.events.unlistenByKey(Blockly.FieldColour.changeEventKey_)};Blockly.FieldDropdown=function(a,b){this.menuGenerator_=a;this.trimOptions_();var c=this.getOptions_()[0];Blockly.FieldDropdown.superClass_.constructor.call(this,c[1],b)};goog.inherits(Blockly.FieldDropdown,Blockly.Field);Blockly.FieldDropdown.CHECKMARK_OVERHANG=25;Blockly.FieldDropdown.ARROW_CHAR=goog.userAgent.ANDROID?"\u25bc":"\u25be";Blockly.FieldDropdown.prototype.CURSOR="default"; -Blockly.FieldDropdown.prototype.init=function(a){this.sourceBlock_||(this.arrow_=Blockly.createSvgElement("tspan",{},null),this.arrow_.appendChild(document.createTextNode(a.RTL?Blockly.FieldDropdown.ARROW_CHAR+" ":" "+Blockly.FieldDropdown.ARROW_CHAR)),Blockly.FieldDropdown.superClass_.init.call(this,a),a=this.text_,this.text_=null,this.setText(a))}; +Blockly.FieldDropdown.prototype.init=function(a){this.fieldGroup_||(this.arrow_=Blockly.createSvgElement("tspan",{},null),this.arrow_.appendChild(document.createTextNode(a.RTL?Blockly.FieldDropdown.ARROW_CHAR+" ":" "+Blockly.FieldDropdown.ARROW_CHAR)),Blockly.FieldDropdown.superClass_.init.call(this,a),a=this.text_,this.text_=null,this.setText(a))}; Blockly.FieldDropdown.prototype.showEditor_=function(){Blockly.WidgetDiv.show(this,this.sourceBlock_.RTL,null);var a=this,b=new goog.ui.Menu;b.setRightToLeft(this.sourceBlock_.RTL);for(var c=this.getOptions_(),d=0;d=c.height+d.y?e.y-(h.height+2):e.y+f.height;this.sourceBlock_.RTL?(e.x+=f.width,e.x+=Blockly.FieldDropdown.CHECKMARK_OVERHANG,e.xc.width+d.x-h.width&&(e.x=c.width+d.x-h.width));Blockly.WidgetDiv.position(e.x,e.y,c,d,this.sourceBlock_.RTL);b.setAllowAutoFocus(!0); @@ -1243,14 +1253,14 @@ Blockly.FieldDropdown.prototype.getOptions_=function(){return goog.isFunction(th Blockly.FieldDropdown.prototype.setValue=function(a){if(null!==a&&a!==this.value_){this.sourceBlock_&&Blockly.Events.isEnabled()&&Blockly.Events.fire(new Blockly.Events.Change(this.sourceBlock_,"field",this.name,this.value_,a));this.value_=a;for(var b=this.getOptions_(),c=0;c=a.clientX&&0==a.clientY&&0==a.button)a.stopPropagation();else{var b=a.clientX-Blockly.Flyout.startDownEvent_.clientX;a=a.clientY-Blockly.Flyout.startDownEvent_.clientY;Math.sqrt(b*b+a*a)>Blockly.DRAG_RADIUS&&Blockly.Flyout.startFlyout_.createBlockFunc_(Blockly.Flyout.startBlock_)(Blockly.Flyout.startDownEvent_)}}; -Blockly.Flyout.prototype.createBlockFunc_=function(a){var b=this,c=this.targetWorkspace_;return function(d){if(!Blockly.isRightButton(d)&&!a.disabled){Blockly.Events.disable();var e=Blockly.Xml.blockToDom(a),e=Blockly.Xml.domToBlock(c,e),f=a.getSvgRoot();if(!f)throw"originBlock is not rendered.";f=Blockly.getSvgXY_(f,c);if(b.RTL){var g=c.getMetrics().viewWidth-b.width_;f.x+=g/c.scale-g}else f.x+=b.workspace_.scrollX/b.workspace_.scale-b.workspace_.scrollX;f.y+=b.workspace_.scrollY/b.workspace_.scale- +Blockly.Flyout.prototype.createBlockFunc_=function(a){var b=this,c=this.targetWorkspace_;return function(d){if(!Blockly.isRightButton(d)&&!a.disabled){Blockly.Events.disable();var e=Blockly.Xml.blockToDom(a),e=Blockly.Xml.domToBlock(e,c),f=a.getSvgRoot();if(!f)throw"originBlock is not rendered.";f=Blockly.getSvgXY_(f,c);if(b.RTL){var g=c.getMetrics().viewWidth-b.width_;f.x+=g/c.scale-g}else f.x+=b.workspace_.scrollX/b.workspace_.scale-b.workspace_.scrollX;f.y+=b.workspace_.scrollY/b.workspace_.scale- b.workspace_.scrollY;g=e.getSvgRoot();if(!g)throw"block is not rendered.";g=Blockly.getSvgXY_(g,c);g.x+=c.scrollX/c.scale-c.scrollX;g.y+=c.scrollY/c.scale-c.scrollY;c.toolbox_&&!c.scrollbar&&(g.x+=c.toolbox_.width/c.scale);e.moveBy(f.x-g.x,f.y-g.y);Blockly.Events.enable();Blockly.Events.isEnabled()&&(Blockly.Events.setGroup(!0),Blockly.Events.fire(new Blockly.Events.Create(e)));b.autoClose?b.hide():b.filterForCapacity_();e.onMouseDown_(d);Blockly.dragMode_=Blockly.DRAG_FREE;e.setDragging_(!0)}}}; Blockly.Flyout.prototype.filterForCapacity_=function(){for(var a=this.targetWorkspace_.remainingCapacity(),b=this.workspace_.getTopBlocks(!1),c=0,d;d=b[c];c++)if(-1==this.permanentlyDisabled_.indexOf(d)){var e=d.getDescendants();d.setDisabled(e.length>a)}};Blockly.Flyout.prototype.getClientRect=function(){var a=this.svgGroup_.getBoundingClientRect();if(this.RTL){var b=a.left+a.width+1E9;return new goog.math.Rect(a.left,-1E9,b,2E9)}b=1E9+a.width+a.left;return new goog.math.Rect(-1E9,-1E9,b,2E9)}; Blockly.Flyout.terminateDrag_=function(){Blockly.Flyout.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_),Blockly.Flyout.onMouseUpWrapper_=null);Blockly.Flyout.onMouseMoveBlockWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseMoveBlockWrapper_),Blockly.Flyout.onMouseMoveBlockWrapper_=null);Blockly.Flyout.onMouseMoveWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseMoveWrapper_),Blockly.Flyout.onMouseMoveWrapper_=null);Blockly.Flyout.onMouseUpWrapper_&&(Blockly.unbindEvent_(Blockly.Flyout.onMouseUpWrapper_), @@ -1333,11 +1343,7 @@ Blockly.Css.CONTENT=[".blocklySvg {","background-color: #fff;","outline: none;", Blockly.WidgetDiv.show=function(a,b,c){Blockly.WidgetDiv.hide();Blockly.WidgetDiv.owner_=a;Blockly.WidgetDiv.dispose_=c;a=goog.style.getViewportPageOffset(document);Blockly.WidgetDiv.DIV.style.top=a.y+"px";Blockly.WidgetDiv.DIV.style.direction=b?"rtl":"ltr";Blockly.WidgetDiv.DIV.style.display="block";Blockly.Events.setGroup(!0)}; Blockly.WidgetDiv.hide=function(){Blockly.WidgetDiv.owner_&&(Blockly.WidgetDiv.owner_=null,Blockly.WidgetDiv.DIV.style.display="none",Blockly.WidgetDiv.DIV.style.left="",Blockly.WidgetDiv.DIV.style.top="",Blockly.WidgetDiv.DIV.style.height="",Blockly.WidgetDiv.dispose_&&Blockly.WidgetDiv.dispose_(),Blockly.WidgetDiv.dispose_=null,goog.dom.removeChildren(Blockly.WidgetDiv.DIV),Blockly.Events.setGroup(!1))};Blockly.WidgetDiv.isVisible=function(){return!!Blockly.WidgetDiv.owner_}; Blockly.WidgetDiv.hideIfOwner=function(a){Blockly.WidgetDiv.owner_==a&&Blockly.WidgetDiv.hide()};Blockly.WidgetDiv.position=function(a,b,c,d,e){bc.width+d.x&&(a=c.width+d.x):aBlockly.DRAG_RADIUS&& Blockly.longStop_();a.stopPropagation()}}}; -Blockly.onKeyDown_=function(a){if(!Blockly.isTargetInput_(a)){var b=!1;if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode)try{Blockly.selected&&Blockly.selected.isDeletable()&&(b=!0)}finally{a.preventDefault()}else if(a.altKey||a.ctrlKey||a.metaKey)Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&&(67==a.keyCode?(Blockly.hideChaff(),Blockly.copy_(Blockly.selected)):88==a.keyCode&&(Blockly.copy_(Blockly.selected),b=!0)),86==a.keyCode?Blockly.clipboardXml_&& -Blockly.clipboardSource_.paste(Blockly.clipboardXml_):90==a.keyCode&&(Blockly.hideChaff(),Blockly.mainWorkspace.undo(a.shiftKey));b&&(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(Blockly.dragMode_!=Blockly.DRAG_FREE,!0),Blockly.highlightedConnection_&&(Blockly.highlightedConnection_.unhighlight(),Blockly.highlightedConnection_=null),Blockly.Events.setGroup(!1))}};Blockly.terminateDrag_=function(){Blockly.BlockSvg.terminateDrag_();Blockly.Flyout.terminateDrag_()}; -Blockly.longPid_=0;Blockly.longStart_=function(a,b){Blockly.longStop_();Blockly.longPid_=setTimeout(function(){a.button=2;b.onMouseDown_(a)},Blockly.LONGPRESS)};Blockly.longStop_=function(){Blockly.longPid_&&(clearTimeout(Blockly.longPid_),Blockly.longPid_=0)}; +Blockly.onKeyDown_=function(a){if(!Blockly.mainWorkspace.options.readOnly&&!Blockly.isTargetInput_(a)){var b=!1;if(27==a.keyCode)Blockly.hideChaff();else if(8==a.keyCode||46==a.keyCode)try{Blockly.selected&&Blockly.selected.isDeletable()&&(b=!0)}finally{a.preventDefault()}else if(a.altKey||a.ctrlKey||a.metaKey)Blockly.selected&&Blockly.selected.isDeletable()&&Blockly.selected.isMovable()&&(67==a.keyCode?(Blockly.hideChaff(),Blockly.copy_(Blockly.selected)):88==a.keyCode&&(Blockly.copy_(Blockly.selected), +b=!0)),86==a.keyCode?Blockly.clipboardXml_&&Blockly.clipboardSource_.paste(Blockly.clipboardXml_):90==a.keyCode&&(Blockly.hideChaff(),Blockly.mainWorkspace.undo(a.shiftKey));b&&(Blockly.Events.setGroup(!0),Blockly.hideChaff(),Blockly.selected.dispose(Blockly.dragMode_!=Blockly.DRAG_FREE,!0),Blockly.highlightedConnection_&&(Blockly.highlightedConnection_.unhighlight(),Blockly.highlightedConnection_=null),Blockly.Events.setGroup(!1))}}; +Blockly.terminateDrag_=function(){Blockly.BlockSvg.terminateDrag_();Blockly.Flyout.terminateDrag_()};Blockly.longPid_=0;Blockly.longStart_=function(a,b){Blockly.longStop_();Blockly.longPid_=setTimeout(function(){a.button=2;b.onMouseDown_(a)},Blockly.LONGPRESS)};Blockly.longStop_=function(){Blockly.longPid_&&(clearTimeout(Blockly.longPid_),Blockly.longPid_=0)}; Blockly.copy_=function(a){var b=Blockly.Xml.blockToDom(a);Blockly.dragMode_!=Blockly.DRAG_FREE&&Blockly.Xml.deleteNext(b);var c=a.getRelativeToSurfaceXY();b.setAttribute("x",a.RTL?-c.x:c.x);b.setAttribute("y",c.y);Blockly.clipboardXml_=b;Blockly.clipboardSource_=a.workspace};Blockly.duplicate_=function(a){var b=Blockly.clipboardXml_,c=Blockly.clipboardSource_;Blockly.copy_(a);a.workspace.paste(Blockly.clipboardXml_);Blockly.clipboardXml_=b;Blockly.clipboardSource_=c}; Blockly.onContextMenu_=function(a){Blockly.isTargetInput_(a)||a.preventDefault()};Blockly.hideChaff=function(a){Blockly.Tooltip.hide();Blockly.WidgetDiv.hide();a||(a=Blockly.getMainWorkspace(),a.toolbox_&&a.toolbox_.flyout_&&a.toolbox_.flyout_.autoClose&&a.toolbox_.clearSelection())}; Blockly.getMainWorkspaceMetrics_=function(){var a=Blockly.svgSize(this.getParentSvg());this.toolbox_&&(a.width-=this.toolbox_.width);var b=Blockly.Flyout.prototype.CORNER_RADIUS-1,c=a.width-b,d=a.height-b,e=this.getBlocksBoundingBox(),f=e.width*this.scale,g=e.height*this.scale,h=e.x*this.scale,k=e.y*this.scale;this.scrollbar?(b=Math.min(h-c/2,h+f-c),c=Math.max(h+f+c/2,h+c),f=Math.min(k-d/2,k+g-d),d=Math.max(k+g+d/2,k+d)):(b=e.x,c=b+e.width,f=e.y,d=f+e.height);e=0;!this.RTL&&this.toolbox_&&(e=this.toolbox_.width); diff --git a/blockly_uncompressed.js b/blockly_uncompressed.js index fc3a55af8..3b7f6e0ab 100644 --- a/blockly_uncompressed.js +++ b/blockly_uncompressed.js @@ -80,7 +80,7 @@ goog.addDependency("../../../" + dir + "/core/variables.js", ['Blockly.Variables goog.addDependency("../../../" + dir + "/core/warning.js", ['Blockly.Warning'], ['Blockly.Bubble', 'Blockly.Icon']); goog.addDependency("../../../" + dir + "/core/widgetdiv.js", ['Blockly.WidgetDiv'], ['Blockly.Css', 'goog.dom', 'goog.style']); goog.addDependency("../../../" + dir + "/core/workspace.js", ['Blockly.Workspace'], ['goog.math']); -goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.ScrollbarPair', 'Blockly.Trashcan', 'Blockly.Workspace', 'Blockly.Xml', 'Blockly.ZoomControls', 'goog.dom', 'goog.math.Coordinate', 'goog.userAgent']); +goog.addDependency("../../../" + dir + "/core/workspace_svg.js", ['Blockly.WorkspaceSvg'], ['Blockly.ConnectionDB', 'Blockly.Options', 'Blockly.ScrollbarPair', 'Blockly.Trashcan', 'Blockly.Workspace', 'Blockly.Xml', 'Blockly.ZoomControls', 'goog.dom', 'goog.math.Coordinate', 'goog.userAgent']); goog.addDependency("../../../" + dir + "/core/xml.js", ['Blockly.Xml'], ['goog.dom']); goog.addDependency("../../../" + dir + "/core/zoom_controls.js", ['Blockly.ZoomControls'], ['goog.dom']); goog.addDependency("../../alltests.js", [], []); diff --git a/msg/js/ba.js b/msg/js/ba.js index b93d82c89..8c6b00db1 100644 --- a/msg/js/ba.js +++ b/msg/js/ba.js @@ -316,9 +316,9 @@ Blockly.Msg.TEXT_CREATE_JOIN_TITLE_JOIN = "ҡушылығыҙ"; Blockly.Msg.TEXT_CREATE_JOIN_TOOLTIP = "Add, remove, or reorder sections to reconfigure this text block."; // untranslated Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_END = "to letter # from end"; // untranslated Blockly.Msg.TEXT_GET_SUBSTRING_END_FROM_START = "# хатҡа"; -Blockly.Msg.TEXT_GET_SUBSTRING_END_LAST = "to last letter"; // untranslated +Blockly.Msg.TEXT_GET_SUBSTRING_END_LAST = "һуңғы хәрефкә тиклем"; Blockly.Msg.TEXT_GET_SUBSTRING_HELPURL = "https://github.com/google/blockly/wiki/Text#extracting-a-region-of-text"; // untranslated -Blockly.Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT = "in text"; // untranslated +Blockly.Msg.TEXT_GET_SUBSTRING_INPUT_IN_TEXT = "текста"; Blockly.Msg.TEXT_GET_SUBSTRING_START_FIRST = "get substring from first letter"; // untranslated Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_END = "get substring from letter # from end"; // untranslated Blockly.Msg.TEXT_GET_SUBSTRING_START_FROM_START = "get substring from letter #"; // untranslated @@ -326,7 +326,7 @@ Blockly.Msg.TEXT_GET_SUBSTRING_TAIL = ""; // untranslated Blockly.Msg.TEXT_GET_SUBSTRING_TOOLTIP = "Returns a specified portion of the text."; // untranslated Blockly.Msg.TEXT_INDEXOF_HELPURL = "https://github.com/google/blockly/wiki/Text#finding-text"; // untranslated Blockly.Msg.TEXT_INDEXOF_INPUT_INTEXT = "текстҡа"; -Blockly.Msg.TEXT_INDEXOF_OPERATOR_FIRST = "find first occurrence of text"; // untranslated +Blockly.Msg.TEXT_INDEXOF_OPERATOR_FIRST = "текстың тәүге инеүен табырға"; Blockly.Msg.TEXT_INDEXOF_OPERATOR_LAST = "Текстың һуңғы инеүен табырға"; Blockly.Msg.TEXT_INDEXOF_TAIL = ""; // untranslated Blockly.Msg.TEXT_INDEXOF_TOOLTIP = "Returns the index of the first/last occurrence of the first text in the second text. Returns 0 if text is not found."; // untranslated