Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Mobiledoc 0.3.2 #62

Merged
merged 1 commit into from
Jul 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion lib/renderer-factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
} from './renderers/0-2';
import Renderer_0_3, {
MOBILEDOC_VERSION_0_3_0,
MOBILEDOC_VERSION_0_3_1
MOBILEDOC_VERSION_0_3_1,
MOBILEDOC_VERSION_0_3_2
} from './renderers/0-3';
import RENDER_TYPE from './utils/render-type';

Expand Down Expand Up @@ -89,6 +90,7 @@
return new Renderer_0_2(mobiledoc, this.options).render();
case MOBILEDOC_VERSION_0_3_0:
case MOBILEDOC_VERSION_0_3_1:
case MOBILEDOC_VERSION_0_3_2:
return new Renderer_0_3(mobiledoc, this.options).render();
default:
throw new Error(`Unexpected Mobiledoc version "${version}"`);
Expand Down
8 changes: 5 additions & 3 deletions lib/renderers/0-3.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ import {

export const MOBILEDOC_VERSION_0_3_0 = '0.3.0';
export const MOBILEDOC_VERSION_0_3_1 = '0.3.1';
export const MOBILEDOC_VERSION = MOBILEDOC_VERSION_0_3_0;
export const MOBILEDOC_VERSION_0_3_2 = '0.3.2';

const IMAGE_SECTION_TAG_NAME = 'img';

function validateVersion(version) {
switch (version) {
case MOBILEDOC_VERSION_0_3_0:
case MOBILEDOC_VERSION_0_3_1:
case MOBILEDOC_VERSION_0_3_2:
return;
default:
throw new Error(`Unexpected Mobiledoc version "${version}"`);
Expand Down Expand Up @@ -374,14 +375,15 @@ export default class Renderer {
return rendered || createTextNode(this.dom, '');
}

renderMarkupSection([type, tagName, markers]) {
renderMarkupSection([type, tagName, markers, attributes = []]) {
tagName = tagName.toLowerCase();
if (!isValidSectionTagName(tagName, MARKUP_SECTION_TYPE)) {
return;
}

let attrsObj = reduceAttributes(attributes);
let renderer = this.sectionElementRendererFor(tagName);
let element = renderer(tagName, this.dom);
let element = renderer(tagName, this.dom, attrsObj);

this.renderMarkersOnElement(element, markers);
return element;
Expand Down
32 changes: 32 additions & 0 deletions lib/utils/array-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,35 @@ export function includes(array, detectValue) {
}
return false;
}


/**
* @param {Array} array of key1,value1,key2,value2,...
* @return {Object} {key1:value1, key2:value2, ...}
* @private
*/
export function kvArrayToObject(array) {
if (!Array.isArray(array)) { return {}; }

const obj = {};
for (let i = 0; i < array.length; i+=2) {
let [key, value] = [array[i], array[i+1]];
obj[key] = value;
}
return obj;
}

/**
* @param {Object} {key1:value1, key2:value2, ...}
* @return {Array} array of key1,value1,key2,value2,...
* @private
*/
export function objectToSortedKVArray(obj) {
const keys = Object.keys(obj).sort();
const result = [];
keys.forEach(k => {
result.push(k);
result.push(obj[k]);
});
return result;
}
22 changes: 21 additions & 1 deletion lib/utils/render-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,30 @@ import {
sanitizeHref
} from './sanitization-utils';

export function defaultSectionElementRenderer(tagName, dom) {
export const VALID_ATTRIBUTES = [
'data-md-text-align'
];

function _isValidAttribute(attr) {
return VALID_ATTRIBUTES.indexOf(attr) !== -1;
}

function handleMarkupSectionAttribute(element, attributeKey, attributeValue) {
if (!_isValidAttribute(attributeKey)) {
throw new Error(`Cannot use attribute: ${attributeKey}`);
}

element.setAttribute(attributeKey, attributeValue);
}

export function defaultSectionElementRenderer(tagName, dom, attrsObj = {}) {
let element;
if (isMarkupSectionElementName(tagName)) {
element = dom.createElement(tagName);

Object.keys(attrsObj).forEach(k => {
handleMarkupSectionAttribute(element, k, attrsObj[k]);
});
} else {
element = dom.createElement('div');
element.setAttribute('class', tagName);
Expand Down
18 changes: 11 additions & 7 deletions tests/helpers/create-mobiledoc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const MOBILEDOC_VERSION_0_3_1 = '0.3.1';
const MOBILEDOC_VERSION_0_3_2 = '0.3.2';
import {
MARKUP_SECTION_TYPE,
CARD_SECTION_TYPE
Expand All @@ -8,7 +8,9 @@ import {
ATOM_MARKER_TYPE
} from 'mobiledoc-dom-renderer/utils/marker-types';

export function createBlankMobiledoc({version=MOBILEDOC_VERSION_0_3_1}={}) {
import { objectToSortedKVArray } from 'mobiledoc-dom-renderer/utils/array-utils';

export function createBlankMobiledoc({version=MOBILEDOC_VERSION_0_3_2}={}) {
return {
version,
atoms: [],
Expand All @@ -18,7 +20,7 @@ export function createBlankMobiledoc({version=MOBILEDOC_VERSION_0_3_1}={}) {
};
}

export function createMobiledocWithAtom({version=MOBILEDOC_VERSION_0_3_1, atom}={}) {
export function createMobiledocWithAtom({version=MOBILEDOC_VERSION_0_3_2, atom}={}) {
return {
version,
atoms: [atom],
Expand All @@ -32,7 +34,7 @@ export function createMobiledocWithAtom({version=MOBILEDOC_VERSION_0_3_1, atom}=
};
}

export function createMobiledocWithCard({version=MOBILEDOC_VERSION_0_3_1, card}={}) {
export function createMobiledocWithCard({version=MOBILEDOC_VERSION_0_3_2, card}={}) {
return {
version,
atoms: [],
Expand All @@ -46,7 +48,7 @@ export function createMobiledocWithCard({version=MOBILEDOC_VERSION_0_3_1, card}=
};
}

export function createSimpleMobiledoc({sectionName='p', text='hello world', markup=null, version=MOBILEDOC_VERSION_0_3_1}={}) {
export function createSimpleMobiledoc({sectionName='p', text='hello world', markup=null, version=MOBILEDOC_VERSION_0_3_2, attributes={}}={}) {
let openedMarkups = markup ? [0] : [];
let closedMarkups = markup ? 1 : 0;
let markups = markup ? [markup] : [];
Expand All @@ -58,8 +60,10 @@ export function createSimpleMobiledoc({sectionName='p', text='hello world', mark
markups: markups,
sections: [
[MARKUP_SECTION_TYPE, sectionName, [
[MARKUP_MARKER_TYPE, openedMarkups, closedMarkups, text]]
]
[MARKUP_MARKER_TYPE, openedMarkups, closedMarkups, text]
],
objectToSortedKVArray(attributes)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The optional section attribute value should only be in this array if the version of mobiledoc is 0.3.2, if 0.3.1 or earlier it should not be present at all. This will ensure the tests are still testing old 0.3.1 docs, which we really care about continuing to support/test.

],
]
};
}
31 changes: 31 additions & 0 deletions tests/unit/renderers/0-3-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
const { test, module } = QUnit;
const MOBILEDOC_VERSION_0_3_0 = '0.3.0';
const MOBILEDOC_VERSION_0_3_1 = '0.3.1';
const MOBILEDOC_VERSION_0_3_2 = '0.3.2';
const dataUri = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=";


Expand Down Expand Up @@ -71,6 +72,36 @@ test('renders 0.3.0 markup section "pull-quote" as div with class', (assert) =>
assert.equal(outerHTML(sectionEl), '<div class="pull-quote">hello world</div>');
});

test('renders 0.3.2 markup section attributes', (assert) => {
let mobiledoc = createSimpleMobiledoc({
version: MOBILEDOC_VERSION_0_3_2,
sectionName: 'p',
text: 'hello world',
attributes: { 'data-md-text-align': 'center' }
});

let { result: rendered } = renderer.render(mobiledoc);
assert.equal(childNodesLength(rendered), 1,
'renders 1 section');
let sectionEl = rendered.firstChild;

assert.equal(outerHTML(sectionEl), '<p data-md-text-align="center">hello world</p>');
});

test('throws when given invalid attribute', (assert) => {
let mobiledoc = createSimpleMobiledoc({
version: MOBILEDOC_VERSION_0_3_2,
sectionName: 'p',
text: 'hello world',
attributes: { 'data-md-bad-attribute': 'something' }
});

assert.throws(
() => { renderer.render(mobiledoc) }, // jshint ignore: line
new RegExp(`Cannot use attribute: data-md-bad-attribute`)
);
});

test('renders 0.3.1 markup section "pull-quote" as div with class', (assert) => {
let mobiledoc = createSimpleMobiledoc({
version: MOBILEDOC_VERSION_0_3_1,
Expand Down
52 changes: 52 additions & 0 deletions tests/unit/utils/array-utils-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* global QUnit */

import {
kvArrayToObject,
objectToSortedKVArray
} from 'mobiledoc-dom-renderer/utils/array-utils';

const { test, module } = QUnit;

module('Unit: Mobiledoc DOM Renderer - Array utils');

test('#kvArrayToObject', (assert) => {
assert.deepEqual(
kvArrayToObject([]),
{}
);
assert.deepEqual(
kvArrayToObject(['data-md-text-align', 'center']),
{
'data-md-text-align': 'center'
}
);
});

test('#objectToSortedKVArray', (assert) => {
assert.deepEqual(
objectToSortedKVArray({}),
[]
);
assert.deepEqual(
objectToSortedKVArray(
{
'data-md-text-align': 'center'
}
),
[
'data-md-text-align', 'center'
]
);
assert.deepEqual(
objectToSortedKVArray(
{
'data-md-text-align': 'center',
'data-md-color': 'red'
}
),
[
'data-md-color', 'red',
'data-md-text-align', 'center'
]
);
});