Skip to content

Commit

Permalink
Port render nodes to use the linked list implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mixonic committed Aug 7, 2015
1 parent 3dd658e commit d262593
Show file tree
Hide file tree
Showing 5 changed files with 65 additions and 83 deletions.
10 changes: 5 additions & 5 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -333,15 +333,15 @@ class Editor {
if (currentMarker.length === 0 && currentMarker.section.markers.length > 1) {
leftRenderNode.scheduleForRemoval();

let isFirstRenderNode = leftRenderNode === leftRenderNode.parentNode.firstChild;
let isFirstRenderNode = leftRenderNode === leftRenderNode.parent.childNodes.head;
if (isFirstRenderNode) {
// move cursor to start of next node
nextCursorMarker = leftRenderNode.nextSibling.postNode;
nextCursorMarker = leftRenderNode.next.postNode;
nextCursorOffset = 0;
} else {
// move cursor to end of prev node
nextCursorMarker = leftRenderNode.previousSibling.postNode;
nextCursorOffset = leftRenderNode.previousSibling.postNode.length;
nextCursorMarker = leftRenderNode.prev.postNode;
nextCursorOffset = leftRenderNode.prev.postNode.length;
}
} else {
leftRenderNode.markDirty();
Expand Down Expand Up @@ -418,7 +418,7 @@ class Editor {
const newSection = this.builder.createMarkupSection('p');
newSection.appendMarker(rightMarker);

let nodeForMove = markerRenderNode.nextSibling;
let nodeForMove = markerRenderNode.next;
while (nodeForMove) {
nodeForMove.scheduleForRemoval();
let movedMarker = nodeForMove.postNode.clone();
Expand Down
76 changes: 24 additions & 52 deletions src/js/models/render-node.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,47 @@
export default class RenderNode {
import LinkedItem from "content-kit-editor/utils/linked-item";
import LinkedList from "content-kit-editor/utils/linked-list";

export default class RenderNode extends LinkedItem {
constructor(postNode) {
this.parentNode = null;
super();
this.parent = null;
this.isDirty = true;
this.isRemoved = false;
this.postNode = postNode;

this.firstChild = null;
this.lastChild = null;
this.nextSibling = null;
this.previousSibling = null;
this.childNodes = new LinkedList({
adoptItem: item => {
item.parent = this;
item.renderTree = this.renderTree;
},
freeItem: item => {
item.parent = null;
item.renderTree = null;
}
});
}
scheduleForRemoval() {
this.isRemoved = true;
if (this.parentNode) {
this.parentNode.markDirty();
if (this.parent) {
this.parent.markDirty();
}
}
markDirty() {
this.isDirty = true;
if (this.parentNode) {
this.parentNode.markDirty();
if (this.parent) {
this.parent.markDirty();
}
}
markClean() {
this.isDirty = false;
}
appendChild(child) {
if (!this.firstChild) {
this.firstChild = child;
}
if (this.lastChild) {
child.previousSibling = this.lastChild;
this.lastChild.nextSibling = child;
}
this.lastChild = child;
child.parentNode = this;
child.renderTree = this.renderTree;
this.childNodes.append(child);
}
removeChild(child) {
if (child.nextSibling) {
child.nextSibling.previousSibling = child.previousSibling;
} else {
this.lastChild = child.previousSibling;
}
if (child.previousSibling) {
child.previousSibling.nextSibling = child.nextSibling;
} else {
this.firstChild = child.nextSibling;
}
this.childNodes.remove(child);
}
insertAfter(node, previousChild) {
if (previousChild) {
node.previousSibling = previousChild;
if (previousChild.nextSibling) {
previousChild.nextSibling.previousSibling = node;
node.nextSibling = previousChild.nextSibling;
} else {
this.lastChild = node;
}
previousChild.nextSibling = node;
} else {
node.nextSibling = this.firstChild;
if (node.nextSibling) {
node.nextSibling.previousSibling = node;
} else {
this.lastChild = node;
}
this.firstChild = node;
}
node.parentNode = this;
node.renderTree = this.renderTree;
insertAfter(node, prev) {
this.childNodes.insertAfter(node, prev);
}
set element(element) {
this._element = element;
Expand Down
39 changes: 19 additions & 20 deletions src/js/renderers/editor-dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,18 +114,18 @@ class Visitor {
if (!hasRendered) {
let element = renderNode.element;

if (renderNode.previousSibling) {
let previousElement = renderNode.previousSibling.element;
if (renderNode.prev) {
let previousElement = renderNode.prev.element;
let nextElement = previousElement.nextSibling;
if (nextElement) {
nextElement.parentNode.insertBefore(element, nextElement);
}
}
if (!element.parentNode) {
renderNode.parentNode.element.appendChild(element);
renderNode.parent.element.appendChild(element);
}
} else {
renderNode.parentNode.element.replaceChild(element, originalElement);
renderNode.parent.element.replaceChild(element, originalElement);
}

// remove all elements so that we can rerender
Expand All @@ -138,12 +138,12 @@ class Visitor {
[MARKER_TYPE](renderNode, marker) {
let parentElement;

if (renderNode.previousSibling) {
parentElement = getNextMarkerElement(renderNode.previousSibling);
if (renderNode.prev) {
parentElement = getNextMarkerElement(renderNode.prev);
} else {
parentElement = renderNode.parentNode.element;
parentElement = renderNode.parent.element;
}
let textNode = renderMarker(marker, parentElement, renderNode.previousSibling);
let textNode = renderMarker(marker, parentElement, renderNode.prev);

renderNode.element = textNode;
}
Expand All @@ -156,15 +156,15 @@ class Visitor {
} else {
let element = document.createElement('img');
element.src = section.src;
if (renderNode.previousSibling) {
let previousElement = renderNode.previousSibling.element;
if (renderNode.prev) {
let previousElement = renderNode.prev.element;
let nextElement = previousElement.nextSibling;
if (nextElement) {
nextElement.parentNode.insertBefore(element, nextElement);
}
}
if (!element.parentNode) {
renderNode.parentNode.element.appendChild(element);
renderNode.parent.element.appendChild(element);
}
renderNode.element = element;
}
Expand All @@ -178,15 +178,15 @@ class Visitor {
const element = document.createElement('div');
element.contentEditable = 'false';
renderNode.element = element;
if (renderNode.previousSibling) {
let previousElement = renderNode.previousSibling.element;
if (renderNode.prev) {
let previousElement = renderNode.prev.element;
let nextElement = previousElement.nextSibling;
if (nextElement) {
nextElement.parentNode.insertBefore(element, nextElement);
}
}
if (!element.parentNode) {
renderNode.parentNode.element.appendChild(element);
renderNode.parent.element.appendChild(element);
}

if (card) {
Expand All @@ -204,7 +204,7 @@ let destroyHooks = {
throw new Error('post destruction is not supported by the renderer');
},
[MARKUP_SECTION_TYPE](renderNode, section) {
let post = renderNode.parentNode.postNode;
let post = renderNode.parent.postNode;
post.removeSection(section);
// Some formatting commands remove the element from the DOM during
// formatting. Do not error if this is the case.
Expand Down Expand Up @@ -236,7 +236,7 @@ let destroyHooks = {
},

[IMAGE_SECTION_TYPE](renderNode, section) {
let post = renderNode.parentNode.postNode;
let post = renderNode.parent.postNode;
post.removeSection(section);
renderNode.element.parentNode.removeChild(renderNode.element);
},
Expand All @@ -245,17 +245,17 @@ let destroyHooks = {
if (renderNode.cardNode) {
renderNode.cardNode.teardown();
}
let post = renderNode.parentNode.postNode;
let post = renderNode.parent.postNode;
post.removeSection(section);
renderNode.element.parentNode.removeChild(renderNode.element);
}
};

// removes children from parentNode that are scheduled for removal
function removeChildren(parentNode) {
let child = parentNode.firstChild;
let child = parentNode.childNodes.head;
while (child) {
let nextChild = child.nextSibling;
let nextChild = child.next;
if (child.isRemoved) {
destroyHooks[child.postNode.type](child, child.postNode);
parentNode.removeChild(child);
Expand All @@ -271,7 +271,6 @@ function lookupNode(renderTree, parentNode, postNode, previousNode) {
return postNode.renderNode;
} else {
let renderNode = new RenderNode(postNode);
renderNode.renderTree = renderTree;
parentNode.insertAfter(renderNode, previousNode);
postNode.renderNode = renderNode;
return renderNode;
Expand Down
13 changes: 12 additions & 1 deletion src/js/utils/linked-list.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
export default class LinkedList {
constructor() {
constructor(options) {
this.head = null;
this.tail = null;
if (options) {
let {adoptItem, freeItem} = options;
this.adoptItem = adoptItem;
this.freeItem = freeItem;
}
}
prepend(item) {
this.insertBefore(item, this.head);
Expand All @@ -18,6 +23,9 @@ export default class LinkedList {
}
insertBefore(item, nextItem) {
this.remove(item);
if (this.adoptItem) {
this.adoptItem(item);
}
if (nextItem && nextItem.prev) {
// middle of the items
let prevItem = nextItem.prev;
Expand Down Expand Up @@ -47,6 +55,9 @@ export default class LinkedList {
}
}
remove(item) {
if (this.freeItem) {
this.freeItem(item);
}
if (item.next && item.prev) {
// Middle of the list
item.next.prev = item.prev;
Expand Down
10 changes: 5 additions & 5 deletions tests/unit/renderers/editor-dom-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ test("It renders a dirty post with un-rendered sections", (assert) => {
assert.equal(renderTree.node.element.outerHTML, '<div><p></p><p></p></div>',
'correct HTML is rendered');

assert.ok(renderTree.node.firstChild,
assert.ok(renderTree.node.childNodes.head,
'sectionA creates a first child');
assert.equal(renderTree.node.firstChild.postNode, sectionA,
assert.equal(renderTree.node.childNodes.head.postNode, sectionA,
'sectionA is first renderNode child');
assert.ok(!renderTree.node.firstChild.isDirty, 'sectionA node is clean');
assert.equal(renderTree.node.lastChild.postNode, sectionB,
assert.ok(!renderTree.node.childNodes.head.isDirty, 'sectionA node is clean');
assert.equal(renderTree.node.childNodes.tail.postNode, sectionB,
'sectionB is second renderNode child');
assert.ok(!renderTree.node.lastChild.isDirty, 'sectionB node is clean');
assert.ok(!renderTree.node.childNodes.tail.isDirty, 'sectionB node is clean');
});

[
Expand Down

0 comments on commit d262593

Please sign in to comment.