diff --git a/core/events.js b/core/events.js index 3a4f33b21..36dc17069 100644 --- a/core/events.js +++ b/core/events.js @@ -55,29 +55,53 @@ Blockly.Events.recordUndo = true; Blockly.Events.disabled_ = 0; /** - * Name of event that creates a block. + * Name of event that creates a block. Will be deprecated for BLOCK_CREATE. * @const */ Blockly.Events.CREATE = 'create'; /** - * Name of event that deletes a block. + * Name of event that creates a block. + * @const + */ +Blockly.Events.BLOCK_CREATE = Blockly.Events.CREATE; + +/** + * Name of event that deletes a block. Will be deprecated for BLOCK_DELETE. * @const */ Blockly.Events.DELETE = 'delete'; /** - * Name of event that changes a block. + * Name of event that deletes a block. + * @const + */ +Blockly.Events.BLOCK_DELETE = Blockly.Events.DELETE; + +/** + * Name of event that changes a block. Will be deprecated for BLOCK_CHANGE. * @const */ Blockly.Events.CHANGE = 'change'; /** - * Name of event that moves a block. + * Name of event that changes a block. + * @const + */ +Blockly.Events.BLOCK_CHANGE = Blockly.Events.CHANGE; + +/** + * Name of event that moves a block. Will be deprecated for BLOCK_MOVE. * @const */ Blockly.Events.MOVE = 'move'; +/** + * Name of event that moves a block. + * @const + */ +Blockly.Events.BLOCK_MOVE = Blockly.Events.MOVE; + /** * Name of event that records a UI change. * @const @@ -364,6 +388,14 @@ Blockly.Events.Create = function(block) { }; goog.inherits(Blockly.Events.Create, Blockly.Events.Abstract); +/** + * Class for a block creation event. + * @param {Blockly.Block} block The created block. Null for a blank event. + * @extends {Blockly.Events.Abstract} + * @constructor + */ +Blockly.Events.BlockCreate = Blockly.Events.Create; + /** * Type of this event. * @type {string} @@ -438,6 +470,14 @@ Blockly.Events.Delete = function(block) { }; goog.inherits(Blockly.Events.Delete, Blockly.Events.Abstract); +/** + * Class for a block deletion event. + * @param {Blockly.Block} block The deleted block. Null for a blank event. + * @extends {Blockly.Events.Abstract} + * @constructor + */ +Blockly.Events.BlockDelete = Blockly.Events.Delete; + /** * Type of this event. * @type {string} @@ -508,6 +548,18 @@ Blockly.Events.Change = function(block, element, name, oldValue, newValue) { }; goog.inherits(Blockly.Events.Change, Blockly.Events.Abstract); +/** + * Class for a block change event. + * @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. + * @param {string} newValue New value of element. + * @extends {Blockly.Events.Abstract} + * @constructor + */ +Blockly.Events.BlockChange = Blockly.Events.Change; + /** * Type of this event. * @type {string} @@ -624,6 +676,15 @@ Blockly.Events.Move = function(block) { }; goog.inherits(Blockly.Events.Move, Blockly.Events.Abstract); + +/** + * Class for a block move event. Created before the move. + * @param {Blockly.Block} block The moved block. Null for a blank event. + * @extends {Blockly.Events.Abstract} + * @constructor + */ +Blockly.Events.BlockMove = Blockly.Events.Move; + /** * Type of this event. * @type {string} diff --git a/tests/jsunit/event_test.js b/tests/jsunit/event_test.js new file mode 100644 index 000000000..e4513026a --- /dev/null +++ b/tests/jsunit/event_test.js @@ -0,0 +1,231 @@ +/** + * @license + * Visual Blocks Editor + * + * Copyright 2017 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. + */ + + /** + * @fileoverview Tests for Blockly.Events + * @author marisaleung@google.com (Marisa Leung) + */ +'use strict'; + +goog.require('goog.testing'); +goog.require('goog.testing.MockControl'); + +var mockControl_; +var saved_msg = Blockly.Msg.DELETE_VARIABLE; +var workspace; + +function eventTest_setUp() { + workspace = new Blockly.Workspace(); + mockControl_ = new goog.testing.MockControl(); +} + +function eventTest_setUpWithMockBlocks() { + eventTest_setUp(); + Blockly.defineBlocksWithJsonArray([{ + 'type': 'field_variable_test_block', + 'message0': '%1', + 'args0': [ + { + 'type': 'field_variable', + 'name': 'VAR', + 'variable': 'item' + } + ], + }]); + // Need to define this because field_variable's dropdownCreate() calls replace + // on undefined value, Blockly.Msg.DELETE_VARIABLE. To fix this, define + // Blockly.Msg.DELETE_VARIABLE as %1 so the replace function finds the %1 it + // expects. + Blockly.Msg.DELETE_VARIABLE = '%1'; +} + +function eventTest_tearDown() { + mockControl_.$tearDown(); + workspace.dispose(); +} + +function eventTest_tearDownWithMockBlocks() { + eventTest_tearDown(); + delete Blockly.Blocks.field_variable_test_block; + Blockly.Msg.DELETE_VARIABLE = saved_msg; +} + +function test_abstract_constructor_block() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, '1'); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.Abstract(block); + assertEquals('1', event.blockId); + assertEquals(workspace.id, event.workspaceId); + assertEquals('', event.group); + assertEquals(true, event.recordUndo); + eventTest_tearDownWithMockBlocks(); +} + +function test_abstract_constructor_null() { + eventTest_setUpWithMockBlocks(); + var event = new Blockly.Events.Abstract(null); + assertUndefined(event.blockId); + assertUndefined(event.workspaceId); + assertEquals('', event.group); + assertEquals(true, event.recordUndo); + eventTest_tearDownWithMockBlocks(); +} + +function checkCreateEventValues(event, block, ids, type) { + var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block)); + var result_xml = Blockly.Xml.domToText(event.xml); + assertEquals(expected_xml, result_xml); + isEqualArrays(ids, event.ids); + assertEquals(type, event.type); +} + +function checkDeleteEventValues(event, block, ids, type) { + var expected_xml = Blockly.Xml.domToText(Blockly.Xml.blockToDom(block)); + var result_xml = Blockly.Xml.domToText(event.oldXml); + assertEquals(expected_xml, result_xml); + isEqualArrays(ids, event.ids); + assertEquals(type, event.type); +} + +function checkChangeAndMoveEventValues(event, values) { + var keys = Object.keys(values); + for (var i = 0, field; field = keys[i]; i++) { + assertEquals(values[field], event[field]); + } +} + +function test_create_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.Create(block); + checkCreateEventValues(event, block, ['1'], 'create'); + eventTest_tearDownWithMockBlocks(); +} + +function test_blockCreate_constructor() { + // expect that blockCreate behaves the same as create. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.BlockCreate(block); + checkCreateEventValues(event, block, ['1'], 'create'); + eventTest_tearDownWithMockBlocks(); +} + +function test_delete_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.Delete(block); + checkDeleteEventValues(event, block, ['1'], 'delete'); + eventTest_tearDownWithMockBlocks(); +} + +function test_blockDelete_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.BlockDelete(block); + checkDeleteEventValues(event, block, ['1'], 'delete'); + eventTest_tearDownWithMockBlocks(); +} + +function test_change_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.Change(block, 'field', 'VAR', 'item', 'item2'); + checkChangeAndMoveEventValues(event, {'element': 'field', 'name': 'VAR', + 'oldValue': 'item', 'newValue': 'item2', 'type': 'change'}); + eventTest_tearDownWithMockBlocks(); +} + +function test_blockChange_constructor() { + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1']); + var block = new Blockly.Block(workspace, 'field_variable_test_block'); + var event = new Blockly.Events.BlockChange(block, 'field', 'VAR', 'item', + 'item2'); + checkChangeAndMoveEventValues(event, {'element': 'field', 'name': 'VAR', + 'oldValue': 'item', 'newValue': 'item2', 'type': 'change'}); + eventTest_tearDownWithMockBlocks(); +} + +function test_move_constructorCoordinate() { + // Expect the oldCoordinate to be set. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + var block1 = new Blockly.Block(workspace, 'field_variable_test_block'); + var coordinate = new goog.math.Coordinate(3,4); + block1.xy_ = coordinate; + + var event = new Blockly.Events.Move(block1); + checkChangeAndMoveEventValues(event, {'oldCoordinate': coordinate, + 'type': 'move'}); + eventTest_tearDownWithMockBlocks(); +} + +function test_move_constructoroldParentId() { + // Expect the oldParentId to be set but not the oldCoordinate to be set. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + var block1 = new Blockly.Block(workspace, 'field_variable_test_block'); + var block2 = new Blockly.Block(workspace, 'field_variable_test_block'); + block1.parentBlock_ = block2; + block1.xy_ = new goog.math.Coordinate(3,4); + + var event = new Blockly.Events.Move(block1); + checkChangeAndMoveEventValues(event, {'oldCoordinate': undefined, + 'oldParentId': '2', 'type': 'move'}); + block1.parentBlock_ = null; + eventTest_tearDownWithMockBlocks(); +} + +function test_blockMove_constructorCoordinate() { + // Expect the oldCoordinate to be set. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + var block1 = new Blockly.Block(workspace, 'field_variable_test_block'); + var coordinate = new goog.math.Coordinate(3,4); + block1.xy_ = coordinate; + + var event = new Blockly.Events.BlockMove(block1); + checkChangeAndMoveEventValues(event, {'oldCoordinate': coordinate, + 'type': 'move'}); + eventTest_tearDownWithMockBlocks(); +} + +function test_blockMove_constructoroldParentId() { + // Expect the oldParentId to be set but not the oldCoordinate to be set. + eventTest_setUpWithMockBlocks(); + setUpMockMethod(mockControl_, Blockly.utils, 'genUid', null, ['1', '2']); + var block1 = new Blockly.Block(workspace, 'field_variable_test_block'); + var block2 = new Blockly.Block(workspace, 'field_variable_test_block'); + block1.parentBlock_ = block2; + block1.xy_ = new goog.math.Coordinate(3,4); + + var event = new Blockly.Events.BlockMove(block1); + checkChangeAndMoveEventValues(event, {'oldCoordinate': undefined, + 'oldParentId': '2', 'type': 'move'}); + block1.parentBlock_ = null; + eventTest_tearDownWithMockBlocks(); +} diff --git a/tests/jsunit/index.html b/tests/jsunit/index.html index bfef4841e..c4a60b7d8 100644 --- a/tests/jsunit/index.html +++ b/tests/jsunit/index.html @@ -12,6 +12,7 @@ +