From e1a5edaff7e1a6e59e7aa64ff7c4b305ba96a941 Mon Sep 17 00:00:00 2001 From: Cory Forsyth Date: Wed, 12 Aug 2015 13:38:50 -0400 Subject: [PATCH] Render a last marker with trailing space using NO_BREAK_SPACE Fixes #68 --- src/js/renderers/editor-dom.js | 17 ++++++++++-- tests/acceptance/editor-sections-test.js | 34 +++++++++++++++++++++++- tests/helpers/dom.js | 7 ++++- 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/js/renderers/editor-dom.js b/src/js/renderers/editor-dom.js index 6b67fd601..0906624e4 100644 --- a/src/js/renderers/editor-dom.js +++ b/src/js/renderers/editor-dom.js @@ -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); @@ -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) { @@ -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; @@ -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; diff --git a/tests/acceptance/editor-sections-test.js b/tests/acceptance/editor-sections-test.js index 52f8d704c..1df209dec 100644 --- a/tests/acceptance/editor-sections-test.js +++ b/tests/acceptance/editor-sections-test.js @@ -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; @@ -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 diff --git a/tests/helpers/dom.js b/tests/helpers/dom.js index 3df9acc48..42632d004 100644 --- a/tests/helpers/dom.js +++ b/tests/helpers/dom.js @@ -156,6 +156,10 @@ function triggerEnter(editor) { } } +function insertText(string) { + document.execCommand('insertText', false, string); +} + const DOMHelper = { moveCursorTo, selectText, @@ -167,7 +171,8 @@ const DOMHelper = { getCursorPosition, getSelectedText, triggerDelete, - triggerEnter + triggerEnter, + insertText }; export { triggerEvent };