diff --git a/MarkupEditor/Resources/markup.js b/MarkupEditor/Resources/markup.js index 6124793..4940e62 100644 --- a/MarkupEditor/Resources/markup.js +++ b/MarkupEditor/Resources/markup.js @@ -2850,10 +2850,10 @@ const _undoPasteHTML = function(undoerData) { if (_isEmptyPlaceholder(topLevelNode)) { topLevelNode.replaceWith(newEmptyElement); } else { - if (topLevelNode.nextSibling) { // We are at the end of the document + if (topLevelNode.nextSibling) { topLevelNode.parentNode.insertBefore(newEmptyElement, topLevelNode); - } else { - topLevelNode.parentNode.insertBefore(newEmptyElement, null); + } else { // We are at the end of the document + _findContentEditable(topLevelNode).insertBefore(newEmptyElement, null); }; }; newRange.setStart(newEmptyElement, 0); @@ -2970,10 +2970,7 @@ const _deleteRange = function(range, rootName) { endOffset = startOffset; }; } else if (trailingWasDeleted) { - //WAS: endLocation = _firstSelectableLocationBefore(trailingNode) ?? _firstSelectableLocationAfter(trailingNode); - //NOW: - //endLocation = _firstSelectableLocationAfter(trailingNode) ?? _firstSelectableLocationBefore(trailingNode); if (endLocation) { endContainer = endLocation.container; endOffset = endLocation.offset; @@ -3018,9 +3015,9 @@ const _deleteRange = function(range, rootName) { const topLevelNode = _topLevelElementContaining(trailingNode); if (topLevelNode && _isEmpty(topLevelNode)) { // We are left with an empty top-level node (like a table or p), so delete it. - // If it's a table, then we treat it specially, because the selection was inside - // of the table and should be left before it. - if (_isTableElement(topLevelNode)) { + // If it's a table, list, or blockquote, then we treat it specially, because + // the selection was inside of the topLevelElement and should be left before it. + if (_isTableElement(topLevelNode) || _isListElement(topLevelNode) || _isBlockquoteElement(topLevelNode)) { _deleteAndResetSelection(topLevelNode, 'BEFORE'); } else { _deleteAndResetSelection(topLevelNode, 'AFTER'); @@ -7546,8 +7543,7 @@ const _monitorEnterTags = _listTags.concat(['TABLE', 'BLOCKQUOTE']); const _monitorIndentTags = _listTags.concat(['BLOCKQUOTE']); // Tags we monitor for Tab or Ctrl+] -//TODO: Include BLOCKQUOTE? -const _topLevelTags = _paragraphStyleTags.concat(_listTags.concat(['TABLE', 'BLOCKQUOTE'])); // Allowed top-level tags within editor +const _topLevelTags = _paragraphStyleTags.concat(_listTags.concat(['TABLE', 'BLOCKQUOTE'])); // Allowed top-level tags w/in editor const _voidTags = ['BR', 'IMG', 'AREA', 'COL', 'EMBED', 'HR', 'INPUT', 'LINK', 'META', 'PARAM'] // Tags that are self-closing diff --git a/MarkupEditorTests/BasicTests/BasicTests.swift b/MarkupEditorTests/BasicTests/BasicTests.swift index 206e735..64d7fc6 100644 --- a/MarkupEditorTests/BasicTests/BasicTests.swift +++ b/MarkupEditorTests/BasicTests/BasicTests.swift @@ -2916,6 +2916,7 @@ class BasicTests: XCTestCase, MarkupDelegate { endOffset: 0, pasteString: "

A title

A subtitle

A paragraph.

" ), + // Tables HtmlTest( description: "TABLE in P - Paste a table at a blank paragraph", startHtml: "

This is just a simple paragraph.


", @@ -2976,6 +2977,128 @@ class BasicTests: XCTestCase, MarkupDelegate { endOffset: 0, pasteString: "

Hello world

" ), + // Lists + HtmlTest( + description: "OL in P - Paste a list at a blank paragraph", + startHtml: "

This is just a simple paragraph.


", + endHtml: "

This is just a simple paragraph.

  1. Item 1

  2. Item 2

", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list at beginning of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "
  1. Item 1

  2. Item 2

This is just a simple paragraph.

", + startId: "p", // Select "|This" + startOffset: 0, + endId: "p", + endOffset: 0, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list at end of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is just a simple paragraph.

  1. Item 1

  2. Item 2

", + startId: "p", // Select "paragraph.|" + startOffset: 32, + endId: "p", + endOffset: 32, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list in text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

  1. Item 1

  2. Item 2

st a simple paragraph.

", + startId: "p", // Select "ju|st" + startOffset: 10, + endId: "p", + endOffset: 10, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list in formatted text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

  1. Item 1

  2. Item 2

st a simple paragraph.

", + startId: "b", // Select "ju|st" + startOffset: 2, + endId: "b", + endOffset: 2, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "P in P - Paste a simple paragraph at a blank line after a list", + startHtml: "
  1. Item 1

  2. Item 2


", + endHtml: "
  1. Item 1

  2. Item 2

Hello world

", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "

Hello world

" + ), + // Blockquotes + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE at a blank paragraph", + startHtml: "

This is just a simple paragraph.


", + endHtml: "

This is just a simple paragraph.

Double-indented.
", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE at beginning of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "
Double-indented.

This is just a simple paragraph.

", + startId: "p", // Select "|This" + startOffset: 0, + endId: "p", + endOffset: 0, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE at end of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is just a simple paragraph.

Double-indented.
", + startId: "p", // Select "paragraph.|" + startOffset: 32, + endId: "p", + endOffset: 32, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE in text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

Double-indented.

st a simple paragraph.

", + startId: "p", // Select "ju|st" + startOffset: 10, + endId: "p", + endOffset: 10, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE in formatted text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

Double-indented.

st a simple paragraph.

", + startId: "b", // Select "ju|st" + startOffset: 2, + endId: "b", + endOffset: 2, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "P in P - Paste a simple paragraph at a blank line after a BLOCKQUOTE", + startHtml: "
Double-indented.


", + endHtml: "
Double-indented.

Hello world

", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "

Hello world

" + ), ] for test in htmlTests { test.printDescription() diff --git a/MarkupEditorTests/RedoTests/RedoTests.swift b/MarkupEditorTests/RedoTests/RedoTests.swift index 041a14a..2488f1e 100644 --- a/MarkupEditorTests/RedoTests/RedoTests.swift +++ b/MarkupEditorTests/RedoTests/RedoTests.swift @@ -2859,6 +2859,7 @@ class RedoTests: XCTestCase, MarkupDelegate { endOffset: 0, pasteString: "

A title

A subtitle

A paragraph.

" ), + // Tables HtmlTest( description: "TABLE in P - Paste a table at a blank paragraph", startHtml: "

This is just a simple paragraph.


", @@ -2921,6 +2922,132 @@ class RedoTests: XCTestCase, MarkupDelegate { endOffset: 0, pasteString: "

Hello world

" ), + // Lists + HtmlTest( + description: "OL in P - Paste a list at a blank paragraph", + startHtml: "

This is just a simple paragraph.


", + endHtml: "

This is just a simple paragraph.

  1. Item 1

  2. Item 2

", + undoHtml: "

This is just a simple paragraph.


", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list at beginning of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "
  1. Item 1

  2. Item 2

This is just a simple paragraph.

", + startId: "p", // Select "|This" + startOffset: 0, + endId: "p", + endOffset: 0, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list at end of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is just a simple paragraph.

  1. Item 1

  2. Item 2

", + startId: "p", // Select "paragraph.|" + startOffset: 32, + endId: "p", + endOffset: 32, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list in text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

  1. Item 1

  2. Item 2

st a simple paragraph.

", + startId: "p", // Select "ju|st" + startOffset: 10, + endId: "p", + endOffset: 10, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list in formatted text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

  1. Item 1

  2. Item 2

st a simple paragraph.

", + startId: "b", // Select "ju|st" + startOffset: 2, + endId: "b", + endOffset: 2, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "P in P - Paste a simple paragraph at a blank line after a list", + startHtml: "
  1. Item 1

  2. Item 2


", + endHtml: "
  1. Item 1

  2. Item 2

Hello world

", + undoHtml: "
  1. Item 1

  2. Item 2


", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "

Hello world

" + ), + // Blockquotes + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE at a blank paragraph", + startHtml: "

This is just a simple paragraph.


", + endHtml: "

This is just a simple paragraph.

Double-indented.
", + undoHtml: "

This is just a simple paragraph.


", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE at beginning of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "
Double-indented.

This is just a simple paragraph.

", + startId: "p", // Select "|This" + startOffset: 0, + endId: "p", + endOffset: 0, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE at end of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is just a simple paragraph.

Double-indented.
", + startId: "p", // Select "paragraph.|" + startOffset: 32, + endId: "p", + endOffset: 32, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE in text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

Double-indented.

st a simple paragraph.

", + startId: "p", // Select "ju|st" + startOffset: 10, + endId: "p", + endOffset: 10, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE in formatted text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

Double-indented.

st a simple paragraph.

", + startId: "b", // Select "ju|st" + startOffset: 2, + endId: "b", + endOffset: 2, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "P in P - Paste a simple paragraph at a blank line after a BLOCKQUOTE", + startHtml: "
Double-indented.


", + endHtml: "
Double-indented.

Hello world

", + undoHtml: "
Double-indented.


", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "

Hello world

" + ), ] for test in htmlTests { test.printDescription() diff --git a/MarkupEditorTests/UndoTests/UndoTests.swift b/MarkupEditorTests/UndoTests/UndoTests.swift index 80f157e..90181bb 100644 --- a/MarkupEditorTests/UndoTests/UndoTests.swift +++ b/MarkupEditorTests/UndoTests/UndoTests.swift @@ -2625,6 +2625,7 @@ class UndoTests: XCTestCase, MarkupDelegate { endOffset: 0, pasteString: "

A title

A subtitle

A paragraph.

" ), + // Tables HtmlTest( description: "TABLE in P - Paste a table at a blank paragraph", startHtml: "

This is just a simple paragraph.


", @@ -2687,6 +2688,132 @@ class UndoTests: XCTestCase, MarkupDelegate { endOffset: 0, pasteString: "

Hello world

" ), + // Lists + HtmlTest( + description: "OL in P - Paste a list at a blank paragraph", + startHtml: "

This is just a simple paragraph.


", + endHtml: "

This is just a simple paragraph.

  1. Item 1

  2. Item 2

", + undoHtml: "

This is just a simple paragraph.


", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list at beginning of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "
  1. Item 1

  2. Item 2

This is just a simple paragraph.

", + startId: "p", // Select "|This" + startOffset: 0, + endId: "p", + endOffset: 0, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list at end of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is just a simple paragraph.

  1. Item 1

  2. Item 2

", + startId: "p", // Select "paragraph.|" + startOffset: 32, + endId: "p", + endOffset: 32, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list in text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

  1. Item 1

  2. Item 2

st a simple paragraph.

", + startId: "p", // Select "ju|st" + startOffset: 10, + endId: "p", + endOffset: 10, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "OL in P - Paste a list in formatted text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

  1. Item 1

  2. Item 2

st a simple paragraph.

", + startId: "b", // Select "ju|st" + startOffset: 2, + endId: "b", + endOffset: 2, + pasteString: "
  1. Item 1

  2. Item 2

" + ), + HtmlTest( + description: "P in P - Paste a simple paragraph at a blank line after a list", + startHtml: "
  1. Item 1

  2. Item 2


", + endHtml: "
  1. Item 1

  2. Item 2

Hello world

", + undoHtml: "
  1. Item 1

  2. Item 2


", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "

Hello world

" + ), + // Blockquotes + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE at a blank paragraph", + startHtml: "

This is just a simple paragraph.


", + endHtml: "

This is just a simple paragraph.

Double-indented.
", + undoHtml: "

This is just a simple paragraph.


", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE at beginning of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "
Double-indented.

This is just a simple paragraph.

", + startId: "p", // Select "|This" + startOffset: 0, + endId: "p", + endOffset: 0, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE at end of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is just a simple paragraph.

Double-indented.
", + startId: "p", // Select "paragraph.|" + startOffset: 32, + endId: "p", + endOffset: 32, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE in text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

Double-indented.

st a simple paragraph.

", + startId: "p", // Select "ju|st" + startOffset: 10, + endId: "p", + endOffset: 10, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "BLOCKQUOTE in P - Paste a BLOCKQUOTE in formatted text of a paragraph", + startHtml: "

This is just a simple paragraph.

", + endHtml: "

This is ju

Double-indented.

st a simple paragraph.

", + startId: "b", // Select "ju|st" + startOffset: 2, + endId: "b", + endOffset: 2, + pasteString: "
Double-indented.
" + ), + HtmlTest( + description: "P in P - Paste a simple paragraph at a blank line after a BLOCKQUOTE", + startHtml: "
Double-indented.


", + endHtml: "
Double-indented.

Hello world

", + undoHtml: "
Double-indented.


", + startId: "blank", // Select "|
" + startOffset: 0, + endId: "blank", + endOffset: 0, + pasteString: "

Hello world

" + ), ] for test in htmlTests { test.printDescription()