diff --git a/ATOMS.md b/ATOMS.md index fb5f4f66c..a7baeffee 100644 --- a/ATOMS.md +++ b/ATOMS.md @@ -4,7 +4,7 @@ Atoms are effectively read-only inline cards. ## Atom format -An atom is a javascript object with 3 *required* properties: +An atom is a JavaScript object with 3 *required* properties: * `name` [string] - The name of this atom in the mobiledoc * `type` [string] - The output of this atom. Valid values are 'dom', 'html', and 'text' diff --git a/README.md b/README.md index bc6d627a3..66457bc45 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ editor.render(element); * `spellcheck` - [boolean] whether to enable spellcheck. Defaults to true. * `autofocus` - [boolean] When true, focuses on the editor when it is rendered. * `cards` - [array] The list of cards that the editor may render -* `cardOptions` - [object] Options passed to +* `cardOptions` - [object] Options passed to cards and atoms * `unknownCardHandler` - [function] This will be invoked by the editor-renderer whenever it encounters an unknown card ### Editor API @@ -141,9 +141,7 @@ editor.run(postEditor => { const mention = postEditor.builder.createAtom("mention", "John Doe", { id: 42 }); // insert at current cursor position: // or should the user have to grab the current position from the editor first? - postEditor.insert(mention); - // or specify a different position: - postEditor.insert(mention, position); + postEditor.insertMarkers(editor.range.head, [mention]); }); ``` diff --git a/src/js/models/atom-node.js b/src/js/models/atom-node.js index 265cc5147..bc7b4602e 100644 --- a/src/js/models/atom-node.js +++ b/src/js/models/atom-node.js @@ -50,11 +50,11 @@ export default class AtomNode { let { atom: { name } } = this; assert( - `Atom "${name}" must render dom (render value was: "${rendered}")`, + `Atom "${name}" must return a DOM node (returned value was: "${rendered}")`, !!rendered.nodeType ); this.element.appendChild(rendered); this._rendered = rendered; } -} \ No newline at end of file +} diff --git a/tests/helpers/assertions.js b/tests/helpers/assertions.js index 6fc2c7bb1..6d0aebc62 100644 --- a/tests/helpers/assertions.js +++ b/tests/helpers/assertions.js @@ -14,6 +14,23 @@ import { ATOM_TYPE } from 'mobiledoc-kit/models/types'; +/*jshint latedef: false */ +function compareMarkers(actual, expected, assert, path, deepCompare) { + if (actual.value !== expected.value) { + assert.equal(actual.value, expected.value, `wrong value at ${path}`); + } + if (actual.markups.length !== expected.markups.length) { + assert.equal(actual.markups.length, expected.markups.length, + `wrong markups at ${path}`); + } + if (deepCompare) { + actual.markups.forEach((markup, index) => { + comparePostNode(markup, expected.markups[index], + assert, `${path}:${index}`, deepCompare); + }); + } +} + function comparePostNode(actual, expected, assert, path='root', deepCompare=false) { if (!actual || !expected) { assert.ok(!!actual, `missing actual post node at ${path}`); @@ -38,20 +55,13 @@ function comparePostNode(actual, expected, assert, path='root', deepCompare=fals } break; case ATOM_TYPE: - case MARKER_TYPE: - if (actual.value !== expected.value) { - assert.equal(actual.value, expected.value, `wrong value at ${path}`); - } - if (actual.markups.length !== expected.markups.length) { - assert.equal(actual.markups.length, expected.markups.length, - `wrong markups at ${path}`); - } - if (deepCompare) { - actual.markups.forEach((markup, index) => { - comparePostNode(markup, expected.markups[index], - assert, `${path}:${index}`, deepCompare); - }); + if (actual.name !== expected.name) { + assert.equal(actual.name, expected.name, `wrong atom name at ${path}`); } + compareMarkers(actual, expected, assert, path, deepCompare); + break; + case MARKER_TYPE: + compareMarkers(actual, expected, assert, path, deepCompare); break; case MARKUP_SECTION_TYPE: case LIST_ITEM_TYPE: diff --git a/tests/unit/editor/atom-lifecycle-test.js b/tests/unit/editor/atom-lifecycle-test.js index 53f5a2fb9..bb694c9a4 100644 --- a/tests/unit/editor/atom-lifecycle-test.js +++ b/tests/unit/editor/atom-lifecycle-test.js @@ -113,7 +113,7 @@ test('returning wrong type from render throws', (assert) => { assert.throws(() => { editor.render(editorElement); - }, new RegExp(`Atom "${atomName}" must render dom`)); + }, new RegExp(`Atom "${atomName}" must return a DOM node`)); }); test('returning undefined from render is ok', (assert) => { diff --git a/tests/unit/editor/post-test.js b/tests/unit/editor/post-test.js index c388ca259..b457e7237 100644 --- a/tests/unit/editor/post-test.js +++ b/tests/unit/editor/post-test.js @@ -44,7 +44,8 @@ let renderedRange; function buildEditorWithMobiledoc(builderFn) { let mobiledoc = Helpers.mobiledoc.build(builderFn); let unknownCardHandler = () => {}; - editor = new Editor({mobiledoc, unknownCardHandler}); + let unknownAtomHandler = () => {}; + editor = new Editor({mobiledoc, unknownCardHandler, unknownAtomHandler}); editor.render(editorElement); editor.renderRange = function() { renderedRange = this.range; @@ -1592,6 +1593,36 @@ test('#toggleMarkup when the editor has no cursor', (assert) => { assert.ok(renderedRange.isBlank, 'rendered range is blank'); }); +test('#insertMarkers inserts an atom', (assert) => { + let toInsert, expected; + Helpers.postAbstract.build(({post, markupSection, marker, markup, atom}) => { + toInsert = [ + atom('simple-atom', '123', [markup('b')]) + ]; + expected = post([ + markupSection('p', [ + marker('abc'), + atom('simple-atom', '123', [markup('b')]), + marker('def') + ])]); + }); + + editor = buildEditorWithMobiledoc(({post, markupSection, marker}) => { + return post([markupSection('p', [marker('abcdef')])]); + }); + let position = new Position(editor.post.sections.head, 'abc'.length); + postEditor = new PostEditor(editor); + postEditor.insertMarkers(position, toInsert); + postEditor.complete(); + + assert.postIsSimilar(editor.post, expected); + assert.renderTreeIsEqual(editor._renderTree, expected); + assert.positionIsEqual( + renderedRange.head, + new Position(editor.post.sections.head, 4) + ); +}); + test('#insertMarkers inserts the markers in middle, merging markups', (assert) => { let toInsert, expected; Helpers.postAbstract.build(({post, markupSection, marker, markup}) => {