diff --git a/MOBILEDOC.md b/MOBILEDOC.md index cde0cc08c..479dec7bb 100644 --- a/MOBILEDOC.md +++ b/MOBILEDOC.md @@ -36,7 +36,7 @@ The wrapper signature: ``` { - version: "0.3.0", ──── Versioning information + version: "0.3.1", ──── Versioning information markups: [ ──── Ordered list of markup types markup, markup @@ -63,7 +63,7 @@ Markups have a tagName and an optional array of attributes. Not all markups can ``` { - version: "0.3.0", + version: "0.3.1", markups: [ [tagName, optionalAttributesArray], ──── Markup ["em"], ──── Example simple markup with no attributes @@ -78,7 +78,7 @@ Atoms have a name, text value and arbitrary payload. ``` { - version: "0.3.0", + version: "0.3.1", atoms: [ [atomName, atomText, atomPayload], ──── Atom ['mention', '@bob', { id: 42 }] ──── Example 'mention' atom @@ -92,7 +92,7 @@ Cards have a name and arbitrary payload. ``` { - version: "0.3.0", + version: "0.3.1", cards: [ [cardName, cardPayload], ──── Card ['image', { ──── Example 'image' card @@ -108,7 +108,7 @@ Markup sections, in addition to plain text, can include markups and atoms. ``` { - version: "0.3.0", + version: "0.3.1", markups: [ ["b"], ──── Markup at index 0 ["i"] ──── Markup at index 1 @@ -140,6 +140,18 @@ Markup sections, in addition to plain text, can include markups and atoms. } ``` +A section `tagName` must be one of: + +* `aside` +* `blockquote` +* `h1` +* `h2` +* `h3` +* `h4` +* `h5` +* `h6` +* `p` + The index in `openMarkupsIndex` specifies which markups should be opened at the start of the `value` text. As these tags are opened, then create a stack of opened markups. The `numberOfClosedMarkups` says how many of those opened markup tags should @@ -149,6 +161,19 @@ In addition to markers, markup sections may contain [ATOMS](ATOMS.md). Atoms in a markup section have a `textTypeIdentifier` of 1 and contain an `atomTypeIndex`. They also contain the same `openMarkupsIndex` and `numberOfClosedMarkups` values that other markers have, so that markup can flow across them. +A markup definition array's first item (the markup `tagName`) must be one of: + +* `a` - Hypertext link +* `b` - Bold +* `code` - Code +* `em` - Emphasis +* `i` - Italic +* `s` - Strike-through +* `strong` - Strong +* `sub` - Subscript +* `sup` - Superscript +* `u` - Underline + If an atom is present in Mobiledoc but no atom implementation is registered, the text value of the atom will be rendered as plain text as a fallback. @@ -156,7 +181,7 @@ value of the atom will be rendered as plain text as a fallback. ``` { - version: "0.3.0", + version: "0.3.1", cards: [ ["card-name", { cardPayload }] ], diff --git a/README.md b/README.md index de7bc0c27..183341b2f 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ optionally a Mobiledoc to load. For example: ```js var simpleMobiledoc = { - version: "0.3.0", + version: "0.3.1", markups: [], atoms: [], cards: [], @@ -117,7 +117,7 @@ document's ``: ### Editor API -* `editor.serialize(version="0.3.0")` - serialize the current post for persistence. Returns +* `editor.serialize(version="0.3.1")` - serialize the current post for persistence. Returns Mobiledoc. * `editor.destroy()` - teardown the editor event listeners, free memory etc. * `editor.disableEditing()` - stop the user from being able to edit the diff --git a/assets/demo/vendor/mobiledoc-pretty-json-renderer.js b/assets/demo/vendor/mobiledoc-pretty-json-renderer.js index b46771267..2e797f83d 100644 --- a/assets/demo/vendor/mobiledoc-pretty-json-renderer.js +++ b/assets/demo/vendor/mobiledoc-pretty-json-renderer.js @@ -52,7 +52,7 @@ var mobiledocPrettyJSONRenderer = if (doc == null || typeof doc === 'string') { return JSON.stringify(doc); } - if (doc.version !== '0.3.0') { + if (doc.version && doc.version.indexOf('0.3') === 0) { return JSON.stringify(doc, null, 2); } var lists = [ @@ -208,4 +208,4 @@ var mobiledocPrettyJSONRenderer = /***/ } -/******/ ]); \ No newline at end of file +/******/ ]); diff --git a/package.json b/package.json index 36ee7683b..8b379193d 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "repository": "https://github.com/bustlelabs/mobiledoc-kit", "scripts": { "start": "broccoli serve --host 0.0.0.0", - "test:ci": "npm run build:docs && npm run build && testem ci -f testem-ci.json", + "test:ci": "PATH=node_modules/phantomjs-prebuilt/bin/:$PATH npm run build:docs && npm run build && testem ci -f testem-ci.json", "test": "PATH=node_modules/phantomjs-prebuilt/bin/:$PATH npm run build:docs && npm run build && testem ci -f testem.json", "build": "rm -rf dist && broccoli build dist", "build:docs": "jsdoc -c ./.jsdoc", @@ -37,13 +37,13 @@ ], "license": "MIT", "dependencies": { - "mobiledoc-html-renderer": "^0.3.0", - "mobiledoc-text-renderer": "^0.3.0" + "mobiledoc-html-renderer": "0.3.1", + "mobiledoc-text-renderer": "0.3.1" }, "devDependencies": { "broccoli": "^0.16.9", - "broccoli-cli": "^1.0.0", "broccoli-babel-transpiler": "^5.6.1", + "broccoli-cli": "^1.0.0", "broccoli-funnel": "^1.0.1", "broccoli-inject-livereload": "^0.2.0", "broccoli-less-single": "^0.6.2", diff --git a/src/js/editor/text-input-handlers.js b/src/js/editor/text-input-handlers.js index 6cc19add5..ccf6dedbb 100644 --- a/src/js/editor/text-input-handlers.js +++ b/src/js/editor/text-input-handlers.js @@ -33,7 +33,7 @@ export function replaceWithListSection(editor, listTagName) { * Does nothing if the cursor position is not at the start of the section. * * @param {Editor} editor - * @param {String} headingTagName ("h1","h2","h3") + * @param {String} headingTagName ('h1', 'h2', 'h3', 'h4', 'h5', 'h6') * @public */ export function replaceWithHeaderSection(editor, headingTagName) { @@ -70,8 +70,15 @@ export const DEFAULT_TEXT_INPUT_HANDLERS = [ }, { name: 'heading', - // "# " -> h1, "## " -> h2, "### " -> h3 - match: /^(#{1,3}) $/, + /* + * "# " -> h1 + * "## " -> h2 + * "### " -> h3 + * "#### " -> h4 + * "##### " -> h5 + * "###### " -> h6 + */ + match: /^(#{1,6}) $/, run(editor, matches) { let capture = matches[1]; let headingTag = 'h' + capture.length; diff --git a/src/js/models/markup-section.js b/src/js/models/markup-section.js index e7799324b..ad6b21c75 100644 --- a/src/js/models/markup-section.js +++ b/src/js/models/markup-section.js @@ -5,16 +5,32 @@ import { MARKUP_SECTION_TYPE } from './types'; // valid values of `tagName` for a MarkupSection export const VALID_MARKUP_SECTION_TAGNAMES = [ - 'p', 'h3', 'h2', 'h1', 'blockquote', 'pull-quote' + 'aside', + 'blockquote', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'p' ].map(normalizeTagName); // valid element names for a MarkupSection. A MarkupSection with a tagName // not in this will be rendered as a div with a className matching the // tagName export const MARKUP_SECTION_ELEMENT_NAMES = [ - 'p', 'h3', 'h2', 'h1', 'blockquote' + 'aside', + 'blockquote', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'p' ].map(normalizeTagName); -export const DEFAULT_TAG_NAME = VALID_MARKUP_SECTION_TAGNAMES[0]; +export const DEFAULT_TAG_NAME = VALID_MARKUP_SECTION_TAGNAMES[8]; const MarkupSection = class MarkupSection extends Markerable { constructor(tagName=DEFAULT_TAG_NAME, markers=[]) { diff --git a/src/js/models/markup.js b/src/js/models/markup.js index a7e9a8a89..c8a5091c0 100644 --- a/src/js/models/markup.js +++ b/src/js/models/markup.js @@ -4,15 +4,16 @@ import { MARKUP_TYPE } from './types'; import assert from '../utils/assert'; export const VALID_MARKUP_TAGNAMES = [ + 'a', 'b', + 'code', + 'em', 'i', + 's', // strikethrough 'strong', - 'em', - 'a', - 'u', 'sub', // subscript 'sup', // superscript - 's' // strikethrough + 'u' ].map(normalizeTagName); export const VALID_ATTRIBUTES = [ diff --git a/src/js/parsers/mobiledoc/0-2.js b/src/js/parsers/mobiledoc/0-2.js index cc375849d..5314fb284 100644 --- a/src/js/parsers/mobiledoc/0-2.js +++ b/src/js/parsers/mobiledoc/0-2.js @@ -80,7 +80,7 @@ export default class MobiledocParser { } parseMarkupSection([type, tagName, markers], post) { - const section = this.builder.createMarkupSection(tagName); + const section = this.builder.createMarkupSection(tagName.toLowerCase() === 'pull-quote' ? 'aside' : tagName); post.sections.append(section); this.parseMarkers(markers, section); // Strip blank markers after they have been created. This ensures any diff --git a/src/js/parsers/mobiledoc/0-3-1.js b/src/js/parsers/mobiledoc/0-3-1.js new file mode 100644 index 000000000..324056da2 --- /dev/null +++ b/src/js/parsers/mobiledoc/0-3-1.js @@ -0,0 +1,165 @@ +import { + MOBILEDOC_MARKUP_SECTION_TYPE, + MOBILEDOC_IMAGE_SECTION_TYPE, + MOBILEDOC_LIST_SECTION_TYPE, + MOBILEDOC_CARD_SECTION_TYPE, + MOBILEDOC_MARKUP_MARKER_TYPE, + MOBILEDOC_ATOM_MARKER_TYPE +} from 'mobiledoc-kit/renderers/mobiledoc/0-3-1'; +import { kvArrayToObject, filter } from "../../utils/array-utils"; +import assert from 'mobiledoc-kit/utils/assert'; + +/* + * Parses from mobiledoc -> post + */ +export default class MobiledocParser { + constructor(builder) { + this.builder = builder; + } + + /** + * @param {Mobiledoc} + * @return {Post} + */ + parse({ version, sections, markups: markerTypes, cards: cardTypes, atoms: atomTypes }) { + try { + const post = this.builder.createPost(); + + this.markups = []; + this.markerTypes = this.parseMarkerTypes(markerTypes); + this.cardTypes = this.parseCardTypes(cardTypes); + this.atomTypes = this.parseAtomTypes(atomTypes); + this.parseSections(sections, post); + + return post; + } catch (e) { + assert(`Unable to parse mobiledoc: ${e.message}`, false); + } + } + + parseMarkerTypes(markerTypes) { + return markerTypes.map((markerType) => this.parseMarkerType(markerType)); + } + + parseMarkerType([tagName, attributesArray]) { + const attributesObject = kvArrayToObject(attributesArray || []); + return this.builder.createMarkup(tagName, attributesObject); + } + + parseCardTypes(cardTypes) { + return cardTypes.map((cardType) => this.parseCardType(cardType)); + } + + parseCardType([cardName, cardPayload]) { + return [cardName, cardPayload]; + } + + parseAtomTypes(atomTypes) { + return atomTypes.map((atomType) => this.parseAtomType(atomType)); + } + + parseAtomType([atomName, atomValue, atomPayload]) { + return [atomName, atomValue, atomPayload]; + } + + parseSections(sections, post) { + sections.forEach((section) => this.parseSection(section, post)); + } + + parseSection(section, post) { + let [type] = section; + switch(type) { + case MOBILEDOC_MARKUP_SECTION_TYPE: + this.parseMarkupSection(section, post); + break; + case MOBILEDOC_IMAGE_SECTION_TYPE: + this.parseImageSection(section, post); + break; + case MOBILEDOC_CARD_SECTION_TYPE: + this.parseCardSection(section, post); + break; + case MOBILEDOC_LIST_SECTION_TYPE: + this.parseListSection(section, post); + break; + default: + assert('Unexpected section type ${type}', false); + } + } + + getAtomTypeFromIndex(index) { + const atomType = this.atomTypes[index]; + assert(`No atom definition found at index ${index}`, !!atomType); + return atomType; + } + + getCardTypeFromIndex(index) { + const cardType = this.cardTypes[index]; + assert(`No card definition found at index ${index}`, !!cardType); + return cardType; + } + + parseCardSection([type, cardIndex], post) { + const [name, payload] = this.getCardTypeFromIndex(cardIndex); + const section = this.builder.createCardSection(name, payload); + post.sections.append(section); + } + + parseImageSection([type, src], post) { + const section = this.builder.createImageSection(src); + post.sections.append(section); + } + + parseMarkupSection([type, tagName, markers], post) { + const section = this.builder.createMarkupSection(tagName); + post.sections.append(section); + this.parseMarkers(markers, section); + // Strip blank markers after they have been created. This ensures any + // markup they include has been correctly populated. + filter(section.markers, m => m.isBlank).forEach(m => { + section.markers.remove(m); + }); + } + + parseListSection([type, tagName, items], post) { + const section = this.builder.createListSection(tagName); + post.sections.append(section); + this.parseListItems(items, section); + } + + parseListItems(items, section) { + items.forEach(i => this.parseListItem(i, section)); + } + + parseListItem(markers, section) { + const item = this.builder.createListItem(); + this.parseMarkers(markers, item); + section.items.append(item); + } + + parseMarkers(markers, parent) { + markers.forEach(m => this.parseMarker(m, parent)); + } + + parseMarker([type, markerTypeIndexes, closeCount, value], parent) { + markerTypeIndexes.forEach(index => { + this.markups.push(this.markerTypes[index]); + }); + + const marker = this.buildMarkerType(type, value); + parent.markers.append(marker); + + this.markups = this.markups.slice(0, this.markups.length-closeCount); + } + + buildMarkerType(type, value) { + switch (type) { + case MOBILEDOC_MARKUP_MARKER_TYPE: + return this.builder.createMarker(value, this.markups.slice()); + case MOBILEDOC_ATOM_MARKER_TYPE: + const [atomName, atomValue, atomPayload] = this.getAtomTypeFromIndex(value); + return this.builder.createAtom(atomName, atomValue, atomPayload, this.markups.slice()); + default: + assert(`Unexpected marker type ${type}`, false); + } + } +} diff --git a/src/js/parsers/mobiledoc/0-3.js b/src/js/parsers/mobiledoc/0-3.js index b5db376e4..00b22ebf9 100644 --- a/src/js/parsers/mobiledoc/0-3.js +++ b/src/js/parsers/mobiledoc/0-3.js @@ -110,7 +110,7 @@ export default class MobiledocParser { } parseMarkupSection([type, tagName, markers], post) { - const section = this.builder.createMarkupSection(tagName); + const section = this.builder.createMarkupSection(tagName.toLowerCase() === 'pull-quote' ? 'aside' : tagName); post.sections.append(section); this.parseMarkers(markers, section); // Strip blank markers after they have been created. This ensures any diff --git a/src/js/parsers/mobiledoc/index.js b/src/js/parsers/mobiledoc/index.js index d14cee904..5c5b3b7f4 100644 --- a/src/js/parsers/mobiledoc/index.js +++ b/src/js/parsers/mobiledoc/index.js @@ -1,8 +1,10 @@ import MobiledocParser_0_2 from './0-2'; import MobiledocParser_0_3 from './0-3'; +import MobiledocParser_0_3_1 from './0-3-1'; import { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_2 } from 'mobiledoc-kit/renderers/mobiledoc/0-2'; import { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_3 } from 'mobiledoc-kit/renderers/mobiledoc/0-3'; +import { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_3_1 } from 'mobiledoc-kit/renderers/mobiledoc/0-3-1'; import assert from 'mobiledoc-kit/utils/assert'; function parseVersion(mobiledoc) { @@ -17,6 +19,8 @@ export default { return new MobiledocParser_0_2(builder).parse(mobiledoc); case MOBILEDOC_VERSION_0_3: return new MobiledocParser_0_3(builder).parse(mobiledoc); + case MOBILEDOC_VERSION_0_3_1: + return new MobiledocParser_0_3_1(builder).parse(mobiledoc); default: assert(`Unknown version of mobiledoc parser requested: ${version}`, false); diff --git a/src/js/renderers/mobiledoc/0-3-1.js b/src/js/renderers/mobiledoc/0-3-1.js new file mode 100644 index 000000000..74c109ff4 --- /dev/null +++ b/src/js/renderers/mobiledoc/0-3-1.js @@ -0,0 +1,159 @@ +import {visit, visitArray, compile} from '../../utils/compiler'; +import { objectToSortedKVArray } from '../../utils/array-utils'; +import { + POST_TYPE, + MARKUP_SECTION_TYPE, + LIST_SECTION_TYPE, + LIST_ITEM_TYPE, + MARKER_TYPE, + MARKUP_TYPE, + IMAGE_SECTION_TYPE, + CARD_TYPE, + ATOM_TYPE +} from '../../models/types'; + +export const MOBILEDOC_VERSION = '0.3.1'; +export const MOBILEDOC_MARKUP_SECTION_TYPE = 1; +export const MOBILEDOC_IMAGE_SECTION_TYPE = 2; +export const MOBILEDOC_LIST_SECTION_TYPE = 3; +export const MOBILEDOC_CARD_SECTION_TYPE = 10; + +export const MOBILEDOC_MARKUP_MARKER_TYPE = 0; +export const MOBILEDOC_ATOM_MARKER_TYPE = 1; + +const visitor = { + [POST_TYPE](node, opcodes) { + opcodes.push(['openPost']); + visitArray(visitor, node.sections, opcodes); + }, + [MARKUP_SECTION_TYPE](node, opcodes) { + opcodes.push(['openMarkupSection', node.tagName]); + visitArray(visitor, node.markers, opcodes); + }, + [LIST_SECTION_TYPE](node, opcodes) { + opcodes.push(['openListSection', node.tagName]); + visitArray(visitor, node.items, opcodes); + }, + [LIST_ITEM_TYPE](node, opcodes) { + opcodes.push(['openListItem']); + visitArray(visitor, node.markers, opcodes); + }, + [IMAGE_SECTION_TYPE](node, opcodes) { + opcodes.push(['openImageSection', node.src]); + }, + [CARD_TYPE](node, opcodes) { + opcodes.push(['openCardSection', node.name, node.payload]); + }, + [MARKER_TYPE](node, opcodes) { + opcodes.push(['openMarker', node.closedMarkups.length, node.value]); + visitArray(visitor, node.openedMarkups, opcodes); + }, + [MARKUP_TYPE](node, opcodes) { + opcodes.push(['openMarkup', node.tagName, objectToSortedKVArray(node.attributes)]); + }, + [ATOM_TYPE](node, opcodes) { + opcodes.push(['openAtom', node.closedMarkups.length, node.name, node.value, node.payload]); + visitArray(visitor, node.openedMarkups, opcodes); + } +}; + +const postOpcodeCompiler = { + openMarker(closeCount, value) { + this.markupMarkerIds = []; + this.markers.push([ + MOBILEDOC_MARKUP_MARKER_TYPE, + this.markupMarkerIds, + closeCount, + value || '' + ]); + }, + openMarkupSection(tagName) { + this.markers = []; + this.sections.push([MOBILEDOC_MARKUP_SECTION_TYPE, tagName, this.markers]); + }, + openListSection(tagName) { + this.items = []; + this.sections.push([MOBILEDOC_LIST_SECTION_TYPE, tagName, this.items]); + }, + openListItem() { + this.markers = []; + this.items.push(this.markers); + }, + openImageSection(url) { + this.sections.push([MOBILEDOC_IMAGE_SECTION_TYPE, url]); + }, + openCardSection(name, payload) { + const index = this._addCardTypeIndex(name, payload); + this.sections.push([MOBILEDOC_CARD_SECTION_TYPE, index]); + }, + openAtom(closeCount, name, value, payload) { + const index = this._addAtomTypeIndex(name, value, payload); + this.markupMarkerIds = []; + this.markers.push([ + MOBILEDOC_ATOM_MARKER_TYPE, + this.markupMarkerIds, + closeCount, + index + ]); + }, + openPost() { + this.atomTypes = []; + this.cardTypes = []; + this.markerTypes = []; + this.sections = []; + this.result = { + version: MOBILEDOC_VERSION, + atoms: this.atomTypes, + cards: this.cardTypes, + markups: this.markerTypes, + sections: this.sections + }; + }, + openMarkup(tagName, attributes) { + const index = this._findOrAddMarkerTypeIndex(tagName, attributes); + this.markupMarkerIds.push(index); + }, + _addCardTypeIndex(cardName, payload) { + let cardType = [cardName, payload]; + this.cardTypes.push(cardType); + return this.cardTypes.length - 1; + }, + _addAtomTypeIndex(atomName, atomValue, payload) { + let atomType = [atomName, atomValue, payload]; + this.atomTypes.push(atomType); + return this.atomTypes.length - 1; + }, + _findOrAddMarkerTypeIndex(tagName, attributesArray) { + if (!this._markerTypeCache) { this._markerTypeCache = {}; } + const key = `${tagName}-${attributesArray.join('-')}`; + + let index = this._markerTypeCache[key]; + if (index === undefined) { + let markerType = [tagName]; + if (attributesArray.length) { markerType.push(attributesArray); } + this.markerTypes.push(markerType); + + index = this.markerTypes.length - 1; + this._markerTypeCache[key] = index; + } + + return index; + } +}; + +/** + * Render from post -> mobiledoc + */ +export default { + /** + * @param {Post} + * @return {Mobiledoc} + */ + render(post) { + let opcodes = []; + visit(visitor, post, opcodes); + let compiler = Object.create(postOpcodeCompiler); + compile(compiler, opcodes); + return compiler.result; + } +}; diff --git a/src/js/renderers/mobiledoc/index.js b/src/js/renderers/mobiledoc/index.js index 3390efa62..e3e8b21e4 100644 --- a/src/js/renderers/mobiledoc/index.js +++ b/src/js/renderers/mobiledoc/index.js @@ -1,18 +1,21 @@ import MobiledocRenderer_0_2, { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_2 } from './0-2'; import MobiledocRenderer_0_3, { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_3 } from './0-3'; +import MobiledocRenderer_0_3_1, { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_3_1 } from './0-3-1'; import assert from 'mobiledoc-kit/utils/assert'; -export const MOBILEDOC_VERSION = MOBILEDOC_VERSION_0_3; +export const MOBILEDOC_VERSION = MOBILEDOC_VERSION_0_3_1; export default { render(post, version) { switch (version) { case MOBILEDOC_VERSION_0_2: return MobiledocRenderer_0_2.render(post); - case undefined: - case null: case MOBILEDOC_VERSION_0_3: return MobiledocRenderer_0_3.render(post); + case undefined: + case null: + case MOBILEDOC_VERSION_0_3_1: + return MobiledocRenderer_0_3_1.render(post); default: assert(`Unknown version of mobiledoc renderer requested: ${version}`, false); } diff --git a/tests/acceptance/basic-editor-test.js b/tests/acceptance/basic-editor-test.js index 74239ff6c..169cffcce 100644 --- a/tests/acceptance/basic-editor-test.js +++ b/tests/acceptance/basic-editor-test.js @@ -149,7 +149,7 @@ test('select-all and type text works ok', (assert) => { assert.selectedText('abc', 'precond - abc is selected'); assert.hasElement('#editor p:contains(abc)', 'precond - renders p'); - + Helpers.dom.insertText(editor, 'X'); assert.hasNoElement('#editor p:contains(abc)', 'replaces existing text'); diff --git a/tests/acceptance/cursor-movement-test.js b/tests/acceptance/cursor-movement-test.js index 1ed7f7ef3..7bfaff09d 100644 --- a/tests/acceptance/cursor-movement-test.js +++ b/tests/acceptance/cursor-movement-test.js @@ -228,8 +228,8 @@ test('left arrow when at the head of an atom moves the cursor left off the atom' marker('cc') ]) ]); - // TODO just make 0.3.0 default - }, '0.3.0'); + // TODO just make 0.3.1 default + }, '0.3.1'); editor = new Editor({mobiledoc, atoms}); editor.render(editorElement); @@ -285,8 +285,8 @@ test('right arrow when at the head of an atom moves the cursor across the atom', marker('cc') ]) ]); - // TODO just make 0.3.0 default - }, '0.3.0'); + // TODO just make 0.3.1 default + }, '0.3.1'); editor = new Editor({mobiledoc, atoms}); editor.render(editorElement); diff --git a/tests/acceptance/editor-atoms-test.js b/tests/acceptance/editor-atoms-test.js index b7d712785..e054886fc 100644 --- a/tests/acceptance/editor-atoms-test.js +++ b/tests/acceptance/editor-atoms-test.js @@ -1,6 +1,6 @@ import { Editor } from 'mobiledoc-kit'; import Helpers from '../test-helpers'; -import { MOBILEDOC_VERSION } from 'mobiledoc-kit/renderers/mobiledoc/0-3'; +import { MOBILEDOC_VERSION } from 'mobiledoc-kit/renderers/mobiledoc/0-3-1'; import Range from 'mobiledoc-kit/utils/cursor/range'; const { test, module } = Helpers; diff --git a/tests/acceptance/editor-input-handlers-test.js b/tests/acceptance/editor-input-handlers-test.js index 72bb35b88..8762232b9 100644 --- a/tests/acceptance/editor-input-handlers-test.js +++ b/tests/acceptance/editor-input-handlers-test.js @@ -42,6 +42,18 @@ const headerTests = [{ text: '###', toInsert: ' ', headerTagName: 'h3' +}, { + text: '####', + toInsert: ' ', + headerTagName: 'h4' +}, { + text: '#####', + toInsert: ' ', + headerTagName: 'h5' +}, { + text: '######', + toInsert: ' ', + headerTagName: 'h6' }]; headerTests.forEach(({text, toInsert, headerTagName}) => { diff --git a/tests/helpers/editor.js b/tests/helpers/editor.js index e1dbc525e..af7c0ff7a 100644 --- a/tests/helpers/editor.js +++ b/tests/helpers/editor.js @@ -1,6 +1,6 @@ import PostAbstractHelpers from './post-abstract'; import Editor from 'mobiledoc-kit/editor/editor'; -import MobiledocRenderer from 'mobiledoc-kit/renderers/mobiledoc/0-3'; +import MobiledocRenderer from 'mobiledoc-kit/renderers/mobiledoc/0-3-1'; function retargetPosition(position, toPost) { let fromPost = position.section.post; diff --git a/tests/helpers/mobiledoc.js b/tests/helpers/mobiledoc.js index 12b7aaf99..016380889 100644 --- a/tests/helpers/mobiledoc.js +++ b/tests/helpers/mobiledoc.js @@ -2,6 +2,7 @@ import PostAbstractHelpers from './post-abstract'; import mobiledocRenderers from 'mobiledoc-kit/renderers/mobiledoc'; import MobiledocRenderer_0_2, { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_2 } from 'mobiledoc-kit/renderers/mobiledoc/0-2'; import MobiledocRenderer_0_3, { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_3 } from 'mobiledoc-kit/renderers/mobiledoc/0-3'; +import MobiledocRenderer_0_3_1, { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_3_1 } from 'mobiledoc-kit/renderers/mobiledoc/0-3-1'; import Editor from 'mobiledoc-kit/editor/editor'; import Range from 'mobiledoc-kit/utils/cursor/range'; import { mergeWithOptions } from 'mobiledoc-kit/utils/merge'; @@ -24,6 +25,8 @@ function build(treeFn, version) { return MobiledocRenderer_0_2.render(post); case MOBILEDOC_VERSION_0_3: return MobiledocRenderer_0_3.render(post); + case MOBILEDOC_VERSION_0_3_1: + return MobiledocRenderer_0_3_1.render(post); case undefined: case null: return mobiledocRenderers.render(post); diff --git a/tests/unit/editor/atom-lifecycle-test.js b/tests/unit/editor/atom-lifecycle-test.js index fce39ffd3..46639c159 100644 --- a/tests/unit/editor/atom-lifecycle-test.js +++ b/tests/unit/editor/atom-lifecycle-test.js @@ -2,7 +2,7 @@ import Helpers from '../../test-helpers'; import { Editor } from 'mobiledoc-kit'; let editorElement, editor; -import { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_3 } from 'mobiledoc-kit/renderers/mobiledoc/0-3'; +import { MOBILEDOC_VERSION as MOBILEDOC_VERSION_0_3_1 } from 'mobiledoc-kit/renderers/mobiledoc/0-3-1'; const { module, test } = Helpers; const { postAbstract: { DEFAULT_ATOM_NAME } } = Helpers; @@ -29,7 +29,7 @@ function makeEl(id, text='@atom') { // Default version is 0.2 for the moment function build(fn) { - return Helpers.mobiledoc.build(fn, MOBILEDOC_VERSION_0_3); + return Helpers.mobiledoc.build(fn, MOBILEDOC_VERSION_0_3_1); } function assertRenderArguments(assert, args, expected) { diff --git a/tests/unit/editor/editor-test.js b/tests/unit/editor/editor-test.js index 642bafdff..a0fdb30d5 100644 --- a/tests/unit/editor/editor-test.js +++ b/tests/unit/editor/editor-test.js @@ -186,6 +186,9 @@ test('#serialize serializes to MOBILEDOC_VERSION by default', (assert) => { let mobiledoc3 = Helpers.mobiledoc.build(({post, markupSection, marker}) => { return post([markupSection('p', [marker('abc')])]); }, '0.3.0'); + let mobiledoc3_1 = Helpers.mobiledoc.build(({post, markupSection, marker}) => { + return post([markupSection('p', [marker('abc')])]); + }, '0.3.1'); editor = Helpers.mobiledoc.renderInto(editorElement, ({post, markupSection, marker}) => { return post([markupSection('p', [marker('abc')])]); @@ -193,7 +196,8 @@ test('#serialize serializes to MOBILEDOC_VERSION by default', (assert) => { assert.deepEqual(editor.serialize('0.2.0'), mobiledoc2, 'serializes 0.2.0'); assert.deepEqual(editor.serialize('0.3.0'), mobiledoc3, 'serializes 0.3.0'); - assert.deepEqual(editor.serialize(), mobiledoc3, 'serializes 0.3.0 by default'); + assert.deepEqual(editor.serialize('0.3.1'), mobiledoc3_1, 'serializes 0.3.1'); + assert.deepEqual(editor.serialize(), mobiledoc3_1, 'serializes 0.3.1 by default'); assert.throws( () => editor.serialize('unknown'), diff --git a/tests/unit/parsers/dom-test.js b/tests/unit/parsers/dom-test.js index 5397d0433..6fa105ea2 100644 --- a/tests/unit/parsers/dom-test.js +++ b/tests/unit/parsers/dom-test.js @@ -277,7 +277,7 @@ test('span with font-weight "bold" maps to strong', (assert) => { assert.ok(marker.hasMarkup('strong'), 'marker is strong'); }); -let recognizedTags = ['h1','h2','h3','blockquote']; +let recognizedTags = ['aside', 'blockquote', 'h1','h2','h3','h4','h5','h6','p']; recognizedTags.forEach(tag => { test(`recognized markup section tags are parsed (${tag})`, (assert) => { let element = buildDOM(`<${tag}>${tag} text`); diff --git a/tests/unit/parsers/mobiledoc/0-2-test.js b/tests/unit/parsers/mobiledoc/0-2-test.js index 05abc364b..ebb89d0d9 100644 --- a/tests/unit/parsers/mobiledoc/0-2-test.js +++ b/tests/unit/parsers/mobiledoc/0-2-test.js @@ -125,6 +125,33 @@ test('#parse doc with marker type', (assert) => { ); }); +test('#parse pull-quote section to aside node', (assert) => { + const mobiledoc = { + version: MOBILEDOC_VERSION, + sections: [ + [], + [[ + 1,'PULL-QUOTE', [ + [[], 0, 'quoted'] + ] + ]] + ] + }; + const parsed = parser.parse(mobiledoc); + + let section = builder.createMarkupSection('ASIDE', [], false); + let markers = [ + builder.createMarker('quoted', []) + ]; + markers.forEach(marker => section.markers.append(marker)); + post.sections.append(section); + + assert.deepEqual( + parsed, + post + ); +}); + test('#parse doc with image section', (assert) => { const mobiledoc = { version: MOBILEDOC_VERSION, diff --git a/tests/unit/parsers/mobiledoc/0-3-test.js b/tests/unit/parsers/mobiledoc/0-3-test.js index 5a2f74aa7..fc500a504 100644 --- a/tests/unit/parsers/mobiledoc/0-3-test.js +++ b/tests/unit/parsers/mobiledoc/0-3-test.js @@ -137,6 +137,35 @@ test('#parse doc with marker type', (assert) => { ); }); +test('#parse pull-quote section to aside node', (assert) => { + const mobiledoc = { + version: MOBILEDOC_VERSION, + atoms: [], + cards: [], + markups: [], + sections: [ + [ + 1,'PULL-QUOTE', [ + [0, [], 0, 'quoted'] + ] + ] + ] + }; + const parsed = parser.parse(mobiledoc); + + let section = builder.createMarkupSection('ASIDE', [], false); + let markers = [ + builder.createMarker('quoted', []) + ]; + markers.forEach(marker => section.markers.append(marker)); + post.sections.append(section); + + assert.deepEqual( + parsed, + post + ); +}); + test('#parse doc with image section', (assert) => { const mobiledoc = { version: MOBILEDOC_VERSION, diff --git a/tests/unit/renderers/editor-dom-test.js b/tests/unit/renderers/editor-dom-test.js index 99ff4326c..5299684fc 100644 --- a/tests/unit/renderers/editor-dom-test.js +++ b/tests/unit/renderers/editor-dom-test.js @@ -775,15 +775,15 @@ test('removes nested children of removed render nodes', (assert) => { 'section render node has all children removed'); }); -test('renders markup section "pull-quote" as
', (assert) => { +test('renders markup section "aside" as ', (assert) => { const post = Helpers.postAbstract.build(({post, markupSection, marker}) => { - return post([markupSection('pull-quote', [marker('abc')])]); + return post([markupSection('aside', [marker('abc')])]); }); const renderTree = new RenderTree(post); render(renderTree); const expectedDOM = Helpers.dom.build(t => { - return t('div', {"class": "pull-quote"}, [t.text('abc')]); + return t('aside', {}, [t.text('abc')]); }); assert.equal(renderTree.rootElement.innerHTML, expectedDOM.outerHTML); diff --git a/tests/unit/renderers/mobiledoc/0-2-test.js b/tests/unit/renderers/mobiledoc/0-2-test.js index cfa06a272..87d160995 100644 --- a/tests/unit/renderers/mobiledoc/0-2-test.js +++ b/tests/unit/renderers/mobiledoc/0-2-test.js @@ -175,9 +175,9 @@ test('renders a post with a list', (assert) => { }); }); -test('renders a pull-quote as markup section', (assert) => { +test('renders an aside as markup section', (assert) => { const post = Helpers.postAbstract.build(({post, markupSection, marker}) => { - return post([markupSection('pull-quote', [marker('abc')])]); + return post([markupSection('aside', [marker('abc')])]); }); const mobiledoc = render(post); assert.deepEqual(mobiledoc, { @@ -185,7 +185,7 @@ test('renders a pull-quote as markup section', (assert) => { sections: [ [], [ - [1, 'pull-quote', [[[], 0, 'abc']]] + [1, 'aside', [[[], 0, 'abc']]] ] ] }); diff --git a/tests/unit/renderers/mobiledoc/0-3-test.js b/tests/unit/renderers/mobiledoc/0-3-test.js index 8853e796c..d0618880f 100644 --- a/tests/unit/renderers/mobiledoc/0-3-test.js +++ b/tests/unit/renderers/mobiledoc/0-3-test.js @@ -319,9 +319,9 @@ test('renders a post with a list', (assert) => { }); }); -test('renders a pull-quote as markup section', (assert) => { +test('renders an aside as markup section', (assert) => { const post = Helpers.postAbstract.build(({post, markupSection, marker}) => { - return post([markupSection('pull-quote', [marker('abc')])]); + return post([markupSection('aside', [marker('abc')])]); }); const mobiledoc = render(post); assert.deepEqual(mobiledoc, { @@ -330,7 +330,7 @@ test('renders a pull-quote as markup section', (assert) => { cards: [], markups: [], sections: [ - [1, 'pull-quote', [[0, [], 0, 'abc']]] + [1, 'aside', [[0, [], 0, 'abc']]] ] }); }); diff --git a/yarn.lock b/yarn.lock index 8d9e1d813..7256e21d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2730,13 +2730,13 @@ mktemp@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/mktemp/-/mktemp-0.4.0.tgz#6d0515611c8a8c84e484aa2000129b98e981ff0b" -mobiledoc-html-renderer@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/mobiledoc-html-renderer/-/mobiledoc-html-renderer-0.3.0.tgz#a26e92d28a06007c545a597813072feec484e74a" +mobiledoc-html-renderer@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/mobiledoc-html-renderer/-/mobiledoc-html-renderer-0.3.1.tgz#a411181015c40be26d716d82824691a63fa8ba88" -mobiledoc-text-renderer@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/mobiledoc-text-renderer/-/mobiledoc-text-renderer-0.3.0.tgz#5b18fc7e1f26d4a149e924a228396ee8e5396a43" +mobiledoc-text-renderer@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/mobiledoc-text-renderer/-/mobiledoc-text-renderer-0.3.1.tgz#08f06f4696925dbacdf1c508144b8caed58e1127" modify-values@^1.0.0: version "1.0.0"