Skip to content

Commit

Permalink
Merge pull request #48 from mixonic/ll
Browse files Browse the repository at this point in the history
Port posts and markers to linked lists
  • Loading branch information
mixonic committed Aug 10, 2015
2 parents 63474c8 + 7731668 commit e632b88
Show file tree
Hide file tree
Showing 25 changed files with 501 additions and 374 deletions.
2 changes: 1 addition & 1 deletion src/js/commands/image.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export default class ImageCommand extends Command {
let sections = this.editor.activeSections;
let lastSection = sections[sections.length - 1];
let section = builder.createCardSection('image');
post.insertSectionAfter(section, lastSection);
post.sections.insertAfter(section, lastSection);
sections.forEach(section => section.renderNode.scheduleForRemoval());

this.editor.rerender();
Expand Down
30 changes: 13 additions & 17 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ class Editor {
}
} else {
let currentSection = currentMarker.section;
let previousMarker = currentMarker.previousSibling;
let previousMarker = currentMarker.prev;
if (previousMarker) { // (B)
let markerLength = previousMarker.length;
previousMarker.deleteValueAtOffset(markerLength - 1);
Expand All @@ -394,17 +394,17 @@ class Editor {
// * none -- do nothing
// * markup section -- join to it
// * non-markup section (card) -- select it? delete it?
let previousSection = this.post.getPreviousSection(currentSection);
let previousSection = currentSection.prev;
if (previousSection) {
let isMarkupSection = previousSection.type === MARKUP_SECTION_TYPE;

if (isMarkupSection) {
let previousSectionMarkerLength = previousSection.markers.length;
let lastPreviousMarker = previousSection.markers.tail;
previousSection.join(currentSection);
previousSection.renderNode.markDirty();
currentSection.renderNode.scheduleForRemoval();

nextCursorMarker = previousSection.markers[previousSectionMarkerLength];
nextCursorMarker = lastPreviousMarker.next;
nextCursorOffset = 0;
/*
} else {
Expand Down Expand Up @@ -449,23 +449,23 @@ class Editor {
// FIXME rightMarker is not guaranteed to be there
let [leftMarker, rightMarker] = newMarkers;

section.insertMarkerAfter(leftMarker, marker);
section.markers.insertAfter(leftMarker, marker);
markerRenderNode.scheduleForRemoval();

const newSection = this.builder.createMarkupSection('p');
newSection.appendMarker(rightMarker);
newSection.markers.append(rightMarker);

let nodeForMove = markerRenderNode.next;
while (nodeForMove) {
nodeForMove.scheduleForRemoval();
let movedMarker = nodeForMove.postNode.clone();
newSection.appendMarker(movedMarker);
newSection.markers.append(movedMarker);

nodeForMove = nodeForMove.nextSibling;
nodeForMove = nodeForMove.next;
}

const post = this.post;
post.insertSectionAfter(newSection, section);
post.sections.insertAfter(newSection, section);

this.rerender();
this.trigger('update');
Expand Down Expand Up @@ -657,8 +657,8 @@ class Editor {
sectionRenderNode.markClean();

let previousSectionRenderNode = previousSection && previousSection.renderNode;
this.post.insertSectionAfter(section, previousSection);
this._renderTree.node.insertAfter(sectionRenderNode, previousSectionRenderNode);
this.post.sections.insertAfter(section, previousSection);
this._renderTree.node.childNodes.insertAfter(sectionRenderNode, previousSectionRenderNode);
}

// may cause duplicates to be included
Expand Down Expand Up @@ -802,16 +802,12 @@ class Editor {
let newRenderNode = this._renderTree.buildRenderNode(newSection);
let renderNodes = this.cursor.activeSections.map(s => s.renderNode);
let lastRenderNode = renderNodes[renderNodes.length-1];
lastRenderNode.parentNode.insertAfter(newRenderNode, lastRenderNode);
this.post.insertSectionAfter(newSection, lastRenderNode.postNode);
lastRenderNode.parent.childNodes.insertAfter(newRenderNode, lastRenderNode);
this.post.sections.insertAfter(newSection, lastRenderNode.postNode);
renderNodes.forEach(renderNode => renderNode.scheduleForRemoval());
this.trigger('update');
}

removeSection(section) {
this.post.removeSection(section);
}

destroy() {
this.removeAllEventListeners();
this.removeAllViews();
Expand Down
5 changes: 4 additions & 1 deletion src/js/models/card.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import LinkedItem from "content-kit-editor/utils/linked-item";

export const CARD_TYPE = 'card-section';

export default class Card {
export default class Card extends LinkedItem {
constructor(name, payload) {
super();
this.name = name;
this.payload = payload;
this.type = CARD_TYPE;
Expand Down
11 changes: 4 additions & 7 deletions src/js/models/cursor.js
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,12 @@ export default class Cursor {
const {result:startSection} = detectParentNode(startContainer, isSectionElement);
const {result:endSection} = detectParentNode(endContainer, isSectionElement);

const startIndex = sections.indexOf(startSection),
endIndex = sections.indexOf(endSection) + 1;

return sections.slice(startIndex, endIndex);
return sections.readRange(startSection, endSection);
}

// moves cursor to the start of the section
moveToSection(section) {
const marker = section.markers[0];
const marker = section.markers.head;
if (!marker) { throw new Error('Cannot move cursor to section without a marker'); }
const markerElement = marker.renderNode.element;

Expand All @@ -124,8 +121,8 @@ export default class Cursor {
const startSection = sections[0],
endSection = sections[sections.length - 1];

const startNode = startSection.markers[0].renderNode.element,
endNode = endSection.markers[endSection.markers.length - 1].renderNode.element;
const startNode = startSection.markers.head.renderNode.element,
endNode = endSection.markers.tail.renderNode.element;

const startOffset = 0,
endOffset = endNode.textContent.length;
Expand Down
24 changes: 5 additions & 19 deletions src/js/models/marker.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ import {
detect,
difference
} from 'content-kit-editor/utils/array-utils';
import LinkedItem from "content-kit-editor/utils/linked-item";

const Marker = class Marker {
const Marker = class Marker extends LinkedItem {
constructor(value='', markups=[]) {
super();
this.value = value;
this.markups = [];
this.type = MARKER_TYPE;
Expand Down Expand Up @@ -107,29 +109,13 @@ const Marker = class Marker {
}

get openedMarkups() {
let previousMarkups = this.previousSibling && this.previousSibling.markups;
return difference(this.markups, previousMarkups || []);
return difference(this.markups, (this.prev ? this.prev.markups : []));
}

get closedMarkups() {
let nextMarkups = this.nextSibling && this.nextSibling.markups;
return difference(this.markups, nextMarkups || []);
return difference(this.markups, (this.next ? this.next.markups : []));
}

// FIXME this should be implemented as a linked list
get nextSibling() {
let index = this.section.markers.indexOf(this);
if (index > -1 && index < this.section.markers.length-1) {
return this.section.markers[index + 1];
}
}

get previousSibling() {
let index = this.section.markers.indexOf(this);
if (index > 0) {
return this.section.markers[index - 1];
}
}
};

export default Marker;
100 changes: 35 additions & 65 deletions src/js/models/markup-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,25 @@ export const VALID_MARKUP_SECTION_TAGNAMES = [
'p', 'h3', 'h2', 'h1', 'blockquote', 'ul', 'ol'
].map(normalizeTagName);
export const MARKUP_SECTION_TYPE = 'markup-section';
import LinkedList from "content-kit-editor/utils/linked-list";
import LinkedItem from "content-kit-editor/utils/linked-item";

export default class Section {
export default class Section extends LinkedItem {
constructor(tagName, markers=[]) {
this.markers = [];
super();
this.markers = new LinkedList({
adoptItem: (marker) => {
marker.section = this;
},
freeItem: (marker) => {
marker.section = null;
}
});
this.tagName = tagName || DEFAULT_TAG_NAME;
this.type = MARKUP_SECTION_TYPE;
this.element = null;

markers.forEach(m => this.appendMarker(m));
markers.forEach(m => this.markers.append(m));
}

set tagName(val) {
Expand Down Expand Up @@ -49,50 +59,10 @@ export default class Section {
*/
splitMarker(marker, offset, endOffset=marker.length) {
const newMarkers = marker.split(offset, endOffset);
this.replaceMarker(marker, newMarkers);
this.markers.splice(marker, 1, newMarkers);
return newMarkers;
}

replaceMarker(oldMarker, newMarkers=[]) {
let previousMarker = oldMarker;

let i = newMarkers.length;
while (i--) {
let currentMarker = newMarkers[i];
this.insertMarkerAfter(currentMarker, previousMarker);
}

this.removeMarker(oldMarker);
}

prependMarker(marker) {
marker.section = this;
this.markers.unshift(marker);
}

appendMarker(marker) {
marker.section = this;
this.markers.push(marker);
}

removeMarker(marker) {
const index = this.markers.indexOf(marker);
if (index === -1) {
throw new Error('Cannot remove not-found marker');
}
this.markers.splice(index, 1);
}

insertMarkerAfter(marker, previousMarker) {
const index = this.markers.indexOf(previousMarker);
if (index === -1) {
throw new Error('Cannot insert marker after: ' + previousMarker);
}

marker.section = this;
this.markers.splice(index + 1, 0, marker);
}

/**
* @return {Array} 2 new sections
*/
Expand All @@ -107,12 +77,9 @@ export default class Section {
new this.constructor(this.tagName, [])
];
}
const middleIndex = this.markers.indexOf(middle);

for (let i=0; i<this.markers.length; i++) {
if (i < middleIndex) { left.push(this.markers[i]); }
if (i > middleIndex) { right.push(this.markers[i]); }
}
left = (middle.prev ? this.markers.readRange(null, middle.prev) : []);
right = (middle.next ? this.markers.readRange(middle.next, null) : []);

let leftLength = left.reduce((prev, cur) => prev + cur.length, 0);
let middleOffset = offset - leftLength;
Expand All @@ -129,7 +96,9 @@ export default class Section {

// mutates this by appending the other section's (cloned) markers to it
join(otherSection) {
otherSection.markers.forEach(m => this.appendMarker(m.clone()));
otherSection.markers.forEach(m => {
this.markers.append(m.clone());
});
}

/**
Expand All @@ -141,26 +110,27 @@ export default class Section {
* @return {Marker} The marker that contains this offset
*/
markerContaining(offset, leftInclusive=true) {
var length=0, i=0;
let length = 0;
let lastMarker = null;

if (offset === 0) { return this.markers[0]; }

while (length < offset && i < this.markers.length) {
length += this.markers[i].length;
i++;
if (offset === 0) {
return this.markers.head;
}

this.markers.detect((marker) => {
if (length < offset) {
lastMarker = marker;
length += marker.length;
return false;
} else {
return true; // stop iteration
}
});

if (length > offset) {
return this.markers[i-1];
return lastMarker;
} else if (length === offset) {
return this.markers[leftInclusive ? i : i-1];
}
}

get nextSibling() {
const index = this.post.sections.indexOf(this);
if (index !== -1) {
return this.post.sections[index+1];
return (leftInclusive ? lastMarker.next : lastMarker);
}
}
}
Loading

0 comments on commit e632b88

Please sign in to comment.