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

WIP - Initial pass to get attributes in the right location #670

Closed
wants to merge 8 commits into from
4 changes: 2 additions & 2 deletions MOBILEDOC.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,10 +224,10 @@ Markup sections, in addition to plain text, can include markups and atoms.
["mention", "@tom", { id: 12 }] ──── mention Atom at index 1
]
sections: [
[sectionTypeIdentifier, tagName, markers], ──── sectionTypeIdentifier for markup sections
[sectionTypeIdentifier, tagName, markers, attributes], ──── sectionTypeIdentifier for markup sections
[1, "h2", [ is always 1.
[0, [], 0, "Simple h2 example"],
]],
], ['data-md-text-align', 'center']],
[1, "p", [
[textTypeIdentifier, openMarkupsIndexes, numberOfClosedMarkups, value],
[0, [], 0, "Example with no markup"], ──── textTypeIdentifier for markup is always 0
Expand Down
2 changes: 1 addition & 1 deletion src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ class Editor {
return this._parser.parse(dom);
}
} else {
return this.builder.createPost();
return this.builder.createPost([this.builder.createMarkupSection()]);
}
}

Expand Down
10 changes: 10 additions & 0 deletions src/js/models/_attributable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { filterObject } from '../utils/array-utils';

export const VALID_ATTRIBUTES = [
'data-md-text-align'
];

/** @this Attributable */
export function attributable(ctx, attributes) {
ctx.attributes = filterObject(attributes, VALID_ATTRIBUTES);
}
6 changes: 5 additions & 1 deletion src/js/models/markup-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Markerable from './_markerable';
import { normalizeTagName } from '../utils/dom-utils';
import { contains } from '../utils/array-utils';
import { MARKUP_SECTION_TYPE } from './types';
import { attributable } from './_attributable';

// valid values of `tagName` for a MarkupSection
export const VALID_MARKUP_SECTION_TAGNAMES = [
Expand Down Expand Up @@ -33,8 +34,11 @@ export const MARKUP_SECTION_ELEMENT_NAMES = [
export const DEFAULT_TAG_NAME = VALID_MARKUP_SECTION_TAGNAMES[8];

const MarkupSection = class MarkupSection extends Markerable {
constructor(tagName=DEFAULT_TAG_NAME, markers=[]) {
constructor(tagName=DEFAULT_TAG_NAME, markers=[], attributes={}) {
super(MARKUP_SECTION_TYPE, tagName, markers);

attributable(this, attributes);

this.isMarkupSection = true;
}

Expand Down
4 changes: 2 additions & 2 deletions src/js/models/post-node-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,9 @@ class PostNodeBuilder {
* @param {Marker[]} [markers=[]]
* @return {MarkupSection}
*/
createMarkupSection(tagName=DEFAULT_MARKUP_SECTION_TAG_NAME, markers=[], isGenerated=false) {
createMarkupSection(tagName=DEFAULT_MARKUP_SECTION_TAG_NAME, markers=[], isGenerated=false, attributes={}) {
tagName = normalizeTagName(tagName);
const section = new MarkupSection(tagName, markers);
const section = new MarkupSection(tagName, markers, attributes);
if (isGenerated) {
section.isGenerated = true;
}
Expand Down
11 changes: 9 additions & 2 deletions src/js/parsers/mobiledoc/0-3-1.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,15 @@ export default class MobiledocParser {
post.sections.append(section);
}

parseMarkupSection([, tagName, markers], post) {
const section = this.builder.createMarkupSection(tagName);
parseMarkupSection([, tagName, markers, attributesArray], post) {

let attributesObject;
if (Array.isArray(attributesArray)) {
attributesObject = kvArrayToObject(attributesArray);
} else {
attributesObject = {};
}
const section = this.builder.createMarkupSection(tagName, [], false, attributesObject);
post.sections.append(section);
this.parseMarkers(markers, section);
// Strip blank markers after they have been created. This ensures any
Expand Down
17 changes: 17 additions & 0 deletions src/js/renderers/editor-dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { addClassName, removeClassName } from '../utils/dom-utils';
import { MARKUP_SECTION_ELEMENT_NAMES } from '../models/markup-section';
import assert from '../utils/assert';
import { TAB } from 'mobiledoc-kit/utils/characters';
import { VALID_ATTRIBUTES } from '../models/_attributable';

export const CARD_ELEMENT_CLASS_NAME = '__mobiledoc-card';
export const NO_BREAK_SPACE = '\u00A0';
Expand All @@ -26,6 +27,17 @@ export const ATOM_CLASS_NAME = '-mobiledoc-kit__atom';
export const EDITOR_HAS_NO_CONTENT_CLASS_NAME = '__has-no-content';
export const EDITOR_ELEMENT_CLASS_NAME = '__mobiledoc-editor';

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

function handleMarkupSectionAttribute(element, attributeKey, attributeValue) {
assert(`cannot use attribute: ${attributeKey}`, _isValidAttribute(attributeKey));

/* This'll work for now, but in the future should be fleshed out */
element.style.setProperty(attributeKey.replace('data-md-',''), attributeValue);
}

function createElementFromMarkup(doc, markup) {
let element = doc.createElement(markup.tagName);
Object.keys(markup.attributes).forEach(k => {
Expand Down Expand Up @@ -83,6 +95,11 @@ function renderMarkupSection(section) {
let element;
if (MARKUP_SECTION_ELEMENT_NAMES.indexOf(section.tagName) !== -1) {
element = document.createElement(section.tagName);

Object.keys(section.attributes).forEach(k => {
handleMarkupSectionAttribute(element, k, section.attributes[k]);
});

} else {
element = document.createElement('div');
addClassName(element, section.tagName);
Expand Down
6 changes: 3 additions & 3 deletions src/js/renderers/mobiledoc/0-3-1.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ const visitor = {
visitArray(visitor, node.sections, opcodes);
},
[MARKUP_SECTION_TYPE](node, opcodes) {
opcodes.push(['openMarkupSection', node.tagName]);
opcodes.push(['openMarkupSection', node.tagName, objectToSortedKVArray(node.attributes)]);
visitArray(visitor, node.markers, opcodes);
},
[LIST_SECTION_TYPE](node, opcodes) {
Expand Down Expand Up @@ -67,9 +67,9 @@ const postOpcodeCompiler = {
value || ''
]);
},
openMarkupSection(tagName) {
openMarkupSection(tagName, attributes) {
this.markers = [];
this.sections.push([MOBILEDOC_MARKUP_SECTION_TYPE, tagName, this.markers]);
this.sections.push([MOBILEDOC_MARKUP_SECTION_TYPE, tagName, this.markers, attributes]);
},
openListSection(tagName) {
this.items = [];
Expand Down
12 changes: 12 additions & 0 deletions tests/acceptance/basic-editor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ test('typing in empty post correctly adds a section to it', (assert) => {
assert.hasElement('#editor p:contains(XY)', 'inserts text at correct spot');
});

test('when presented no mobiledoc to Editor constructor generates empty section', (assert) => {
editor = new Editor();
editor.render(editorElement);

assert.hasElement('#editor');

/* We are asserting here that there is a clickable target in the DOM. */
assert.hasElement('#editor p');
let {post: expected} = Helpers.postAbstract.buildFromText('');
assert.postIsSimilar(editor.post, expected);
});

test('typing when on the end of a card is blocked', (assert) => {
editor = Helpers.editor.buildFromText('[my-card]', {element: editorElement, cards});

Expand Down
13 changes: 13 additions & 0 deletions tests/acceptance/editor-post-editor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,19 @@ test('#insertSectionAtEnd inserts the section at the end', (assert) => {
assert.hasElement('#editor p:eq(1):contains(123)', 'new section added at end');
});

test('markup sections may contain attributes', (assert) => {
const mobiledoc = Helpers.mobiledoc.build(({post, markupSection, marker}) => {
return post([
markupSection('p', [marker('123')], false, {'data-md-text-align': 'center'})
]);
});

editor = new Editor({mobiledoc});
editor.render(editorElement);

assert.hasElement('#editor p[style="text-align: center;"]');
});

test('#insertSection inserts after the cursor active section', (assert) => {
let newSection;
const mobiledoc = Helpers.mobiledoc.build(({post, markupSection, marker}) => {
Expand Down