diff --git a/src/models/state.js b/src/models/state.js index 25153226d..6533f17af 100644 --- a/src/models/state.js +++ b/src/models/state.js @@ -51,7 +51,10 @@ class State extends new Record(DEFAULTS) { selection = selection.collapseToStartOf(text) } - return new State({ document, selection }) + const state = new State({ document, selection }) + return state.transform() + .normalize() + .apply({ save: false }) } /** diff --git a/src/models/text.js b/src/models/text.js index ae9592a15..b344c782e 100644 --- a/src/models/text.js +++ b/src/models/text.js @@ -44,6 +44,24 @@ class Text extends new Record(DEFAULTS) { return new Text(properties) } + /** + * Create a new `Text` from a string + * + * @param {String} content + * @return {Text} + */ + + static createFromString(content) { + return Text.create({ + characters: Character.createList( + content.split('') + .map(c => { + return { text: c } + }) + ) + }) + } + /** * Create a list of `Texts` from an array. * diff --git a/src/plugins/schema.js b/src/plugins/schema.js index 78bba43e2..c0a138011 100644 --- a/src/plugins/schema.js +++ b/src/plugins/schema.js @@ -61,7 +61,7 @@ const MIN_TEXT_RULE = { return nodes.size === 0 ? true : null }, normalize: (transform, node) => { - return transform.insertTextByKey(node.key, 0, '') + return transform.insertNodeByKey(node.key, 0, Text.create()) } } @@ -86,12 +86,34 @@ const INLINE_CHILDREN_RULE = { } /** - * A default schema rule to ensure that inline void nodes are surrounded with text nodes + * A default schema rule to ensure that void nodes contain a single space of content. * * @type {Object} */ const INLINE_VOID_TEXT_RULE = { + match: (object) => { + return (object.kind == 'inline' || object.kind == 'block') && object.isVoid + }, + validate: (node) => { + return node.text !== ' ' || node.nodes.size !== 1 + }, + normalize: (transform, node) => { + transform = node.nodes.reduce((t, child) => { + return t.removeNodeByKey(child.key) + }, transform) + + return transform.insertNodeByKey(node.key, 0, Text.createFromString(' ')) + } +} + +/** + * A default schema rule to ensure that inline void nodes are surrounded with text nodes + * + * @type {Object} + */ + +const INLINE_VOID_TEXTS_AROUND_RULE = { match: (object) => { return object.kind == 'block' }, @@ -174,6 +196,7 @@ const schema = Schema.create({ MIN_TEXT_RULE, INLINE_CHILDREN_RULE, INLINE_VOID_TEXT_RULE, + INLINE_VOID_TEXTS_AROUND_RULE, NO_ADJACENT_TEXT_RULE ] })