Skip to content

Commit

Permalink
fix(paste): Fix insertion into blank section (#466)
Browse files Browse the repository at this point in the history
* Refactor #insertPost tests to use builder and editor DSL.
* Add test helper editor DSL `Helpers.editor.buildFromText(dsl, editorOptions)`
* Add test helper `retargetRange` to retarget a range from one post to
  another. Helps with asserting that the editor's range matches the one
  from the DSL

Fixes #462
  • Loading branch information
bantic authored Aug 24, 2016
1 parent 039fd04 commit a3d274d
Show file tree
Hide file tree
Showing 4 changed files with 274 additions and 1,037 deletions.
64 changes: 36 additions & 28 deletions src/js/editor/post/post-inserter.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,7 @@ class Visitor {
if (this.cursorSection.isBlank && !this._isNested) {
// replace blank section with entire post
let newSections = node.sections.map(s => s.clone());
newSections.forEach(section => {
this._replaceSection(this.cursorSection, section);
});
let lastNewSection = newSections[newSections.length - 1];
this.cursorPosition = lastNewSection.tailPosition();
this._replaceSection(this.cursorSection, newSections);
} else {
node.sections.forEach(section => this.visit(section));
}
Expand Down Expand Up @@ -144,19 +140,17 @@ class Visitor {

// break out of a nested cursor position
_breakNestedAtCursor() {
assert('Cannot call _breakNestedAtCursor if not nested',
this._isNested);
assert('Cannot call _breakNestedAtCursor if not nested', this._isNested);

let parent = this.cursorSection.parent,
cursorAtEndOfList = this.cursorPosition.isEqual(parent.tailPosition());
let parent = this.cursorSection.parent;
let cursorAtEndOfList = this.cursorPosition.isEqual(parent.tailPosition());

if (cursorAtEndOfList) {
let blank = this.builder.createMarkupSection();
this._insertSectionAfter(blank, parent);
this.cursorPosition = blank.headPosition();
} else {
let [pre, blank, post] = this._breakListAtCursor(); // jshint ignore:line
this.cursorPosition = blank.headPosition();
this.cursorPosition = blank.tailPosition();
}
}

Expand All @@ -175,13 +169,6 @@ class Visitor {
return [pre, blank, post];
}

_insertSectionAfter(section, parent) {
assert('Cannot _insertSectionAfter nested section', !parent.isNested);
let reference = parent.next;
let collection = this._post.sections;
this.postEditor.insertSectionBefore(collection, section, reference);
}

_wrapNestedSection(section) {
let tagName = section.parent.tagName;
let parent = this.builder.createListSection(tagName);
Expand Down Expand Up @@ -226,17 +213,41 @@ class Visitor {
_breakMarkerableAtCursor() {
let [pre, post] = // jshint ignore:line
this.postEditor.splitSection(this.cursorPosition);

this.cursorPosition = pre.tailPosition();
}

_replaceSection(section, newSection) {
_replaceSection(section, newSections) {
assert('Cannot replace section that does not have parent.sections',
section.parent && section.parent.sections);
assert('Must pass enumerable to _replaceSection', !!newSections.forEach);

let collection = section.parent.sections,
reference = section.next;
let collection = section.parent.sections;
let reference = section.next;
this.postEditor.removeSection(section);
this.postEditor.insertSectionBefore(collection, newSection, reference);
newSections.forEach(section => {
this.postEditor.insertSectionBefore(collection, section, reference);
});
let lastSection = newSections[newSections.length - 1];

this.cursorPosition = lastSection.tailPosition();
}

_insertSectionBefore(section, reference) {
let collection = this.cursorSection.parent.sections;
this.postEditor.insertSectionBefore(collection, section, reference);

this.cursorPosition = section.tailPosition();
}

// Insert a section after the parent section.
// E.g., add a markup section after a list section
_insertSectionAfter(section, parent) {
assert('Cannot _insertSectionAfter nested section', !parent.isNested);
let reference = parent.next;
let collection = this._post.sections;
this.postEditor.insertSectionBefore(collection, section, reference);
this.cursorPosition = section.tailPosition();
}

_insertLeafSection(section) {
Expand All @@ -249,16 +260,13 @@ class Visitor {
if (this.cursorSection.isBlank) {
assert('Cannot insert leaf non-markerable section when cursor is nested',
!(section.isMarkerable && this._isNested));
this._replaceSection(this.cursorSection, section);
this._replaceSection(this.cursorSection, [section]);
} else if (this.cursorSection.next && this.cursorSection.next.isBlank) {
this._replaceSection(this.cursorSection.next, section);
this._replaceSection(this.cursorSection.next, [section]);
} else {
let reference = this.cursorSection.next;
let collection = this.cursorSection.parent.sections;
this.postEditor.insertSectionBefore(collection, section, reference);
this._insertSectionBefore(section, reference);
}

this.cursorPosition = section.tailPosition();
}
}

Expand Down
54 changes: 54 additions & 0 deletions tests/helpers/editor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import PostAbstractHelpers from './post-abstract';
import Editor from 'mobiledoc-kit/editor/editor';
import MobiledocRenderer from 'mobiledoc-kit/renderers/mobiledoc/0-3';

function retargetPosition(position, fromPost, toPost) {
let sectionIndex;
let retargetedPosition;
fromPost.walkAllLeafSections((section,index) => {
if (sectionIndex !== undefined) { return; }
if (section === position.section) { sectionIndex = index; }
});
if (sectionIndex === undefined) {
throw new Error('`retargetPosition` could not find section index');
}
toPost.walkAllLeafSections((section, index) => {
if (retargetedPosition) { return; }
if (index === sectionIndex) {
retargetedPosition = section.toPosition(position.offset);
}
});
if (!retargetedPosition) {
throw new Error('`retargetPosition` could not find target section');
}
return retargetedPosition;
}

function retargetRange(range, toPost) {
let fromPost = range.head.section.post;
let newHead = retargetPosition(range.head, fromPost, toPost);
let newTail = retargetPosition(range.tail, fromPost, toPost);

return newHead.toRange(newTail);
}

function buildFromText(texts, editorOptions={}) {
let renderElement = editorOptions.element;
delete editorOptions.element;

let {post, range} = PostAbstractHelpers.buildFromText(texts);
let mobiledoc = MobiledocRenderer.render(post);
editorOptions.mobiledoc = mobiledoc;
let editor = new Editor(editorOptions);
if (renderElement) {
editor.render(renderElement);
range = retargetRange(range, editor.post);
editor.selectRange(range);
}
return editor;
}

export {
buildFromText,
retargetRange
};
2 changes: 2 additions & 0 deletions tests/test-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import wait from './helpers/wait';
import MockEditor from './helpers/mock-editor';
import renderBuiltAbstract from './helpers/render-built-abstract';
import run from './helpers/post-editor-run';
import EditorHelpers from './helpers/editor';

const { test:qunitTest, module, skip } = QUnit;

Expand Down Expand Up @@ -45,6 +46,7 @@ export default {
dom: DOMHelpers,
mobiledoc: MobiledocHelpers,
postAbstract: PostAbstract,
editor: EditorHelpers,
test,
module,
skipInIE11,
Expand Down
Loading

0 comments on commit a3d274d

Please sign in to comment.