mirror of
https://github.com/google/blockly.git
synced 2026-01-10 02:17:09 +01:00
Merge pull request #2389 from BeksOmega/feature/SerializableFields
Added isSerializable and SERIALIZABLE to Field
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -172,10 +172,24 @@ Blockly.Field.prototype.clickTarget_ = null;
|
||||
Blockly.Field.NBSP = '\u00A0';
|
||||
|
||||
/**
|
||||
* Editable fields are saved by the XML renderer, non-editable fields are not.
|
||||
* Editable fields usually show some sort of UI indicating they are editable.
|
||||
* They will also be saved by the XML renderer.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
* @default
|
||||
*/
|
||||
Blockly.Field.prototype.EDITABLE = true;
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable. This is not the
|
||||
* case by default so that SERIALIZABLE is backwards compatible.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
* @default
|
||||
*/
|
||||
Blockly.Field.prototype.SERIALIZABLE = false;
|
||||
|
||||
/**
|
||||
* Attach this field to a block.
|
||||
* @param {!Blockly.Block} block The block containing this field.
|
||||
@@ -268,8 +282,7 @@ Blockly.Field.prototype.updateEditable = function() {
|
||||
|
||||
/**
|
||||
* Check whether this field is currently editable. Some fields are never
|
||||
* editable (e.g. text labels). Those fields are not serialized to XML. Other
|
||||
* fields may be editable, and therefore serialized, but may exist on
|
||||
* EDITABLE (e.g. text labels). Other fields may be EDITABLE but may exist on
|
||||
* non-editable blocks.
|
||||
* @return {boolean} Whether this field is editable and on an editable block
|
||||
*/
|
||||
@@ -277,6 +290,26 @@ Blockly.Field.prototype.isCurrentlyEditable = function() {
|
||||
return this.EDITABLE && !!this.sourceBlock_ && this.sourceBlock_.isEditable();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether this field should be serialized by the XML renderer.
|
||||
* Handles the logic for backwards compatibility and incongruous states.
|
||||
* @return {boolean} Whether this field should be serialized or not.
|
||||
*/
|
||||
Blockly.Field.prototype.isSerializable = function() {
|
||||
var isSerializable = false;
|
||||
if (this.name) {
|
||||
if (this.SERIALIZABLE) {
|
||||
isSerializable = true;
|
||||
} else if (this.EDITABLE) {
|
||||
console.warn('Detected an editable field that was not serializable.' +
|
||||
' Please define SERIALIZABLE property as true on all editable custom' +
|
||||
' fields. Proceeding with serialization.');
|
||||
isSerializable = true;
|
||||
}
|
||||
}
|
||||
return isSerializable;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets whether this editable field is visible or not.
|
||||
* @return {boolean} True if visible.
|
||||
|
||||
@@ -66,6 +66,14 @@ Blockly.FieldAngle.fromJson = function(options) {
|
||||
return new Blockly.FieldAngle(options['angle']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldAngle.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Round angles to the nearest 15 degrees when using mouse.
|
||||
* Set to 0 to disable rounding.
|
||||
|
||||
@@ -58,6 +58,14 @@ Blockly.FieldCheckbox.fromJson = function(options) {
|
||||
return new Blockly.FieldCheckbox(options['checked'] ? 'TRUE' : 'FALSE');
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldCheckbox.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Character for the checkmark.
|
||||
*/
|
||||
|
||||
@@ -61,6 +61,14 @@ Blockly.FieldColour.fromJson = function(options) {
|
||||
return new Blockly.FieldColour(options['colour']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldColour.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Default width of a colour field.
|
||||
* @type {number}
|
||||
|
||||
@@ -69,6 +69,14 @@ Blockly.FieldDate.fromJson = function(options) {
|
||||
return new Blockly.FieldDate(options['date']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldDate.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Mouse cursor style when over the hotspot that initiates the editor.
|
||||
*/
|
||||
|
||||
@@ -76,6 +76,14 @@ Blockly.FieldDropdown.fromJson = function(options) {
|
||||
return new Blockly.FieldDropdown(options['options']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldDropdown.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Horizontal distance that a checkmark overhangs the dropdown.
|
||||
*/
|
||||
|
||||
@@ -84,7 +84,10 @@ Blockly.FieldImage.fromJson = function(options) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Editable fields are saved by the XML renderer, non-editable fields are not.
|
||||
* Editable fields usually show some sort of UI indicating they are
|
||||
* editable. This field should not.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldImage.prototype.EDITABLE = false;
|
||||
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @fileoverview Non-editable text field. Used for titles, labels, etc.
|
||||
* @fileoverview Non-editable, non-serializable text field. Used for titles,
|
||||
* labels, etc.
|
||||
* @author fraser@google.com (Neil Fraser)
|
||||
*/
|
||||
'use strict';
|
||||
@@ -34,7 +35,7 @@ goog.require('goog.math.Size');
|
||||
|
||||
|
||||
/**
|
||||
* Class for a non-editable field.
|
||||
* Class for a non-editable, non-serializable text field.
|
||||
* @param {string} text The initial content of the field.
|
||||
* @param {string=} opt_class Optional CSS class for the field's text.
|
||||
* @extends {Blockly.Field}
|
||||
@@ -62,7 +63,10 @@ Blockly.FieldLabel.fromJson = function(options) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Editable fields are saved by the XML renderer, non-editable fields are not.
|
||||
* Editable fields usually show some sort of UI indicating they are
|
||||
* editable. This field should not.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldLabel.prototype.EDITABLE = false;
|
||||
|
||||
|
||||
@@ -65,6 +65,14 @@ Blockly.FieldNumber.fromJson = function(options) {
|
||||
options['min'], options['max'], options['precision']);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldNumber.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Set the maximum, minimum and precision constraints on this field.
|
||||
* Any of these properties may be undefiend or NaN to be disabled.
|
||||
|
||||
@@ -69,6 +69,14 @@ Blockly.FieldTextInput.fromJson = function(options) {
|
||||
return field;
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldTextInput.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Point size of text. Should match blocklyText's font-size in CSS.
|
||||
*/
|
||||
|
||||
@@ -78,6 +78,14 @@ Blockly.FieldVariable.fromJson = function(options) {
|
||||
return new Blockly.FieldVariable(varname, null, variableTypes, defaultType);
|
||||
};
|
||||
|
||||
/**
|
||||
* Serializable fields are saved by the XML renderer, non-serializable fields
|
||||
* are not. Editable fields should also be serializable.
|
||||
* @type {boolean}
|
||||
* @const
|
||||
*/
|
||||
Blockly.FieldVariable.prototype.SERIALIZABLE = true;
|
||||
|
||||
/**
|
||||
* Initialize everything needed to render this field. This includes making sure
|
||||
* that the field's value is valid.
|
||||
|
||||
@@ -140,7 +140,7 @@ Blockly.Xml.fieldToDomVariable_ = function(field) {
|
||||
* @private
|
||||
*/
|
||||
Blockly.Xml.fieldToDom_ = function(field) {
|
||||
if (field.name && field.EDITABLE) {
|
||||
if (field.isSerializable()) {
|
||||
if (field.referencesVariables()) {
|
||||
return Blockly.Xml.fieldToDomVariable_(field);
|
||||
} else {
|
||||
|
||||
@@ -63,7 +63,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"style": "math_blocks",
|
||||
},
|
||||
{
|
||||
"type": "test_fields_dropdown_long",
|
||||
"type": "test_dropdowns_long",
|
||||
"message0": "long: %1",
|
||||
"args0": [
|
||||
{
|
||||
@@ -107,7 +107,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "test_fields_dropdown_images",
|
||||
"type": "test_dropdowns_images",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
@@ -133,7 +133,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "test_fields_dropdown_images_and_text",
|
||||
"type": "test_dropdowns_images_and_text",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
@@ -250,7 +250,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"helpUrl": ""
|
||||
},
|
||||
{
|
||||
"type": "test_fields_number",
|
||||
"type": "test_numbers_float",
|
||||
"message0": "float %1",
|
||||
"args0": [
|
||||
{
|
||||
@@ -264,7 +264,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"tooltip": "A number."
|
||||
},
|
||||
{
|
||||
"type": "test_fields_number_whole",
|
||||
"type": "test_numbers_whole",
|
||||
"message0": "precision 1 %1",
|
||||
"args0": [
|
||||
{
|
||||
@@ -279,7 +279,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"tooltip": "The number should be rounded to multiples of 1"
|
||||
},
|
||||
{
|
||||
"type": "test_fields_number_hundredths",
|
||||
"type": "test_numbers_hundredths",
|
||||
"message0": "precision 0.01 %1",
|
||||
"args0": [
|
||||
{
|
||||
@@ -294,7 +294,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"tooltip": "The number should be rounded to multiples of 0.01"
|
||||
},
|
||||
{
|
||||
"type": "test_fields_number_halves",
|
||||
"type": "test_numbers_halves",
|
||||
"message0": "precision 0.5 %1",
|
||||
"args0": [
|
||||
{
|
||||
@@ -309,7 +309,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"tooltip": "The number should be rounded to multiples of 0.5"
|
||||
},
|
||||
{
|
||||
"type": "test_fields_number_three_halves",
|
||||
"type": "test_numbers_three_halves",
|
||||
"message0": "precision 1.5 %1",
|
||||
"args0": [
|
||||
{
|
||||
@@ -324,7 +324,7 @@ Blockly.defineBlocksWithJsonArray([ // BEGIN JSON EXTRACT
|
||||
"tooltip": "The number should be rounded to multiples of 1.5"
|
||||
},
|
||||
{
|
||||
"type": "test_fields_integer_bounded",
|
||||
"type": "test_numbers_whole_bounded",
|
||||
"message0": "midi note %1",
|
||||
"args0": [
|
||||
{
|
||||
@@ -662,7 +662,7 @@ Blockly.Blocks['test_basic_empty_with_mutator'] = {
|
||||
}
|
||||
};
|
||||
|
||||
Blockly.Blocks['test_fields_dropdown_dynamic'] = {
|
||||
Blockly.Blocks['test_dropdowns_dynamic'] = {
|
||||
init: function() {
|
||||
var dropdown = new Blockly.FieldDropdown(this.dynamicOptions);
|
||||
this.appendDummyInput()
|
||||
|
||||
@@ -16,5 +16,5 @@
|
||||
"assertNotUndefined": true
|
||||
|
||||
},
|
||||
"extends": "eslint:recommended"
|
||||
"extends": "../../.eslintrc.json"
|
||||
}
|
||||
|
||||
@@ -3,18 +3,12 @@
|
||||
suite('Connections', function() {
|
||||
|
||||
suite('Rendered', function() {
|
||||
function assertAllConnectionsHidden(block) {
|
||||
assertAllConnectionsHiddenState(block, true);
|
||||
}
|
||||
function assertAllConnectionsVisible(block) {
|
||||
assertAllConnectionsHiddenState(block, false);
|
||||
}
|
||||
function assertAllConnectionsHiddenState(block, hidden) {
|
||||
var connections = block.getConnections_(true);
|
||||
for (var i = 0; i < connections.length; i++) {
|
||||
var connection = connections[i];
|
||||
if (connection.type == Blockly.PREVIOUS_STATEMENT
|
||||
|| connection.type == Blockly.OUTPUT_VALUE) {
|
||||
|| connection.type == Blockly.OUTPUT_VALUE) {
|
||||
// Only superior connections on inputs get hidden
|
||||
continue;
|
||||
}
|
||||
@@ -22,9 +16,15 @@ suite('Connections', function() {
|
||||
// The next connection is not hidden when collapsed
|
||||
continue;
|
||||
}
|
||||
assertEquals('Connection ' + i + ' failed', hidden, connections[i].hidden_)
|
||||
assertEquals('Connection ' + i + ' failed', hidden, connections[i].hidden_);
|
||||
}
|
||||
}
|
||||
function assertAllConnectionsHidden(block) {
|
||||
assertAllConnectionsHiddenState(block, true);
|
||||
}
|
||||
function assertAllConnectionsVisible(block) {
|
||||
assertAllConnectionsHiddenState(block, false);
|
||||
}
|
||||
|
||||
setup(function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
@@ -83,7 +83,7 @@ suite('Connections', function() {
|
||||
blockA.setCollapsed(true);
|
||||
|
||||
assertEquals(blockA, blockB.getParent());
|
||||
assertNull(blockC.getParent())
|
||||
assertNull(blockC.getParent());
|
||||
assertTrue(blockA.isCollapsed());
|
||||
assertAllConnectionsHidden(blockA);
|
||||
assertAllConnectionsHidden(blockB);
|
||||
@@ -180,7 +180,7 @@ suite('Connections', function() {
|
||||
blockA.setCollapsed(true);
|
||||
|
||||
assertEquals(blockA, blockB.getParent());
|
||||
assertNull(blockC.getParent())
|
||||
assertNull(blockC.getParent());
|
||||
assertTrue(blockA.isCollapsed());
|
||||
assertAllConnectionsHidden(blockA);
|
||||
assertAllConnectionsHidden(blockB);
|
||||
@@ -286,7 +286,7 @@ suite('Connections', function() {
|
||||
blockA.setCollapsed(true);
|
||||
|
||||
assertEquals(blockA, blockB.getParent());
|
||||
assertNull(blockC.getParent())
|
||||
assertNull(blockC.getParent());
|
||||
assertTrue(blockA.isCollapsed());
|
||||
assertAllConnectionsHidden(blockA);
|
||||
assertAllConnectionsHidden(blockB);
|
||||
@@ -307,7 +307,7 @@ suite('Connections', function() {
|
||||
var shadowBlock = connection.targetBlock();
|
||||
assertTrue(shadowBlock.isShadow());
|
||||
assertAllConnectionsHidden(shadowBlock);
|
||||
})
|
||||
});
|
||||
|
||||
test('Reveal shadow value', function() {
|
||||
var blocks = this.blocks;
|
||||
@@ -316,7 +316,7 @@ suite('Connections', function() {
|
||||
var shadowBlock = connection.targetBlock();
|
||||
assertTrue(shadowBlock.isShadow());
|
||||
assertAllConnectionsHidden(shadowBlock);
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -32,7 +32,7 @@ suite('Events', function() {
|
||||
function checkExactEventValues(event, values) {
|
||||
var keys = Object.keys(values);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var field = keys[i]
|
||||
var field = keys[i];
|
||||
assertEquals(values[field], event[field]);
|
||||
}
|
||||
}
|
||||
|
||||
73
tests/mocha/field_test.js
Normal file
73
tests/mocha/field_test.js
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
suite ('Abstract Fields', function() {
|
||||
suite ('Is Serializable', function() {
|
||||
// Both EDITABLE and SERIALIZABLE are default.
|
||||
function FieldDefault() {
|
||||
this.name = 'NAME';
|
||||
}
|
||||
FieldDefault.prototype = Object.create(Blockly.Field.prototype);
|
||||
// EDITABLE is false and SERIALIZABLE is default.
|
||||
function FieldFalseDefault() {
|
||||
this.name = 'NAME';
|
||||
}
|
||||
FieldFalseDefault.prototype = Object.create(Blockly.Field.prototype);
|
||||
FieldFalseDefault.prototype.EDITABLE = false;
|
||||
// EDITABLE is default and SERIALIZABLE is true.
|
||||
function FieldDefaultTrue() {
|
||||
this.name = 'NAME';
|
||||
}
|
||||
FieldDefaultTrue.prototype = Object.create(Blockly.Field.prototype);
|
||||
FieldDefaultTrue.prototype.SERIALIZABLE = true;
|
||||
// EDITABLE is false and SERIALIZABLE is true.
|
||||
function FieldFalseTrue() {
|
||||
this.name = 'NAME';
|
||||
}
|
||||
FieldFalseTrue.prototype = Object.create(Blockly.Field.prototype);
|
||||
FieldFalseTrue.prototype.EDITABLE = false;
|
||||
FieldFalseTrue.prototype.SERIALIZABLE = true;
|
||||
|
||||
/* Test Backwards Compatibility*/
|
||||
test('Editable Default(true), Serializable Default(false)', function() {
|
||||
// An old default field should be serialized.
|
||||
var field = new FieldDefault();
|
||||
console.log('You should receive a warning after this message');
|
||||
assertEquals(true, field.isSerializable());
|
||||
});
|
||||
test('Editable False, Serializable Default(false)', function() {
|
||||
// An old non-editable field should not be serialized.
|
||||
var field = new FieldFalseDefault();
|
||||
assertEquals(false, field.isSerializable());
|
||||
});
|
||||
/* Test Other Cases */
|
||||
test('Editable Default(true), Serializable True', function() {
|
||||
// A field that is both editable and serializable should be serialized.
|
||||
var field = new FieldDefaultTrue();
|
||||
assertEquals(true, field.isSerializable());
|
||||
});
|
||||
test('Editable False, Serializable True', function() {
|
||||
// A field that is not editable, but overrides serializable to true
|
||||
// should be serialized (e.g. field_label_serializable)
|
||||
var field = new FieldFalseTrue();
|
||||
assertEquals(true, field.isSerializable());
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -22,7 +22,9 @@
|
||||
<script src="block_test.js"></script>
|
||||
<script src="event_test.js"></script>
|
||||
<script src="connection_test.js"></script>
|
||||
<script src="field_test.js"></script>
|
||||
<script src="field_variable_test.js"></script>
|
||||
<script src="xml_test.js"></script>
|
||||
<script src="utils_test.js"></script>
|
||||
|
||||
<div id="blocklyDiv"></div>
|
||||
|
||||
273
tests/mocha/xml_test.js
Normal file
273
tests/mocha/xml_test.js
Normal file
@@ -0,0 +1,273 @@
|
||||
/**
|
||||
* @license
|
||||
* Visual Blocks Editor
|
||||
*
|
||||
* Copyright 2019 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.
|
||||
*/
|
||||
|
||||
suite('XML', function() {
|
||||
setup(function() {
|
||||
this.workspace = new Blockly.Workspace();
|
||||
});
|
||||
teardown(function() {
|
||||
this.workspace.dispose();
|
||||
});
|
||||
var assertSimpleField = function(fieldDom, name, text) {
|
||||
assertEquals(text, fieldDom.textContent);
|
||||
assertEquals(name, fieldDom.getAttribute('name'));
|
||||
};
|
||||
var assertNonSerializingField = function(fieldDom) {
|
||||
assertEquals(undefined, fieldDom.childNodes[0]);
|
||||
};
|
||||
var assertVariableField = function(fieldDom, name, type, id, text) {
|
||||
assertEquals(name, fieldDom.getAttribute('name'));
|
||||
assertEquals(type, fieldDom.getAttribute('variabletype'));
|
||||
assertEquals(id, fieldDom.getAttribute('id'));
|
||||
assertEquals(text, fieldDom.textContent);
|
||||
};
|
||||
suite('Serialization', function() {
|
||||
suite('Fields', function() {
|
||||
test('Angle', function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "field_angle_test_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_angle",
|
||||
"name": "ANGLE",
|
||||
"angle": 90
|
||||
}
|
||||
],
|
||||
}]);
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_angle_test_block');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
assertSimpleField(resultFieldDom, 'ANGLE', '90');
|
||||
delete Blockly.Blocks['field_angle_test_block'];
|
||||
});
|
||||
test('Checkbox', function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "field_checkbox_test_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_checkbox",
|
||||
"name": "CHECKBOX",
|
||||
"checked": true
|
||||
}
|
||||
],
|
||||
}]);
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_checkbox_test_block');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
assertSimpleField(resultFieldDom, 'CHECKBOX', 'TRUE');
|
||||
delete Blockly.Blocks['field_checkbox_test_block'];
|
||||
});
|
||||
test('Colour', function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "field_colour_test_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_colour",
|
||||
"name": "COLOUR",
|
||||
"colour": '#000099'
|
||||
}
|
||||
],
|
||||
}]);
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_colour_test_block');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
assertSimpleField(resultFieldDom, 'COLOUR', '#000099');
|
||||
delete Blockly.Blocks['field_colour_test_block'];
|
||||
});
|
||||
test('Date', function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "field_date_test_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_date",
|
||||
"name": "DATE",
|
||||
"date": "2020-02-20"
|
||||
}
|
||||
],
|
||||
}]);
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_date_test_block');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
assertSimpleField(resultFieldDom, 'DATE', '2020-02-20');
|
||||
delete Blockly.Blocks['field_date_test_block'];
|
||||
});
|
||||
test('Dropdown', function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "field_dropdown_test_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_dropdown",
|
||||
"name": "DROPDOWN",
|
||||
"options": [
|
||||
[
|
||||
"a",
|
||||
"A"
|
||||
],
|
||||
[
|
||||
"b",
|
||||
"B"
|
||||
],
|
||||
[
|
||||
"c",
|
||||
"C"
|
||||
]
|
||||
]
|
||||
}
|
||||
],
|
||||
}]);
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_dropdown_test_block');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
assertSimpleField(resultFieldDom, 'DROPDOWN', 'A');
|
||||
delete Blockly.Blocks['field_dropdown_test_block'];
|
||||
});
|
||||
test('Image', function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "field_image_test_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_image",
|
||||
"name": "IMAGE",
|
||||
"src": "https://blockly-demo.appspot.com/static/tests/media/a.png",
|
||||
"width": 32,
|
||||
"height": 32,
|
||||
"alt": "A"
|
||||
}
|
||||
],
|
||||
}]);
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_image_test_block');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block);
|
||||
assertNonSerializingField(resultFieldDom);
|
||||
delete Blockly.Blocks['field_image_test_block'];
|
||||
});
|
||||
test('Label', function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "field_label_test_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_label",
|
||||
"name": "LABEL",
|
||||
"text": "default"
|
||||
}
|
||||
],
|
||||
}]);
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_label_test_block');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block);
|
||||
assertNonSerializingField(resultFieldDom);
|
||||
delete Blockly.Blocks['field_label_test_block'];
|
||||
});
|
||||
test('Number', function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "field_number_test_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_number",
|
||||
"name": "NUMBER",
|
||||
"value": 97
|
||||
}
|
||||
],
|
||||
}]);
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_number_test_block');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
assertSimpleField(resultFieldDom, 'NUMBER', '97');
|
||||
delete Blockly.Blocks['field_number_test_block'];
|
||||
});
|
||||
test('Text Input', function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
"type": "field_text_input_test_block",
|
||||
"message0": "%1",
|
||||
"args0": [
|
||||
{
|
||||
"type": "field_input",
|
||||
"name": "TEXT",
|
||||
"text": "default"
|
||||
}
|
||||
],
|
||||
}]);
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_text_input_test_block');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
assertSimpleField(resultFieldDom, 'TEXT', 'default');
|
||||
});
|
||||
suite('Variable Fields', function() {
|
||||
setup(function() {
|
||||
Blockly.defineBlocksWithJsonArray([{
|
||||
'type': 'field_variable_test_block',
|
||||
'message0': '%1',
|
||||
'args0': [
|
||||
{
|
||||
'type': 'field_variable',
|
||||
'name': 'VAR',
|
||||
'variable': 'item'
|
||||
}
|
||||
]
|
||||
}]);
|
||||
});
|
||||
teardown(function() {
|
||||
delete Blockly.Blocks['field_variable_test_block'];
|
||||
});
|
||||
test('Variable Trivial', function() {
|
||||
this.workspace.createVariable('name1', '', 'id1');
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_variable_test_block');
|
||||
block.inputList[0].fieldRow[0].setValue('id1');
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
assertVariableField(resultFieldDom, 'VAR', '', 'id1', 'name1');
|
||||
});
|
||||
test('Variable Default Case', function() {
|
||||
var cacheGenUid = Blockly.utils.genUid;
|
||||
Blockly.utils.genUid = function() {
|
||||
return '1';
|
||||
};
|
||||
|
||||
try {
|
||||
this.workspace.createVariable('name1');
|
||||
|
||||
Blockly.Events.disable();
|
||||
var block = new Blockly.Block(this.workspace,
|
||||
'field_variable_test_block');
|
||||
block.inputList[0].fieldRow[0].setValue('1');
|
||||
Blockly.Events.enable();
|
||||
|
||||
var resultFieldDom = Blockly.Xml.blockToDom(block).childNodes[0];
|
||||
// Expect type is '' and id is '1' since we don't specify type and id.
|
||||
assertVariableField(resultFieldDom, 'VAR', '', '1', 'name1');
|
||||
} finally {
|
||||
Blockly.utils.genUid = cacheGenUid;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
suite('Deserialization', function() {
|
||||
|
||||
});
|
||||
});
|
||||
@@ -1192,41 +1192,63 @@ h1 {
|
||||
</statement>
|
||||
</block>
|
||||
</category>
|
||||
<category name="Fields">
|
||||
<label text="Numbers"></label>
|
||||
<block type="test_fields_number">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_fields_number_hundredths">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_fields_number_halves">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_fields_number_whole">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_fields_number_three_halves">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_fields_integer_bounded">
|
||||
<field name="NOTE">60</field>
|
||||
</block>
|
||||
<label text="Drop-downs"></label>
|
||||
<block type="test_fields_dropdown_long"></block>
|
||||
<block type="test_fields_dropdown_images"></block>
|
||||
<block type="test_fields_dropdown_images_and_text"></block>
|
||||
<label text="Dynamic Drop-downs"></label>
|
||||
<block type="test_fields_dropdown_dynamic"></block>
|
||||
<button text="Add option" callbackKey="addDynamicOption"></button>
|
||||
<button text="Remove option" callbackKey="removeDynamicOption"></button>
|
||||
<label text="Others"></label>
|
||||
<block type="test_fields_angle"></block>
|
||||
<block type="test_fields_date"></block>
|
||||
<block type="test_fields_text_input"></block>
|
||||
<block type="test_fields_checkbox"></block>
|
||||
<block type="test_fields_colour"></block>
|
||||
<block type="test_fields_variable"></block>
|
||||
<category name="Fields" expanded="true">
|
||||
<category name="Defaults">
|
||||
<block type="test_fields_angle"></block>
|
||||
<block type="test_fields_date"></block>
|
||||
<block type="test_fields_checkbox"></block>
|
||||
<block type="test_fields_colour"></block>
|
||||
<block type="test_fields_text_input"></block>
|
||||
<block type="test_fields_variable"></block>
|
||||
</category>
|
||||
<category name="Numbers">
|
||||
<block type="test_numbers_float">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_numbers_hundredths">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_numbers_halves">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_numbers_whole">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_numbers_three_halves">
|
||||
<field name="NUM">123.456</field>
|
||||
</block>
|
||||
<block type="test_numbers_whole_bounded">
|
||||
<field name="NOTE">60</field>
|
||||
</block>
|
||||
</category>
|
||||
<category name="Drop-downs">
|
||||
<label text="Dynamic"></label>
|
||||
<block type="test_dropdowns_dynamic"></block>
|
||||
<button text="Add option" callbackKey="addDynamicOption"></button>
|
||||
<button text="Remove option" callbackKey="removeDynamicOption"></button>
|
||||
<label text="Other"></label>
|
||||
<block type="test_dropdowns_long"></block>
|
||||
<block type="test_dropdowns_images"></block>
|
||||
<block type="test_dropdowns_images_and_text"></block>
|
||||
</category>
|
||||
<category name="Images">
|
||||
<block type="test_images_datauri"></block>
|
||||
<block type="test_images_small"></block>
|
||||
<block type="test_images_large"></block>
|
||||
<block type="test_images_fliprtl"></block>
|
||||
<block type="test_images_missing"></block>
|
||||
<block type="test_images_many_icons"></block>
|
||||
</category>
|
||||
<category name="Emoji! o((*>ᴗ<*))o">
|
||||
<label text="Unicode & Emojis"></label>
|
||||
<block type="test_style_emoji"></block>
|
||||
<block type="text">
|
||||
<field name="TEXT">Robot face in text field: 🤖</field>
|
||||
</block>
|
||||
<block type="text">
|
||||
<field name="TEXT">Zalgo in text field: B̛̻̦̬̘̰͎̥̈̔͊͞ͅl̡͖̫̺̬̖̣̳̃̀́͑͑̕͟͠͝o̢̹͙̮̫͔͋̉̊̑̿̽̚c̸̹̹̜͙̹̠͋̒͑̊̇͝k̡͉̫͇̖̳͖̊͒́̆̄̎̂̔̕͜͞l̰̙̞̳̩̠͖̯̀̆̈́̿̈̓͗y̨̡̟͇̮͈̬̙̲̏̅̀͘͠</field>
|
||||
</block>
|
||||
</category>
|
||||
</category>
|
||||
<category name="Mutators">
|
||||
<label text="logic_compare"></label>
|
||||
@@ -1266,22 +1288,6 @@ h1 {
|
||||
<block type="test_style_hex4"></block>
|
||||
<block type="test_style_hex5"></block>
|
||||
</category>
|
||||
<category name="Images">
|
||||
<block type="test_images_datauri"></block>
|
||||
<block type="test_images_small"></block>
|
||||
<block type="test_images_large"></block>
|
||||
<block type="test_images_fliprtl"></block>
|
||||
<block type="test_images_missing"></block>
|
||||
<block type="test_images_many_icons"></block>
|
||||
<label text="Unicode & Emojis"></label>
|
||||
<block type="test_style_emoji"></block>
|
||||
<block type="text">
|
||||
<field name="TEXT">Robot face in text field: 🤖</field>
|
||||
</block>
|
||||
<block type="text">
|
||||
<field name="TEXT">Zalgo in text field: B̛̻̦̬̘̰͎̥̈̔͊͞ͅl̡͖̫̺̬̖̣̳̃̀́͑͑̕͟͠͝o̢̹͙̮̫͔͋̉̊̑̿̽̚c̸̹̹̜͙̹̠͋̒͑̊̇͝k̡͉̫͇̖̳͖̊͒́̆̄̎̂̔̕͜͞l̰̙̞̳̩̠͖̯̀̆̈́̿̈̓͗y̨̡̟͇̮͈̬̙̲̏̅̀͘͠</field>
|
||||
</block>
|
||||
</category>
|
||||
</xml>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user