Skip to content

Commit

Permalink
Implement card refactor for editor-dom renderer
Browse files Browse the repository at this point in the history
fixes #236
  • Loading branch information
bantic committed Nov 18, 2015
1 parent 0001015 commit 194172d
Show file tree
Hide file tree
Showing 13 changed files with 663 additions and 444 deletions.
15 changes: 5 additions & 10 deletions src/js/cards/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,11 @@ import placeholderImageSrc from 'mobiledoc-kit/utils/placeholder-image-src';

export default {
name: 'image',
type: 'dom',

display: {
setup(element, options, env, payload) {
let img = document.createElement('img');
img.src = payload.src || placeholderImageSrc;
element.appendChild(img);
return img;
},
teardown(element) {
element.parentNode.removeChild(element);
}
render({env, options, payload}) {
let img = document.createElement('img');
img.src = payload.src || placeholderImageSrc;
return img;
}
};
1 change: 1 addition & 0 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,7 @@ class Editor {
this._isDestroyed = true;
this.removeAllEventListeners();
this.removeAllViews();
this._renderer.destroy();
}

/**
Expand Down
61 changes: 44 additions & 17 deletions src/js/models/card-node.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import assert from '../utils/assert';

export default class CardNode {
constructor(editor, card, section, element, cardOptions) {
this.editor = editor;
this.card = card;
constructor(editor, card, section, element, options) {
this.editor = editor;
this.card = card;
this.section = section;
this.cardOptions = cardOptions;
this.element = element;
this.options = options;

this.mode = null;
this.setupResult = null;

this._teardownCallback = null;
this._rendered = null;
}

render(mode) {
Expand All @@ -16,17 +20,34 @@ export default class CardNode {
this.teardown();

this.mode = mode;
this.setupResult = this.card[mode].setup(
this.element,
this.cardOptions,
this.env,
this.section.payload
);

let method = mode === 'display' ? 'render' : 'edit';

let rendered = this.card[method]({
env: this.env,
options: this.options,
payload: this.section.payload
});

this._validateAndAppendRenderResult(rendered);
}

teardown() {
if (this._teardownCallback) {
this._teardownCallback();
this._teardownCallback = null;
}
if (this._rendered) {
this.element.removeChild(this._rendered);
this._rendered = null;
}
}

get env() {
return {
name: this.card.name,
isInEditor: true,
onTeardown: (callback) => this._teardownCallback = callback,
edit: () => this.edit(),
save: (payload, transition=true) => {
this.section.payload = payload;
Expand All @@ -38,7 +59,7 @@ export default class CardNode {
},
cancel: () => this.display(),
remove: () => this.remove(),
section: this.section
postModel: this.section
};
}

Expand All @@ -54,11 +75,17 @@ export default class CardNode {
this.editor.run(postEditor => postEditor.removeSection(this.section));
}

teardown() {
if (this.mode) {
if (this.card[this.mode].teardown) {
this.card[this.mode].teardown(this.setupResult);
}
_validateAndAppendRenderResult(rendered) {
if (!rendered) {
return;
}

let { card: { name } } = this;
assert(
`Card "${name}" must render dom (render value was: "${rendered}")`,
(typeof rendered === 'object')
);
this.element.appendChild(rendered);
this._rendered = rendered;
}
}
67 changes: 52 additions & 15 deletions src/js/renderers/editor-dom.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import CardNode from 'mobiledoc-kit/models/card-node';
import { detect } from 'mobiledoc-kit/utils/array-utils';
import { detect, forEach } from 'mobiledoc-kit/utils/array-utils';
import {
POST_TYPE,
MARKUP_SECTION_TYPE,
Expand All @@ -12,6 +12,7 @@ import {
import { startsWith, endsWith } from '../utils/string-utils';
import { addClassName } from '../utils/dom-utils';
import { MARKUP_SECTION_ELEMENT_NAMES } from '../models/markup-section';
import assert from '../utils/assert';

export const NO_BREAK_SPACE = '\u00A0';
export const SPACE = ' ';
Expand Down Expand Up @@ -155,19 +156,52 @@ function removeRenderNodeSectionFromParent(renderNode, section) {
}

function removeRenderNodeElementFromParent(renderNode) {
if (renderNode.element.parentNode) {
if (renderNode.element && renderNode.element.parentNode) {
renderNode.element.parentNode.removeChild(renderNode.element);
}
}

function validateCards(cards=[]) {
forEach(cards, card => {
assert(
`Card "${card.name}" must define type "dom", has: "${card.type}"`,
card.type === 'dom'
);
assert(
`Card "${card.name}" must define \`render\` method`,
!!card.render
);
});
return cards;
}

class Visitor {
constructor(editor, cards, unknownCardHandler, options) {
this.editor = editor;
this.cards = cards;
this.cards = validateCards(cards);
this.unknownCardHandler = unknownCardHandler;
this.options = options;
}

_findCard(cardName) {
let card = detect(this.cards, card => card.name === cardName);
return card || this._createUnknownCard(cardName);
}

_createUnknownCard(cardName) {
assert(
`Unknown card "${cardName}" found, but no unknownCardHandler is defined`,
!!this.unknownCardHandler
);

return {
name: cardName,
type: 'dom',
render: this.unknownCardHandler,
edit: this.unknownCardHandler
};
}

[POST_TYPE](renderNode, post, visit) {
if (!renderNode.element) {
renderNode.element = document.createElement('div');
Expand Down Expand Up @@ -251,23 +285,19 @@ class Visitor {
[CARD_TYPE](renderNode, section) {
const originalElement = renderNode.element;
const {editor, options} = this;
const card = detect(this.cards, card => card.name === section.name);

const card = this._findCard(section.name);

let { wrapper, cardElement } = renderCard();
renderNode.element = wrapper;
attachRenderNodeElementToDOM(renderNode, originalElement);

if (card) {
const cardNode = new CardNode(
editor, card, section, cardElement, options);
renderNode.cardNode = cardNode;
const initialMode = section._initialMode;
cardNode[initialMode]();
} else {
const env = { name: section.name };
this.unknownCardHandler(
cardElement, options, env, section.payload);
}
const cardNode = new CardNode(
editor, card, section, cardElement, options);
renderNode.cardNode = cardNode;

const initialMode = section._initialMode;
cardNode[initialMode]();
}
}

Expand Down Expand Up @@ -363,6 +393,12 @@ export default class Renderer {
this.nodes = [];
}

destroy() {
let renderNode = this.renderTree.rootNode;
let force = true;
removeDestroyedChildren(renderNode, force);
}

visit(renderTree, parentNode, postNodes, visitAll=false) {
let previousNode;
postNodes.forEach(postNode => {
Expand All @@ -375,6 +411,7 @@ export default class Renderer {
}

render(renderTree) {
this.renderTree = renderTree;
let renderNode = renderTree.rootNode;
let method, postNode;

Expand Down
11 changes: 3 additions & 8 deletions tests/acceptance/basic-editor-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@ const { test, module } = Helpers;

const cards = [{
name: 'my-card',
display: {
setup() {},
teardown() {}
},
edit: {
setup() {},
teardown() {}
}
type: 'dom',
render() {},
edit() {}
}];

let editor, editorElement;
Expand Down
11 changes: 3 additions & 8 deletions tests/acceptance/cursor-movement-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,9 @@ const { test, module } = Helpers;

const cards = [{
name: 'my-card',
display: {
setup() {},
teardown() {}
},
edit: {
setup() {},
teardown() {}
}
type: 'dom',
render() {},
edit() {}
}];

let editor, editorElement;
Expand Down
11 changes: 3 additions & 8 deletions tests/acceptance/cursor-position-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,9 @@ const { test, module } = Helpers;

const cards = [{
name: 'my-card',
display: {
setup() {},
teardown() {}
},
edit: {
setup() {},
teardown() {}
}
type: 'dom',
render() {},
edit() {}
}];

let editor, editorElement;
Expand Down
Loading

0 comments on commit 194172d

Please sign in to comment.