You probably never asked yourself about it, but how complicated is the deletion of the selection in a markup-based Wysiwyg editor? In one single word: complicated.... I will try below to make you understand what a Wysiwyg markup-based editor does when you hit the delete key.

Let's take a simple example :

<h1>aa[aa</h1>
<ul>
<li>bbbb
   <ul>
     <li>cc]cc</li>
     <li>dddd</li>
   </ul>
</li>
<li>eeee</li>
</ul>

The selection is everything between the square brackets (included). Now the user hits the delete key. The natural algo for that is the following one (I'm not saying it's the only one; see DOMRange.extractContents to see another one):

  1. find all the "visible" nodes in the various ranges (here we have only one range) of the selection. A "visible" node is a text node or an empty element.
  2. split the start and end nodes of each range of the selection if necessary, for instance if these nodes are text nodes and the selection splits the nodes in two nodes of non-zero length.
  3. for each visible node in each range of the selection, remove the node and remove recursively all the parents if they are "removable". A "removable" parent is an empty element or, depending on its tag name, an element containing only text nodes made of whitespaces (/s in regexps); some elements are explicitely not "removable", body for instance.

This method is enough for the test case above and here's the expected result:

<h1>aa</h1>
<ul>
<li>
   <ul>
     <li>cc</li>
     <li>dddd</li>
   </ul>
 </li>
<li>eeee</li>
</ul>

But now imagine we have some markup that requires merging after the deletion of the selection. Here's one:

<ul>
<li>aaaa</li>
<li>bb[bb</li>
</ul>
<ul>
<li>cc]cc</li>
<li>dddd</li>
</ul>

What the user really expects here when the selection is deleted is the merging of the two ULs into one single list. We need then to improve a bit our algo above...

  1. find all the "visible" nodes in the various ranges (here we have only one range) of the selection. A "visible" node is a text node or an empty element.
  2. split the start and end nodes of each range of the selection if necessary, for instance if these nodes are text nodes and the selection splits the nodes in two nodes of non-zero length.
  3. traverse all ranges in our selection and preserve a list of all nodes traversed with the traversal direction (start, up, down, next)
Let's have an example here, and let's reuse the first example at the top of this article wih a h1 followed by a ul. The list of traversed nodes is then:
node
direction
"aa"
start
h1
up
ul
next
li
down
"bbbb"
down
ul
next
li
down
"cc"
down

For our examples of two adjacent lists, the list of traversed nodes is:

node
direction
"bb"
start
li
up
ul
up
ul
next
li
down
"cc"
down

But that's not all... There can be non-significant text nodes in the DOM between elements, like a carriage return between the two ULs. So to make sure we correctly merge during our deletion, the third step of our algo should be this one:

  1. for each node being an element and having a direction "next" in the list of traversed nodes above, find the previous "visible" sibling, discarding text nodes containing only white spaces if the element is a block. If the previous visible sibling is also an element and of same type than the reference node, and if these elements are "mergeable", then append all the children of the reference node to the previous visible node's children and delete the reference node. Two "mergeable" elements are for instance two paragraphs, or two h1 elements, or two dl elements; two inline text elements like span or strong are also mergable if

The rest of the algo is similar to what we did for the h1/ul example above:

  1. for each visible node in each range of the selection, remove the node and remove recursively all the parents if they are "removable". A "removable" parent is an empty element or, depending on its tag name, an element containing only text nodes made of whitespaces (/s in regexps); some elements are explicitelynot "removable", body for instance.
And then result is:
<ul>
<li>aaaa</li>
<li>bb</li>
<li>cc</li>
<li>dddd</li>
</ul>

Next time, we'll dive into some high-level functions like indentations or list creation.