Skip to content

Commit

Permalink
Implement parserPlugins API
Browse files Browse the repository at this point in the history
  • Loading branch information
mixonic committed Dec 8, 2015
1 parent 06b1406 commit f52d97e
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 37 deletions.
4 changes: 2 additions & 2 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class Editor {
this._elementListeners = [];
this._views = [];
this.isEditable = null;
this._cardParsers = options.cardParsers || [];
this._parserPlugins = options.parserPlugins || [];

// FIXME: This should merge onto this.options
mergeWithOptions(this, defaults, options);
Expand Down Expand Up @@ -735,7 +735,7 @@ class Editor {
this.handleDeletion();
}

let pastedPost = parsePostFromPaste(event, this.builder, this._cardParsers);
let pastedPost = parsePostFromPaste(event, this.builder, this._parserPlugins);

this.run(postEditor => {
let nextPosition = postEditor.insertPost(position, pastedPost);
Expand Down
60 changes: 41 additions & 19 deletions src/js/parsers/section.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ import {
transformHTMLText
} from '../parsers/dom';

import assert from '../utils/assert';

function isListSection(section) {
return section.type === LIST_SECTION_TYPE;
}
Expand All @@ -55,7 +57,7 @@ function isListItem(section) {
export default class SectionParser {
constructor(builder, options={}) {
this.builder = builder;
this.cardParsers = options.cardParsers || [];
this.plugins = options.plugins || [];
}

parse(element) {
Expand Down Expand Up @@ -90,11 +92,49 @@ export default class SectionParser {
});
}

runPlugins(node) {
let isNodeFinished = false;
let env = {
addSection: (section) => {
this._closeCurrentSection();
this.sections.push(section);
},
addMarkerable: (marker) => {
let { state } = this;
let { section } = state;
assert(
'Markerables can only be appended to markup sections and list item sections',
section && section.isMarkerable
);
if (state.text) {
this._createMarker();
}
section.markers.append(marker);
},
nodeFinished() {
isNodeFinished = true;
}
};
for (let i=0; i<this.plugins.length; i++) {
let plugin = this.plugins[i];
plugin(node, this.builder, env);
if (isNodeFinished) {
return true;
}
}
return false;
}

parseNode(node) {
if (!this.state.section) {
this._updateStateFromElement(node);
}

let nodeFinished = this.runPlugins(node);
if (nodeFinished) {
return;
}

switch (node.nodeType) {
case TEXT_NODE:
this.parseTextNode(node);
Expand All @@ -107,27 +147,9 @@ export default class SectionParser {
}
}

parseCard(element) {
let { builder } = this;

for (let i=0; i<this.cardParsers.length; i++) {
let card = this.cardParsers[i].parse(element, builder);
if (card) {
this._closeCurrentSection();
this.sections.push(card);
return true;
}
}
}

parseElementNode(element) {
let { state } = this;

let parsedCard = this.parseCard(element);
if (parsedCard) {
return;
}

const markups = this._markupsFromElement(element);
if (markups.length && state.text.length) {
this._createMarker();
Expand Down
4 changes: 2 additions & 2 deletions src/js/utils/paste-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function setClipboardCopyData(copyEvent, editor) {
clipboardData.setData('text/html', html);
}

export function parsePostFromPaste(pasteEvent, builder, cardParsers=[]) {
export function parsePostFromPaste(pasteEvent, builder, plugins=[]) {
let mobiledoc, post;
const mobiledocRegex = new RegExp(/data\-mobiledoc='(.*?)'>/);

Expand All @@ -35,7 +35,7 @@ export function parsePostFromPaste(pasteEvent, builder, cardParsers=[]) {
mobiledoc = JSON.parse(mobiledocString);
post = mobiledocParsers.parse(builder, mobiledoc);
} else {
post = new HTMLParser(builder, {cardParsers}).parse(html);
post = new HTMLParser(builder, {plugins}).parse(html);
}

return post;
Expand Down
11 changes: 5 additions & 6 deletions tests/unit/parsers/dom-google-docs-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,11 @@ Object.keys(GoogleDocs).forEach(key => {
test('img in span can use a cardParser to turn img into image-card', function(assert) {
let example = GoogleDocs['img in span'];
let options = {
cardParsers: [{
parse(element, builder) {
if (element.tagName === 'IMG') {
let payload = {url: element.src};
return builder.createCardSection('image-card', payload);
}
plugins: [function(element, builder, {addSection}) {
if (element.tagName === 'IMG') {
let payload = {url: element.src};
let cardSection = builder.createCardSection('image-card', payload);
addSection(cardSection);
}
}]
};
Expand Down
37 changes: 29 additions & 8 deletions tests/unit/parsers/section-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,21 +104,21 @@ test('#parse turns a textNode into a section', (assert) => {
assert.equal(m1.value, 'I am a text node');
});

test('#parse allows passing in cardParsers that can override parsing', (assert) => {
test('#parse allows passing in parserPlugins that can override element parsing', (assert) => {
let container = buildDOM(`
<p>text 1<img src="http://placehold.it/100x100">text 2</p>
`);

let element = container.firstChild;
let cardParsers = [{
parse(element, builder) {
if (element.tagName === 'IMG') {
let payload = {url: element.src};
return builder.createCardSection('test-image', payload);
}
let plugins = [function(element, builder, {addSection}) {
if (element.tagName !== 'IMG') {
return;
}
let payload = {url: element.src};
let cardSection = builder.createCardSection('test-image', payload);
addSection(cardSection);
}];
parser = new SectionParser(builder, {cardParsers});
parser = new SectionParser(builder, {plugins});
const sections = parser.parse(element);

assert.equal(sections.length, 3, '3 sections');
Expand All @@ -130,3 +130,24 @@ test('#parse allows passing in cardParsers that can override parsing', (assert)
assert.equal(cardSection.name, 'test-image');
assert.deepEqual(cardSection.payload, {url: 'http://placehold.it/100x100'});
});

test('#parse allows passing in parserPlugins that can override text parsing', (assert) => {
let container = buildDOM(`
<p>text 1<img src="http://placehold.it/100x100">text 2</p>
`);

let element = container.firstChild;
let plugins = [function(element, builder, {addMarkerable, nodeFinished}) {
if (element.nodeType === 3) {
if (element.textContent === 'text 1') {
addMarkerable(builder.createMarker('oh my'));
}
nodeFinished();
}
}];
parser = new SectionParser(builder, {plugins});
const sections = parser.parse(element);

assert.equal(sections.length, 1, '1 section');
assert.equal(sections[0].text, 'oh my');
});

0 comments on commit f52d97e

Please sign in to comment.