diff --git a/spec/content.spec.js b/spec/content.spec.js index 56f584c09..c5f1b8ac7 100644 --- a/spec/content.spec.js +++ b/spec/content.spec.js @@ -50,6 +50,21 @@ describe('Content TestCase', function () { } }); + it('should cleanup after list is removed', function () { + this.el.innerHTML = ''; + var editor = this.newMediumEditor('.editor', { + toolbar: { + buttons: ['unorderedlist'] + } + }), + target = editor.elements[0].querySelector('li'), + toolbar = editor.getExtensionByName('toolbar'); + + selectElementContentsAndFire(target); + fireEvent(toolbar.getToolbarElement().querySelector('[data-action="insertunorderedlist"]'), 'click'); + expect(this.el.innerHTML).toBe('

lorem

'); + }); + describe('when the tab key is pressed', function () { it('should indent when within an
  • ', function () { this.el.innerHTML = '
    1. lorem
    2. ipsum
    '; diff --git a/src/js/core.js b/src/js/core.js index 9def0f452..d2b3a01a1 100644 --- a/src/js/core.js +++ b/src/js/core.js @@ -939,7 +939,7 @@ // do some DOM clean-up for known browser issues after the action if (action === 'insertunorderedlist' || action === 'insertorderedlist') { - MediumEditor.util.cleanListDOM(this.options.ownerDocument, this.getSelectedParentElement()); + MediumEditor.util.cleanListDOM(this.options.contentWindow, this.options.ownerDocument, this.getSelectedParentElement()); } this.checkSelection(); diff --git a/src/js/util.js b/src/js/util.js index c2bf06c45..92af85d1e 100644 --- a/src/js/util.js +++ b/src/js/util.js @@ -673,19 +673,58 @@ return false; }, - cleanListDOM: function (ownerDocument, element) { + cleanListDOM: function (contentWindow, ownerDocument, element) { if (element.nodeName.toLowerCase() !== 'li') { - return; - } + var selection = contentWindow.getSelection(), + newRange = ownerDocument.createRange(), + oldRange = selection.getRangeAt(0), + startContainer = oldRange.startContainer, + startOffset = oldRange.startOffset, + endContainer = oldRange.endContainer, + endOffset = oldRange.endOffset, + node, newNode, nextNode; + + if (element.nodeName.toLowerCase() === 'span') { + // Chrome unwraps removed li elements into a span + node = element; + } else { + // FF leaves them as text nodes + node = startContainer; + } + + while (node) { + if (node.nodeName.toLowerCase() !== 'span' && node.nodeName.toLowerCase() !== '#text') { + break; + } + + if (node.nextSibling && node.nextSibling.nodeName.toLowerCase() === 'br') { + node.nextSibling.remove(); + } + + nextNode = node.nextSibling; - var list = element.parentElement; + newNode = ownerDocument.createElement('p'); + node.parentNode.replaceChild(newNode, node); + newNode.appendChild(node); - if (list.parentElement.nodeName.toLowerCase() === 'p') { // yes we need to clean up - Util.unwrap(list.parentElement, ownerDocument); + node = nextNode; + } - // move cursor at the end of the text inside the list - // for some unknown reason, the cursor is moved to end of the "visual" line - MediumEditor.selection.moveCursor(ownerDocument, element.firstChild, element.firstChild.textContent.length); + // Restore selection + newRange.setStart(startContainer, startOffset); + newRange.setEnd(endContainer, endOffset); + selection.removeAllRanges(); + selection.addRange(newRange); + } else { + var list = element.parentElement; + + if (list.parentElement.nodeName.toLowerCase() === 'p') { // yes we need to clean up + Util.unwrap(list.parentElement, ownerDocument); + + // move cursor at the end of the text inside the list + // for some unknown reason, the cursor is moved to end of the "visual" line + MediumEditor.selection.moveCursor(ownerDocument, element.firstChild, element.firstChild.textContent.length); + } } },