mirror of
https://github.com/scratchfoundation/scratch-blocks.git
synced 2025-08-28 22:10:31 -04:00
Create block id database.
This commit is contained in:
parent
b2bbde04a1
commit
3b3ef79fbd
9 changed files with 84 additions and 70 deletions
|
@ -46,11 +46,16 @@ goog.require('goog.string');
|
|||
* @param {!Blockly.Workspace} workspace The block's workspace.
|
||||
* @param {?string} prototypeName Name of the language object containing
|
||||
* type-specific functions for this block.
|
||||
* @param {=string} opt_id Optional ID. Use this ID if provided, otherwise
|
||||
* create a new id.
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.Block = function(workspace, prototypeName) {
|
||||
Blockly.Block = function(workspace, prototypeName, opt_id) {
|
||||
/** @type {string} */
|
||||
this.id = Blockly.genUid();
|
||||
this.id = opt_id || Blockly.genUid();
|
||||
goog.asserts.assert(!Blockly.Block.getById(this.id),
|
||||
'Error: Block "%s" already exists.', this.id);
|
||||
Blockly.Block.BlockDB_[this.id] = this;
|
||||
/** @type {Blockly.Connection} */
|
||||
this.outputConnection = null;
|
||||
/** @type {Blockly.Connection} */
|
||||
|
@ -140,20 +145,6 @@ Blockly.Block.obtain = function(workspace, prototypeName) {
|
|||
*/
|
||||
Blockly.Block.prototype.data = null;
|
||||
|
||||
/**
|
||||
* Get an existing block.
|
||||
* @param {string} id The block's id.
|
||||
* @param {!Blockly.Workspace} workspace The block's workspace.
|
||||
* @return {Blockly.Block} The found block, or null if not found.
|
||||
*/
|
||||
Blockly.Block.getById = function(id, workspace) {
|
||||
if (Blockly.Realtime.isEnabled()) {
|
||||
return Blockly.Realtime.getBlockById(id);
|
||||
} else {
|
||||
return workspace.getBlockById(id);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispose of this block.
|
||||
* @param {boolean} healStack If true, then try to heal any gap by connecting
|
||||
|
@ -201,10 +192,8 @@ Blockly.Block.prototype.dispose = function(healStack, animate,
|
|||
}
|
||||
connections[i].dispose();
|
||||
}
|
||||
// Remove from Realtime set of blocks.
|
||||
if (Blockly.Realtime.isEnabled() && !Blockly.Realtime.withinSync) {
|
||||
Blockly.Realtime.removeBlock(this);
|
||||
}
|
||||
// Remove from block database.
|
||||
delete Blockly.Block.BlockDB_[this.id];
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -1240,3 +1229,19 @@ Blockly.Block.prototype.getRelativeToSurfaceXY = function() {
|
|||
Blockly.Block.prototype.moveBy = function(dx, dy) {
|
||||
this.xy_.translate(dx, dy);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
};
|
||||
|
||||
|
|
|
@ -40,11 +40,14 @@ goog.require('goog.math.Coordinate');
|
|||
* @param {!Blockly.Workspace} workspace The block's workspace.
|
||||
* @param {?string} prototypeName Name of the language object containing
|
||||
* type-specific functions for this block.
|
||||
* @param {=string} opt_id Optional ID. Use this ID if provided, otherwise
|
||||
* create a new id.
|
||||
* @extends {Blockly.Block}
|
||||
* @constructor
|
||||
*/
|
||||
Blockly.BlockSvg = function(workspace, prototypeName) {
|
||||
Blockly.BlockSvg.superClass_.constructor.call(this, workspace, prototypeName);
|
||||
Blockly.BlockSvg = function(workspace, prototypeName, opt_id) {
|
||||
Blockly.BlockSvg.superClass_.constructor.call(this,
|
||||
workspace, prototypeName, opt_id);
|
||||
// Create core elements for the block.
|
||||
/** @type {SVGElement} */
|
||||
this.svgGroup_ = Blockly.createSvgElement('g', {}, null);
|
||||
|
|
|
@ -202,6 +202,8 @@ Blockly.Generator.prototype.valueToCode = function(block, name, order) {
|
|||
}
|
||||
// Value blocks must return code and order of operations info.
|
||||
// Statement blocks must only return code.
|
||||
goog.asserts.assertArray(tuple, 'Expecting tuple from value block "%s".',
|
||||
targetBlock.type);
|
||||
var code = tuple[0];
|
||||
var innerOrder = tuple[1];
|
||||
if (isNaN(innerOrder)) {
|
||||
|
@ -237,6 +239,7 @@ Blockly.Generator.prototype.statementToCode = function(block, name) {
|
|||
var code = this.blockToCode(targetBlock);
|
||||
// Value blocks must return code and order of operations info.
|
||||
// Statement blocks must only return code.
|
||||
goog.asserts.assertString(code, 'Expecting code from statement block "%s".',
|
||||
targetBlock && targetBlock.type);
|
||||
if (code) {
|
||||
code = this.prefixLines(/** @type {string} */ (code), this.INDENT);
|
||||
|
|
|
@ -152,10 +152,12 @@ Blockly.Workspace.prototype.getWidth = function() {
|
|||
* Obtain a newly created block.
|
||||
* @param {?string} prototypeName Name of the language object containing
|
||||
* type-specific functions for this block.
|
||||
* @param {=string} opt_id Optional ID. Use this ID if provided, otherwise
|
||||
* create a new id.
|
||||
* @return {!Blockly.Block} The created block.
|
||||
*/
|
||||
Blockly.Workspace.prototype.newBlock = function(prototypeName) {
|
||||
return new Blockly.Block(this, prototypeName);
|
||||
Blockly.Workspace.prototype.newBlock = function(prototypeName, opt_id) {
|
||||
return new Blockly.Block(this, prototypeName, opt_id);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -250,10 +250,12 @@ Blockly.WorkspaceSvg.prototype.dispose = function() {
|
|||
* Obtain a newly created block.
|
||||
* @param {?string} prototypeName Name of the language object containing
|
||||
* type-specific functions for this block.
|
||||
* @param {=string} opt_id Optional ID. Use this ID if provided, otherwise
|
||||
* create a new id.
|
||||
* @return {!Blockly.BlockSvg} The created block.
|
||||
*/
|
||||
Blockly.WorkspaceSvg.prototype.newBlock = function(prototypeName) {
|
||||
return new Blockly.BlockSvg(this, prototypeName);
|
||||
Blockly.WorkspaceSvg.prototype.newBlock = function(prototypeName, opt_id) {
|
||||
return new Blockly.BlockSvg(this, prototypeName, opt_id);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -445,7 +447,7 @@ Blockly.WorkspaceSvg.prototype.highlightBlock = function(id) {
|
|||
}
|
||||
var block = null;
|
||||
if (id) {
|
||||
block = this.getBlockById(id);
|
||||
block = Blockly.Block.getById(id);
|
||||
if (!block) {
|
||||
return;
|
||||
}
|
||||
|
|
35
core/xml.js
35
core/xml.js
|
@ -295,14 +295,11 @@ Blockly.Xml.domToWorkspace = function(workspace, xml) {
|
|||
* workspace.
|
||||
* @param {!Blockly.Workspace} workspace The workspace.
|
||||
* @param {!Element} xmlBlock XML block element.
|
||||
* @param {boolean=} opt_reuseBlock Optional arg indicating whether to
|
||||
* reinitialize an existing block.
|
||||
* @return {!Blockly.Block} The root block created.
|
||||
*/
|
||||
Blockly.Xml.domToBlock = function(workspace, xmlBlock, opt_reuseBlock) {
|
||||
Blockly.Xml.domToBlock = function(workspace, xmlBlock) {
|
||||
// Create top-level block.
|
||||
var topBlock = Blockly.Xml.domToBlockHeadless_(workspace, xmlBlock,
|
||||
opt_reuseBlock);
|
||||
var topBlock = Blockly.Xml.domToBlockHeadless_(workspace, xmlBlock);
|
||||
if (workspace.rendered) {
|
||||
// Hide connections to speed up assembly.
|
||||
topBlock.setConnectionsHidden(true);
|
||||
|
@ -334,37 +331,17 @@ Blockly.Xml.domToBlock = function(workspace, xmlBlock, opt_reuseBlock) {
|
|||
* workspace.
|
||||
* @param {!Blockly.Workspace} workspace The workspace.
|
||||
* @param {!Element} xmlBlock XML block element.
|
||||
* @param {boolean=} opt_reuseBlock Optional arg indicating whether to
|
||||
* reinitialize an existing block.
|
||||
* @return {!Blockly.Block} The root block created.
|
||||
* @private
|
||||
*/
|
||||
Blockly.Xml.domToBlockHeadless_ =
|
||||
function(workspace, xmlBlock, opt_reuseBlock) {
|
||||
Blockly.Xml.domToBlockHeadless_ = function(workspace, xmlBlock) {
|
||||
var block = null;
|
||||
var prototypeName = xmlBlock.getAttribute('type');
|
||||
if (!prototypeName) {
|
||||
throw 'Block type unspecified: \n' + xmlBlock.outerHTML;
|
||||
}
|
||||
var id = xmlBlock.getAttribute('id');
|
||||
if (opt_reuseBlock && id) {
|
||||
// Only used by realtime.
|
||||
block = Blockly.Block.getById(id, workspace);
|
||||
// TODO: The following is for debugging. It should never actually happen.
|
||||
if (!block) {
|
||||
throw 'Couldn\'t get Block with id: ' + id;
|
||||
}
|
||||
var parentBlock = block.getParent();
|
||||
// If we've already filled this block then we will dispose of it and then
|
||||
// re-fill it.
|
||||
if (block.workspace) {
|
||||
block.dispose(true, false, true);
|
||||
}
|
||||
block.fill(workspace, prototypeName);
|
||||
block.parent_ = parentBlock;
|
||||
} else {
|
||||
block = workspace.newBlock(prototypeName);
|
||||
}
|
||||
block = workspace.newBlock(prototypeName, id);
|
||||
|
||||
var blockChild = null;
|
||||
for (var i = 0, xmlChild; xmlChild = xmlBlock.childNodes[i]; i++) {
|
||||
|
@ -453,7 +430,7 @@ Blockly.Xml.domToBlockHeadless_ =
|
|||
}
|
||||
if (childBlockNode) {
|
||||
blockChild = Blockly.Xml.domToBlockHeadless_(workspace,
|
||||
childBlockNode, opt_reuseBlock);
|
||||
childBlockNode);
|
||||
if (blockChild.outputConnection) {
|
||||
input.connection.connect(blockChild.outputConnection);
|
||||
} else if (blockChild.previousConnection) {
|
||||
|
@ -475,7 +452,7 @@ Blockly.Xml.domToBlockHeadless_ =
|
|||
throw 'Next statement is already connected.';
|
||||
}
|
||||
blockChild = Blockly.Xml.domToBlockHeadless_(workspace,
|
||||
childBlockNode, opt_reuseBlock);
|
||||
childBlockNode);
|
||||
if (!blockChild.previousConnection) {
|
||||
throw 'Next block does not have previous statement.';
|
||||
}
|
||||
|
|
35
tests/jsunit/block_test.js
Normal file
35
tests/jsunit/block_test.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
/**
|
||||
* @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_getById() {
|
||||
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));
|
||||
}
|
|
@ -8,6 +8,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<script src="blockly_test.js"></script>
|
||||
<script src="block_test.js"></script>
|
||||
<script src="connection_test.js"></script>
|
||||
<script src="generator_test.js"></script>
|
||||
<script src="names_test.js"></script>
|
||||
|
|
|
@ -66,17 +66,3 @@ function test_maxBlocksWorkspace() {
|
|||
workspace.clear();
|
||||
assertEquals('Cleared capacity.', 0, workspace.remainingCapacity());
|
||||
}
|
||||
|
||||
function test_getByIdWorkspace() {
|
||||
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));
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue