Skip to content

Commit

Permalink
Render a last marker with trailing space using NO_BREAK_SPACE
Browse files Browse the repository at this point in the history
Fixes #68
  • Loading branch information
bantic committed Aug 12, 2015
1 parent c0a84a9 commit e1a5eda
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 4 deletions.
17 changes: 15 additions & 2 deletions src/js/renderers/editor-dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import { CARD_TYPE } from "../models/card";
import { clearChildNodes } from '../utils/dom-utils';

export const UNPRINTABLE_CHARACTER = "\u200C";
export const NO_BREAK_SPACE = "\u00A0";
const SPACE = ' ';

function createElementFromMarkup(doc, markup) {
var element = doc.createElement(markup.tagName);
Expand All @@ -20,6 +22,10 @@ function createElementFromMarkup(doc, markup) {
return element;
}

function endsWith(string, character) {
return string.charAt(string.length -1) === character;
}

// ascends from element upward, returning the last parent node that is not
// parentElement
function penultimateParentOf(element, parentElement) {
Expand All @@ -42,10 +48,10 @@ function isEmptyText(text) {
return text.trim() === '';
}

// pass in a renderNode's previousSibling
function getNextMarkerElement(renderNode) {
let element = renderNode.element.parentNode;
let closedCount = renderNode.postNode.closedMarkups.length;
let marker = renderNode.postNode;
let closedCount = marker.closedMarkups.length;

while (closedCount--) {
element = element.parentNode;
Expand All @@ -60,6 +66,13 @@ function renderMarker(marker, element, previousRenderNode) {
text = UNPRINTABLE_CHARACTER;
}

// If the textNode has a trailing space, the browser will collapse the
// displayed cursor position to the previous character
// See https://github.com/bustlelabs/content-kit-editor/issues/68
if (!marker.next && endsWith(text, SPACE)) {
text = text.substr(0, text.length - 1) + NO_BREAK_SPACE;
}

let textNode = document.createTextNode(text);
let currentElement = textNode;
let markup;
Expand Down
34 changes: 33 additions & 1 deletion tests/acceptance/editor-sections-test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Editor } from 'content-kit-editor';
import Helpers from '../test-helpers';
import { MOBILEDOC_VERSION } from 'content-kit-editor/renderers/mobiledoc';
import { UNPRINTABLE_CHARACTER } from 'content-kit-editor/renderers/editor-dom';
import {
UNPRINTABLE_CHARACTER,
NO_BREAK_SPACE
} from 'content-kit-editor/renderers/editor-dom';

const { test, module } = QUnit;

Expand Down Expand Up @@ -396,4 +399,33 @@ test('when selection incorrectly contains P start tag, editor reports correct se
});
});

test('deleting when after deletion there is a trailing space positions cursor at end of selection', (assert) => {
const done = assert.async();

editor = new Editor(editorElement, {mobiledoc: mobileDocWith2Sections});

let firstSectionTextNode = editor.element.childNodes[0].firstChild;
Helpers.dom.moveCursorTo(firstSectionTextNode, 'first section'.length);

let count = 'ection'.length;
while (count--) {
Helpers.dom.triggerDelete(editor);
}

assert.equal($('#editor p:eq(0)').text(), 'first s', 'precond - correct section text after initial deletions');

Helpers.dom.triggerDelete(editor);

assert.equal($('#editor p:eq(0)').text(), `first${NO_BREAK_SPACE}`, 'precond - correct text after deleting last char before space');

let text = 'e';
Helpers.dom.insertText(text);

setTimeout(() => {
assert.equal($('#editor p:eq(0)').text(), `first ${text}`, 'character is placed after space');

done();
});
});

// test: deleting at start of section when previous section is a non-markup section
7 changes: 6 additions & 1 deletion tests/helpers/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ function triggerEnter(editor) {
}
}

function insertText(string) {
document.execCommand('insertText', false, string);
}

const DOMHelper = {
moveCursorTo,
selectText,
Expand All @@ -167,7 +171,8 @@ const DOMHelper = {
getCursorPosition,
getSelectedText,
triggerDelete,
triggerEnter
triggerEnter,
insertText
};

export { triggerEvent };
Expand Down

0 comments on commit e1a5eda

Please sign in to comment.