feat: add serialization and deserialization of comments (#5216)

* Add tests for (de)seralizing icons

* Add logic for (de)serializing icons

* fix: add docs for saveIcons

* fix: add timeout for setting comment visible
This commit is contained in:
Beka Westberg
2021-08-18 13:51:34 +00:00
committed by alschmiedt
parent 91922aa571
commit 1b47953c58
4 changed files with 109 additions and 4 deletions

View File

@@ -20,6 +20,7 @@ const Connection = goog.requireType('Blockly.Connection');
const Events = goog.require('Blockly.Events');
const {MissingBlockType, MissingConnection, BadConnectionCheck} =
goog.require('Blockly.serialization.exceptions');
const Size = goog.require('Blockly.utils.Size');
// eslint-disable-next-line no-unused-vars
const Workspace = goog.requireType('Blockly.Workspace');
const Xml = goog.require('Blockly.Xml');
@@ -54,6 +55,7 @@ exports.ConnectionState = ConnectionState;
* inline: (boolean|undefined),
* data: (string|undefined),
* extra-state: *,
* icons: (!Object<string, *>|undefined),
* fields: (!Object<string, *>|undefined),
* inputs: (!Object<string, !ConnectionState>|undefined),
* next: (!ConnectionState|undefined)
@@ -99,6 +101,7 @@ const save = function(
}
saveAttributes(block, state);
saveExtraState(block, state);
saveIcons(block, state);
saveFields(block, state);
if (addInputBlocks) {
saveInputBlocks(block, state);
@@ -171,6 +174,25 @@ const saveExtraState = function(block, state) {
}
};
/**
* Adds the state of all of the icons on the block to the given state object.
* @param {!Block} block The block to serialize the icon state of.
* @param {!State} state The state object to append to.
*/
const saveIcons = function(block, state) {
// TODO(#2105): Remove this logic and put it in the icon.
if (block.getCommentText()) {
state['icons'] = {
'comment': {
'text': block.getCommentText(),
'pinned': block.commentModel.pinned,
'height': Math.round(block.commentModel.size.height),
'width': Math.round(block.commentModel.size.width),
}
};
}
};
/**
* Adds the state of all of the fields on the block to the given state object.
* @param {!Block} block The block to serialize the field state of.
@@ -178,7 +200,7 @@ const saveExtraState = function(block, state) {
*/
const saveFields = function(block, state) {
let hasFieldState = false;
let fields = Object.create(null);
const fields = Object.create(null);
for (let i = 0; i < block.inputList.length; i++) {
const input = block.inputList[i];
for (let j = 0; j < input.fieldRow.length; j++) {
@@ -322,7 +344,7 @@ const loadInternal = function(state, workspace, parentConnection = undefined) {
loadAttributes(block, state);
loadExtraState(block, state);
tryToConnectParent(parentConnection, block, state);
// loadIcons(block, state);
loadIcons(block, state);
loadFields(block, state);
loadInputBlocks(block, state);
loadNextBlocks(block, state);
@@ -427,6 +449,29 @@ const tryToConnectParent = function(parentConnection, child, state) {
}
};
/**
* Applies icon state to the icons on the block, based on the given state
* object.
* @param {!Block} block The block to set the icon state of.
* @param {!State} state The state object to reference.
*/
const loadIcons = function(block, state) {
if (!state['icons']) {
return;
}
// TODO(#2105): Remove this logic and put it in the icon.
const comment = state['icons']['comment'];
if (comment) {
block.setCommentText(comment['text']);
block.commentModel.pinned = comment['pinned'];
block.commentModel.size = new Size(comment['width'], comment['height']);
if (comment['pinned'] && block.getCommentIcon && !block.isInFlyout) {
// Give the block a chance to be positioned and rendered before showing.
setTimeout(() => block.getCommentIcon().setVisible(true), 1);
}
}
};
/**
* Applies any field information available on the state object to the block.
* @param {!Block} block The block to set the field state of.

View File

@@ -196,7 +196,7 @@ goog.addDependency('../../core/renderers/zelos/renderer.js', ['Blockly.zelos.Ren
goog.addDependency('../../core/requires.js', ['Blockly.requires'], ['Blockly', 'Blockly.Comment', 'Blockly.ContextMenuItems', 'Blockly.FieldAngle', 'Blockly.FieldCheckbox', 'Blockly.FieldColour', 'Blockly.FieldDropdown', 'Blockly.FieldImage', 'Blockly.FieldLabelSerializable', 'Blockly.FieldMultilineInput', 'Blockly.FieldNumber', 'Blockly.FieldTextInput', 'Blockly.FieldVariable', 'Blockly.FlyoutButton', 'Blockly.Generator', 'Blockly.HorizontalFlyout', 'Blockly.Mutator', 'Blockly.ShortcutItems', 'Blockly.Themes.Classic', 'Blockly.Toolbox', 'Blockly.Trashcan', 'Blockly.VariablesDynamic', 'Blockly.VerticalFlyout', 'Blockly.Warning', 'Blockly.ZoomControls', 'Blockly.geras.Renderer', 'Blockly.serialization.workspaces', 'Blockly.thrasos.Renderer', 'Blockly.zelos.Renderer']);
goog.addDependency('../../core/scrollbar.js', ['Blockly.Scrollbar'], ['Blockly.Touch', 'Blockly.browserEvents', 'Blockly.utils', 'Blockly.utils.Coordinate', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/scrollbar_pair.js', ['Blockly.ScrollbarPair'], ['Blockly.Events', 'Blockly.Scrollbar', 'Blockly.utils.Svg', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/serialization/blocks.js', ['Blockly.serialization.blocks'], ['Blockly.Events', 'Blockly.Xml', 'Blockly.inputTypes', 'Blockly.serialization.exceptions'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/serialization/blocks.js', ['Blockly.serialization.blocks'], ['Blockly.Events', 'Blockly.Xml', 'Blockly.inputTypes', 'Blockly.serialization.exceptions', 'Blockly.utils.Size'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/serialization/exceptions.js', ['Blockly.serialization.exceptions'], [], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/serialization/variables.js', ['Blockly.serialization.variables'], ['Blockly.Events'], {'lang': 'es6', 'module': 'goog'});
goog.addDependency('../../core/serialization/workspaces.js', ['Blockly.serialization.workspaces'], ['Blockly.Events', 'Blockly.Workspace', 'Blockly.serialization.blocks', 'Blockly.serialization.variables', 'Blockly.utils.dom'], {'lang': 'es6', 'module': 'goog'});

View File

@@ -274,6 +274,67 @@ suite('JSO Serialization', function() {
});
});
suite('Icons', function() {
suite('Comment', function() {
test('Basic', function() {
const block = this.workspace.newBlock('row_block');
block.setCommentText('test');
const jso = Blockly.serialization.blocks.save(block);
assertProperty(
jso,
'icons',
{
'comment': {
'text': 'test',
'pinned': false,
'height': 80,
'width': 160,
}
},
);
});
test('Pinned', function() {
const block = this.workspace.newBlock('row_block');
block.setCommentText('test');
block.commentModel.pinned = true;
const jso = Blockly.serialization.blocks.save(block);
assertProperty(
jso,
'icons',
{
'comment': {
'text': 'test',
'pinned': true,
'height': 80,
'width': 160,
}
},
);
});
test('Size', function() {
const block = this.workspace.newBlock('row_block');
block.setCommentText('test');
block.commentModel.size.height = 40;
block.commentModel.size.width = 320;
const jso = Blockly.serialization.blocks.save(block);
assertProperty(
jso,
'icons',
{
'comment': {
'text': 'test',
'pinned': false,
'height': 40,
'width': 320,
}
},
);
});
});
});
suite('Fields', function() {
class StringStateField extends Blockly.Field {
constructor(value, validator = undefined, config = undefined) {

View File

@@ -1834,5 +1834,4 @@ var runSerializerTestSuite = (serializer, deserializer, testSuite) => {
};
runSerializerTestSuite(null, null, Serializer);
Serializer.Icons.skip = true;
runSerializerTestSuite(state => state, state => state, Serializer);