--- a/editcommands.html Tue Jul 05 12:06:30 2011 -0600
+++ b/editcommands.html Tue Jul 05 14:00:32 2011 -0600
@@ -3410,72 +3410,131 @@
<p>To <dfn id=canonicalize-whitespace>canonicalize whitespace</dfn> at (<var title="">node</var>,
<var title="">offset</var>):
-<p class=XXX>This algorithm fails in all kinds of common cases, like any
-non-text node, or whitespace that spans multiple text nodes. Needs lots of
-fixing.
-
<ol>
- <li>If <var title="">node</var> is not a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node, or is not
- <a href=#editable>editable</a>, or its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>'s <a href=http://www.w3.org/TR/CSS21/cascade.html#computed-value>computed value</a> for "white-space" is
- "pre" or "pre-wrap", abort these steps.
+ <li>If <var title="">node</var> is neither <a href=#editable>editable</a> nor an <a href=#editing-host>editing
+ host</a>, abort these steps.
+
+ <li>Let <var title="">start node</var> equal <var title="">node</var> and let <var title="">start
+ offset</var> equal <var title="">offset</var>.
<!-- First go to the beginning of the current whitespace run. -->
- <li>Let <var title="">start offset</var> equal <var title="">offset</var>.
-
- <li>While <var title="">start offset</var> is positive and the (<var title="">start
- offset</var> − 1)st <a href=http://es5.github.com/#x8.4>element</a> of <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> is a
- space (0x0020) or non-breaking space (0x00A0), subtract one from <var title="">start
- offset</var>.
+ <li>Repeat the following steps:
+
+ <ol>
+ <li>If <var title="">start node</var> has a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> <a href=#in-the-same-editing-host>in the same editing
+ host</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start offset</var> minus one, set
+ <var title="">start node</var> to that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, then set <var title="">start offset</var>
+ to <var title="">start node</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a>.
+
+ <li>Otherwise, if <var title="">start offset</var> is zero and <var title="">start node</var>
+ does not <a href=#follows-a-line-break title="follows a line break">follow a line break</a> and
+ <var title="">start node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is <a href=#in-the-same-editing-host>in the same editing
+ host</a>, set <var title="">start offset</var> to <var title="">start node</var>'s
+ <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a>, then set <var title="">start node</var> to its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
+
+ <p class=XXX>Following a line break is unlikely to be the right criterion.
+
+ <li>Otherwise, if <var title="">start node</var> is a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node and its
+ <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>'s <a href=http://www.w3.org/TR/CSS21/cascade.html#computed-value>computed value</a> for "white-space" is neither "pre" nor "pre-wrap"
+ and <var title="">start offset</var> is not zero and the (<var title="">start offset</var>
+ − 1)st <a href=http://es5.github.com/#x8.4>element</a> of <var title="">start node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> is a space
+ (0x0020) or non-breaking space (0x00A0), subtract one from <var title="">start
+ offset</var>.
+
+ <li>Otherwise, break from this loop.
+ </ol>
<!-- Now collapse any consecutive spaces. -->
- <li>Let <var title="">end offset</var> equal <var title="">start offset</var>.
-
- <li>While <var title="">end offset</var> is less than <var title="">node</var>'s <a href=http://es5.github.com/#x15.5.5.1>length</a>,
- and the <var title="">end offset</var>th <a href=http://es5.github.com/#x8.4>element</a> of <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> is
- 0x0020 or 0x00A0:
+ <li>Let <var title="">end node</var> equal <var title="">start node</var> and <var title="">end
+ offset</var> equal <var title="">start offset</var>.
+
+ <li>Let <var title="">length</var> equal zero.
+
+ <li>Let <var title="">follows space</var> be false.
+
+ <li>Repeat the following steps:
<ol>
- <li>Let <var title="">length</var> equal zero.
-
- <li>While <var title="">end offset</var> plus <var title="">length</var> is less than
- <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-length><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-length>length</a></code>, and the (<var title="">end offset</var> +
- <var title="">length</var>)th <a href=http://es5.github.com/#x8.4>element</a> of <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> is 0x0020,
- add one to <var title="">length</var>.
-
- <li>If <var title="">length</var> is greater than one, call <code class=external data-anolis-spec=domcore title=dom-CharacterData-deleteData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-deletedata>deleteData(<var title="">end
- offset</var> + 1, <var title="">length</var> − 1)</a></code> on <var title="">node</var>.
-
- <li>Add one to <var title="">end offset</var>.
+ <li>If <var title="">end node</var> has a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> <a href=#in-the-same-editing-host>in the same editing
+ host</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">end offset</var>, set <var title="">end node</var>
+ to that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, then set <var title="">end offset</var> to zero.
+
+ <li>Otherwise, if <var title="">end offset</var> is <var title="">end node</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a>
+ and <var title="">end node</var> does not <a href=#precedes-a-line-break title="precedes a line
+ break">precede a line break</a> and <var title="">end node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is
+ <a href=#in-the-same-editing-host>in the same editing host</a>, set <var title="">end offset</var> to one
+ plus <var title="">end node</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a>, then set <var title="">end node</var> to its
+ <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
+
+ <p class=XXX>Preceding a line break is unlikely to be the right criterion.
+
+ <li>Otherwise, if <var title="">end node</var> is a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node and its
+ <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>'s <a href=http://www.w3.org/TR/CSS21/cascade.html#computed-value>computed value</a> for "white-space" is neither "pre" nor "pre-wrap"
+ and <var title="">end offset</var> is not <var title="">end node</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> and the
+ <var title="">end offset</var>th <a href=http://es5.github.com/#x8.4>element</a> of <var title="">end node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> is a
+ space (0x0020) or non-breaking space (0x00A0):
+
+ <ol>
+ <li>If <var title="">follows space</var> is true and the <var title="">end offset</var>th
+ <a href=http://es5.github.com/#x8.4>element</a> of <var title="">end node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> is a space (0x0020), call
+ <code class=external data-anolis-spec=domcore title=dom-CharacterData-deleteData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-deletedata>deleteData(<var title="">end offset</var>, 1)</a></code> on <var title="">end node</var>, then
+ continue this loop from the beginning.
+
+ <li>Set <var title="">follows space</var> to true if the <var title="">end offset</var>th
+ <a href=http://es5.github.com/#x8.4>element</a> of <var title="">end node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code> is a space (0x0020), false
+ otherwise.
+
+ <li>Add one to <var title="">end offset</var>.
+
+ <li>Add one to <var title="">length</var>.
+ </ol>
+
+ <li>Otherwise, break from this loop.
</ol>
<!-- Now replace with the canonical sequence. -->
<li>Let <var title="">replacement whitespace</var> be the <a href=#canonical-space-sequence>canonical space
- sequence</a> of length <var title="">end offset</var> minus <var title="">start
- offset</var>. <var title="">non-breaking start</var> is true if <var title="">start
- offset</var> is zero and false otherwise, and <var title="">non-breaking end</var> is
- true if <var title="">end offset</var> is <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-length><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-length>length</a></code> and false
- otherwise.
-
- <li>While <var title="">start offset</var> is less than <var title="">end offset</var>:
+ sequence</a> of length <var title="">length</var>. <var title="">non-breaking start</var>
+ is true if <var title="">start offset</var> is zero and <var title="">start node</var>
+ <a href=#follows-a-line-break>follows a line break</a>, and false otherwise. <var title="">non-breaking
+ end</var> is true if <var title="">end offset</var> is <var title="">end node</var>'s
+ <code class=external data-anolis-spec=domcore title=dom-CharacterData-length><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-length>length</a></code> and <var title="">end node</var> <a href=#precedes-a-line-break>precedes a line break</a>, and
+ false otherwise.
+
+ <li>While (<var title="">start node</var>, <var title="">start offset</var>) is <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-bp-before title=concept-bp-before>before</a>
+ (<var title="">end node</var>, <var title="">end offset</var>):
<ol>
- <li>Remove the first <a href=http://es5.github.com/#x8.4>element</a> from <var title="">replacement whitespace</var>, and
- let <var title="">element</var> be that <a href=http://es5.github.com/#x8.4>element</a>.
-
- <li>If <var title="">element</var> is not the same as the <var title="">start offset</var>th
- <a href=http://es5.github.com/#x8.4>element</a> of <var title="">node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code>:
+ <li>If <var title="">start node</var> has a <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> <var title="">start
+ offset</var>, set <var title="">start node</var> to that <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, then set
+ <var title="">start offset</var> to zero.
+
+ <li>Otherwise, if <var title="">start node</var> is not a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node or if
+ <var title="">start offset</var> is <var title="">start node</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a>, set
+ <var title="">start offset</var> to one plus <var title="">start node</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a>, then
+ set <var title="">start node</var> to its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
+
+ <li>Otherwise:
<ol>
- <!-- We need to insert then delete, so that we don't change range
- boundary points. -->
- <li>Call <code class=external data-anolis-spec=domcore title=dom-CharacterData-insertData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-insertdata>insertData(<var title="">start offset</var>, <var title="">element</var>)</a></code> on
- <var title="">node</var>.
-
- <li>Call <code class=external data-anolis-spec=domcore title=dom-CharacterData-deleteData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-deletedata>deleteData(<var title="">start offset</var> + 1, 1)</a></code> on
- <var title="">node</var>.
+ <li>Remove the first <a href=http://es5.github.com/#x8.4>element</a> from <var title="">replacement whitespace</var>,
+ and let <var title="">element</var> be that <a href=http://es5.github.com/#x8.4>element</a>.
+
+ <li>If <var title="">element</var> is not the same as the <var title="">start
+ offset</var>th <a href=http://es5.github.com/#x8.4>element</a> of <var title="">start node</var>'s <code class=external data-anolis-spec=domcore title=dom-CharacterData-data><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-data>data</a></code>:
+
+ <ol>
+ <!-- We need to insert then delete, so that we don't change range
+ boundary points. -->
+ <li>Call <code class=external data-anolis-spec=domcore title=dom-CharacterData-insertData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-insertdata>insertData(<var title="">start offset</var>, <var title="">element</var>)</a></code> on
+ <var title="">start node</var>.
+
+ <li>Call <code class=external data-anolis-spec=domcore title=dom-CharacterData-deleteData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-deletedata>deleteData(<var title="">start offset</var> + 1, 1)</a></code> on
+ <var title="">start node</var>.
+ </ol>
+
+ <li>Add one to <var title="">start offset</var>.
</ol>
-
- <li>Add one to <var title="">start offset</var>.
</ol>
</ol>
@@ -3908,58 +3967,61 @@
<li><a href=#canonicalize-whitespace>Canonicalize whitespace</a> at (<var title="">start node</var>,
<var title="">start offset</var>).
+
+ <li>Set <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> to its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>.
+
+ <li>Abort these steps.
</ol>
- <li>Otherwise:
+ <li>If <var title="">start node</var> is an <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node, call
+ <code class=external data-anolis-spec=domcore title=dom-CharacterData-deleteData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-deletedata>deleteData()</a></code> on it, with <var title="">start offset</var> as the first argument and
+ (<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of <var title="">start node</var> − <var title="">start offset</var>) as
+ the second argument.
+
+ <li>Let <var title="">node list</var> be a list of <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a>, initially empty.
+
+ <li>For each <var title="">node</var> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">range</var>, append
+ <var title="">node</var> to <var title="">node list</var> if the last member of <var title="">node
+ list</var> (if any) is not an <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-ancestor title=concept-tree-ancestor>ancestor</a> of <var title="">node</var>;
+ <var title="">node</var> is <a href=#editable>editable</a>; and <var title="">node</var> is not a
+ <code class=external data-anolis-spec=html title="the thead element"><a href=http://www.whatwg.org/html/#the-thead-element>thead</a></code>, <code class=external data-anolis-spec=html title="the tbody element"><a href=http://www.whatwg.org/html/#the-tbody-element>tbody</a></code>, <code class=external data-anolis-spec=html title="the tfoot element"><a href=http://www.whatwg.org/html/#the-tfoot-element>tfoot</a></code>, <code class=external data-anolis-spec=html title="the tr element"><a href=http://www.whatwg.org/html/#the-tr-element>tr</a></code>, <code class=external data-anolis-spec=html title="the th element"><a href=http://www.whatwg.org/html/#the-th-element>th</a></code>, or <code class=external data-anolis-spec=html title="the td element"><a href=http://www.whatwg.org/html/#the-td-element>td</a></code>.
+ <!--
+ IE9 doesn't seem to let you do any intercell deletions: the delete key does
+ nothing if you select across multiple cells. Firefox 5.0a2 and Opera 11.11
+ behave as the spec says, not removing any table things. Chrome 13 dev will
+ remove entire rows if selected. Note that IE, Firefox, Word 2007, and
+ OpenOffice.org 3.2.1 Ubuntu all switch to a magic cell-selection mode when
+ you try to select between cells, at least in some cases, instead of selecting
+ letter-by-letter.
+ -->
+
+ <li>For each <var title="">node</var> in <var title="">node list</var>:
<ol>
- <li>If <var title="">start node</var> is an <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node,
- call <code class=external data-anolis-spec=domcore title=dom-CharacterData-deleteData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-deletedata>deleteData()</a></code> on it, with <var title="">start offset</var> as the first
- argument and (<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of <var title="">start node</var> − <var title="">start
- offset</var>) as the second argument. Then <a href=#canonicalize-whitespace>canonicalize
- whitespace</a> at (<var title="">start node</var>, <var title="">start offset</var>).
-
- <li>Let <var title="">node list</var> be a list of <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a>, initially empty.
-
- <li>For each <var title="">node</var> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">range</var>, append
- <var title="">node</var> to <var title="">node list</var> if the last member of <var title="">node
- list</var> (if any) is not an <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-ancestor title=concept-tree-ancestor>ancestor</a> of <var title="">node</var>;
- <var title="">node</var> is <a href=#editable>editable</a>; and <var title="">node</var> is not a
- <code class=external data-anolis-spec=html title="the thead element"><a href=http://www.whatwg.org/html/#the-thead-element>thead</a></code>, <code class=external data-anolis-spec=html title="the tbody element"><a href=http://www.whatwg.org/html/#the-tbody-element>tbody</a></code>, <code class=external data-anolis-spec=html title="the tfoot element"><a href=http://www.whatwg.org/html/#the-tfoot-element>tfoot</a></code>, <code class=external data-anolis-spec=html title="the tr element"><a href=http://www.whatwg.org/html/#the-tr-element>tr</a></code>, <code class=external data-anolis-spec=html title="the th element"><a href=http://www.whatwg.org/html/#the-th-element>th</a></code>, or <code class=external data-anolis-spec=html title="the td element"><a href=http://www.whatwg.org/html/#the-td-element>td</a></code>.
- <!--
- IE9 doesn't seem to let you do any intercell deletions: the delete key does
- nothing if you select across multiple cells. Firefox 5.0a2 and Opera 11.11
- behave as the spec says, not removing any table things. Chrome 13 dev will
- remove entire rows if selected. Note that IE, Firefox, Word 2007, and
- OpenOffice.org 3.2.1 Ubuntu all switch to a magic cell-selection mode when
- you try to select between cells, at least in some cases, instead of
- selecting letter-by-letter.
- -->
-
- <li>For each <var title="">node</var> in <var title="">node list</var>:
-
- <ol>
- <li>Let <var title="">parent</var> be the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of <var title="">node</var>.
-
- <li>Remove <var title="">node</var> from <var title="">parent</var>.
-
- <li>While <var title="">parent</var> is an <a href=#editable>editable</a> <a href=#inline-node>inline
- node</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> 0, let <var title="">grandparent</var> be the
- <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of <var title="">parent</var>, then remove <var title="">parent</var> from
- <var title="">grandparent</var>, then set <var title="">parent</var> to
- <var title="">grandparent</var>.
-
- <li>If <var title="">parent</var> is <a href=#editable>editable</a> or an <a href=#editing-host>editing
- host</a>, is not an <a href=#inline-node>inline node</a>, and has no <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a>,
- call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a> and append the
- result as the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">parent</var>.
- </ol>
-
- <li>If <var title="">end node</var> is an <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node, call
- <code class=external data-anolis-spec=domcore title=dom-CharacterData-deleteData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-deletedata>deleteData(0, <var title="">end offset</var>)</a></code> on it, then <a href=#canonicalize-whitespace>canonicalize
- whitespace</a> at (<var title="">end node</var>, 0).
+ <li>Let <var title="">parent</var> be the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of <var title="">node</var>.
+
+ <li>Remove <var title="">node</var> from <var title="">parent</var>.
+
+ <li>While <var title="">parent</var> is an <a href=#editable>editable</a> <a href=#inline-node>inline
+ node</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> 0, let <var title="">grandparent</var> be the
+ <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of <var title="">parent</var>, then remove <var title="">parent</var> from
+ <var title="">grandparent</var>, then set <var title="">parent</var> to
+ <var title="">grandparent</var>.
+
+ <li>If <var title="">parent</var> is <a href=#editable>editable</a> or an <a href=#editing-host>editing
+ host</a>, is not an <a href=#inline-node>inline node</a>, and has no <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a>,
+ call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("br")</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a> and append the result
+ as the last <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of <var title="">parent</var>.
</ol>
+ <li>If <var title="">end node</var> is an <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node, call
+ <code class=external data-anolis-spec=domcore title=dom-CharacterData-deleteData><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-characterdata-deletedata>deleteData(0, <var title="">end offset</var>)</a></code> on it.
+
+ <li><a href=#canonicalize-whitespace>Canonicalize whitespace</a> at <var title="">range</var>'s
+ <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>.
+
+ <li><a href=#canonicalize-whitespace>Canonicalize whitespace</a> at <var title="">range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a>.
+
<!--
Now we need to merge blocks. The simplest case is something like
@@ -6456,9 +6518,8 @@
<li>Call <code class=external data-anolis-spec=domrange title=dom-Range-insertNode><a href=http://html5.org/specs/dom-range.html#dom-range-insertnode>insertNode(<var title="">text</var>)</a></code> on the <a href=#active-range>active range</a>.
- <li>Call <code class=external data-anolis-spec=domrange title=dom-Selection-collapse><a href=http://html5.org/specs/dom-range.html#dom-selection-collapse>collapse(<var title="">text</var>, <var title="">length</var>)</a></code> on the
- <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>'s <code class=external data-anolis-spec=domrange><a href=http://html5.org/specs/dom-range.html#selection>Selection</a></code>, where <var title="">length</var> is the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a>
- of <var title="">text</var>.
+ <li>Call <code class=external data-anolis-spec=domrange title=dom-Selection-collapse><a href=http://html5.org/specs/dom-range.html#dom-selection-collapse>collapse(<var title="">text</var>, 1)</a></code> on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>'s
+ <code class=external data-anolis-spec=domrange><a href=http://html5.org/specs/dom-range.html#selection>Selection</a></code>.
</ol>
--- a/implementation.js Tue Jul 05 12:06:30 2011 -0600
+++ b/implementation.js Tue Jul 05 14:00:32 2011 -0600
@@ -3701,81 +3701,159 @@
}
function canonicalizeWhitespace(node, offset) {
- // "If node is not a Text node, or is not editable, or its parent's
- // computed value for "white-space" is "pre" or "pre-wrap", abort these
- // steps."
- if (node.nodeType != Node.TEXT_NODE
- || !isEditable(node)
- || ["pre", "pre-wrap"].indexOf(getComputedStyle(node.parentNode).whiteSpace) != -1) {
+ // "If node is neither editable nor an editing host, abort these steps."
+ if (!isEditable(node) && !isEditingHost(node)) {
return;
}
- // "Let start offset equal offset."
+ // "Let start node equal node and let start offset equal offset."
+ var startNode = node;
var startOffset = offset;
- // "While start offset is positive and the (start offset − 1)st element of
- // node's data is a space (0x0020) or non-breaking space (0x00A0), subtract
- // one from start offset."
- while (startOffset > 0
- && /[ \xa0]/.test(node.data[startOffset - 1])) {
- startOffset--;
- }
-
- // "Let end offset equal start offset."
+ // "Repeat the following steps:"
+ while (true) {
+ // "If start node has a child in the same editing host with index start
+ // offset minus one, set start node to that child, then set start
+ // offset to start node's length."
+ if (0 <= startOffset - 1
+ && inSameEditingHost(startNode, startNode.childNodes[startOffset - 1])) {
+ startNode = startNode.childNodes[startOffset - 1];
+ startOffset = getNodeLength(startNode);
+
+ // "Otherwise, if start offset is zero and start node does not follow a
+ // line break and start node's parent is in the same editing host, set
+ // start offset to start node's index, then set start node to its
+ // parent."
+ } else if (startOffset == 0
+ && !followsLineBreak(startNode)
+ && inSameEditingHost(startNode, startNode.parentNode)) {
+ startOffset = getNodeIndex(startNode);
+ startNode = startNode.parentNode;
+
+ // "Otherwise, if start node is a Text node and its parent's computed
+ // value for "white-space" is neither "pre" nor "pre-wrap" and start
+ // offset is not zero and the (start offset − 1)st element of start
+ // node's data is a space (0x0020) or non-breaking space (0x00A0),
+ // subtract one from start offset."
+ } else if (startNode.nodeType == Node.TEXT_NODE
+ && ["pre", "pre-wrap"].indexOf(getComputedStyle(startNode.parentNode).whiteSpace) == -1
+ && startOffset != 0
+ && /[ \xa0]/.test(startNode.data[startOffset - 1])) {
+ startOffset--;
+
+ // "Otherwise, break from this loop."
+ } else {
+ break;
+ }
+ }
+
+ // "Let end node equal start node and end offset equal start offset."
+ var endNode = startNode;
var endOffset = startOffset;
- // "While end offset is less than node's length, and the end offsetth
- // element of node's data is 0x0020 or 0x00A0:"
- while (endOffset < node.length
- && /[ \xa0]/.test(node.data[endOffset])) {
- // "Let length equal zero."
- var length = 0;
-
- // "While end offset plus length is less than node's length, and the
- // (end offset + length)th element of node's data is 0x0020, add one to
- // length."
- while (endOffset + length < node.length
- && node.data[endOffset + length] == " ") {
+ // "Let length equal zero."
+ var length = 0;
+
+ // "Let follows space be false."
+ var followsSpace = false;
+
+ // "Repeat the following steps:"
+ while (true) {
+ // "If end node has a child in the same editing host with index end
+ // offset, set end node to that child, then set end offset to zero."
+ if (endOffset < endNode.childNodes.length
+ && inSameEditingHost(endNode, endNode.childNodes[endOffset])) {
+ endNode = endNode.childNodes[endOffset];
+ endOffset = 0;
+
+ // "Otherwise, if end offset is end node's length and end node does not
+ // precede a line break and end node's parent is in the same editing
+ // host, set end offset to one plus end node's index, then set end node
+ // to its parent."
+ } else if (endOffset == getNodeLength(endNode)
+ && !precedesLineBreak(endNode)
+ && inSameEditingHost(endNode, endNode.parentNode)) {
+ endOffset = 1 + getNodeIndex(endNode);
+ endNode = endNode.parentNode;
+
+ // "Otherwise, if end node is a Text node and its parent's computed
+ // value for "white-space" is neither "pre" nor "pre-wrap" and end
+ // offset is not end node's length and the end offsetth element of
+ // end node's data is a space (0x0020) or non-breaking space (0x00A0):"
+ } else if (endNode.nodeType == Node.TEXT_NODE
+ && ["pre", "pre-wrap"].indexOf(getComputedStyle(endNode.parentNode).whiteSpace) == -1
+ && endOffset != getNodeLength(endNode)
+ && /[ \xa0]/.test(endNode.data[endOffset])) {
+ // "If follows space is true and the end offsetth element of end
+ // node's data is a space (0x0020), call deleteData(end offset, 1)
+ // on end node, then continue this loop from the beginning."
+ if (followsSpace
+ && " " == endNode.data[endOffset]) {
+ endNode.deleteData(endOffset, 1);
+ continue;
+ }
+
+ // "Set follows space to true if the end offsetth element of end
+ // node's data is a space (0x0020), false otherwise."
+ followsSpace = " " == endNode.data[endOffset];
+
+ // "Add one to end offset."
+ endOffset++;
+
+ // "Add one to length."
length++;
- }
-
- // "If length is greater than one, call deleteData(end offset + 1,
- // length − 1) on node."
- if (length > 1) {
- node.deleteData(endOffset + 1, length - 1);
- }
-
- // "Add one to end offset."
- endOffset++;
+
+ // "Otherwise, break from this loop."
+ } else {
+ break;
+ }
}
// "Let replacement whitespace be the canonical space sequence of length
- // end offset minus start offset. non-breaking start is true if start
- // offset is zero and false otherwise, and non-breaking end is true if end
- // offset is node's length and false otherwise."
- var replacementWhitespace = canonicalSpaceSequence(endOffset - startOffset,
- startOffset == 0,
- endOffset == node.length);
-
- // "While start offset is less than end offset:"
- while (startOffset < endOffset) {
- // "Remove the first element from replacement whitespace, and let
- // element be that element."
- var element = replacementWhitespace[0];
- replacementWhitespace = replacementWhitespace.slice(1);
-
- // "If element is not the same as the start offsetth element of node's
- // data:"
- if (element != node.data[startOffset]) {
- // "Call insertData(start offset, element) on node."
- node.insertData(startOffset, element);
-
- // "Call deleteData(start offset + 1, 1) on node."
- node.deleteData(startOffset + 1, 1);
- }
-
- // "Add one to start offset."
- startOffset++;
+ // length. non-breaking start is true if start offset is zero and start
+ // node follows a line break, and false otherwise. non-breaking end is true
+ // if end offset is end node's length and end node precedes a line break,
+ // and false otherwise."
+ var replacementWhitespace = canonicalSpaceSequence(length,
+ startOffset == 0 && followsLineBreak(startNode),
+ endOffset == getNodeLength(endNode) && precedesLineBreak(endNode));
+
+ // "While (start node, start offset) is before (end node, end offset):"
+ while (getPosition(startNode, startOffset, endNode, endOffset) == "before") {
+ // "If start node has a child with index start offset, set start node
+ // to that child, then set start offset to zero."
+ if (startOffset < startNode.childNodes.length) {
+ startNode = startNode.childNodes[startOffset];
+ startOffset = 0;
+
+ // "Otherwise, if start node is not a Text node or if start offset is
+ // start node's length, set start offset to one plus start node's
+ // index, then set start node to its parent."
+ } else if (startNode.nodeType != Node.TEXT_NODE
+ || startOffset == getNodeLength(startNode)) {
+ startOffset = 1 + getNodeIndex(startNode);
+ startNode = startNode.parentNode;
+
+ // "Otherwise:"
+ } else {
+ // "Remove the first element from replacement whitespace, and let
+ // element be that element."
+ var element = replacementWhitespace[0];
+ replacementWhitespace = replacementWhitespace.slice(1);
+
+ // "If element is not the same as the start offsetth element of
+ // start node's data:"
+ if (element != startNode.data[startOffset]) {
+ // "Call insertData(start offset, element) on start node."
+ startNode.insertData(startOffset, element);
+
+ // "Call deleteData(start offset + 1, 1) on start node."
+ startNode.deleteData(startOffset + 1, 1);
+ }
+
+ // "Add one to start offset."
+ startOffset++;
+ }
}
}
@@ -4279,70 +4357,76 @@
// "Canonicalize whitespace at (start node, start offset)."
canonicalizeWhitespace(startNode, startOffset);
- // "Otherwise:"
- } else {
- // "If start node is an editable Text node, call deleteData() on it,
- // with start offset as the first argument and (length of start node −
- // start offset) as the second argument. Then canonicalize whitespace
- // at (start node, start offset)."
- if (isEditable(startNode)
- && startNode.nodeType == Node.TEXT_NODE) {
- startNode.deleteData(startOffset, getNodeLength(startNode) - startOffset);
- canonicalizeWhitespace(startNode, startOffset);
- }
-
- // "Let node list be a list of nodes, initially empty."
- //
- // "For each node contained in range, append node to node list if the
- // last member of node list (if any) is not an ancestor of node; node
- // is editable; and node is not a thead, tbody, tfoot, tr, th, or td."
- var nodeList = getContainedNodes(range,
- function(node) {
- return isEditable(node)
- && !isHtmlElement(node, ["thead", "tbody", "tfoot", "tr", "th", "td"]);
- }
- );
-
- // "For each node in node list:"
- for (var i = 0; i < nodeList.length; i++) {
- var node = nodeList[i];
-
- // "Let parent be the parent of node."
- var parent_ = node.parentNode;
-
- // "Remove node from parent."
- parent_.removeChild(node);
-
- // "While parent is an editable inline node with length 0, let
- // grandparent be the parent of parent, then remove parent from
- // grandparent, then set parent to grandparent."
- while (isEditable(parent_)
- && isInlineNode(parent_)
- && getNodeLength(parent_) == 0) {
- var grandparent = parent_.parentNode;
- grandparent.removeChild(parent_);
- parent_ = grandparent;
- }
-
- // "If parent is editable or an editing host, is not an inline
- // node, and has no children, call createElement("br") on the
- // context object and append the result as the last child of
- // parent."
- if ((isEditable(parent_) || isEditingHost(parent_))
- && !isInlineNode(parent_)
- && !parent_.hasChildNodes()) {
- parent_.appendChild(document.createElement("br"));
- }
- }
-
- // "If end node is an editable Text node, call deleteData(0, end
- // offset) on it, then canonicalize whitespace at (end node, 0)."
- if (isEditable(endNode)
- && endNode.nodeType == Node.TEXT_NODE) {
- endNode.deleteData(0, endOffset);
- canonicalizeWhitespace(endNode, 0);
- }
- }
+ // "Set range's end to its start."
+ range.setEnd(range.startContainer, range.startOffset);
+
+ // "Abort these steps."
+ return;
+ }
+
+ // "If start node is an editable Text node, call deleteData() on it, with
+ // start offset as the first argument and (length of start node − start
+ // offset) as the second argument."
+ if (isEditable(startNode)
+ && startNode.nodeType == Node.TEXT_NODE) {
+ startNode.deleteData(startOffset, getNodeLength(startNode) - startOffset);
+ }
+
+ // "Let node list be a list of nodes, initially empty."
+ //
+ // "For each node contained in range, append node to node list if the last
+ // member of node list (if any) is not an ancestor of node; node is
+ // editable; and node is not a thead, tbody, tfoot, tr, th, or td."
+ var nodeList = getContainedNodes(range,
+ function(node) {
+ return isEditable(node)
+ && !isHtmlElement(node, ["thead", "tbody", "tfoot", "tr", "th", "td"]);
+ }
+ );
+
+ // "For each node in node list:"
+ for (var i = 0; i < nodeList.length; i++) {
+ var node = nodeList[i];
+
+ // "Let parent be the parent of node."
+ var parent_ = node.parentNode;
+
+ // "Remove node from parent."
+ parent_.removeChild(node);
+
+ // "While parent is an editable inline node with length 0, let
+ // grandparent be the parent of parent, then remove parent from
+ // grandparent, then set parent to grandparent."
+ while (isEditable(parent_)
+ && isInlineNode(parent_)
+ && getNodeLength(parent_) == 0) {
+ var grandparent = parent_.parentNode;
+ grandparent.removeChild(parent_);
+ parent_ = grandparent;
+ }
+
+ // "If parent is editable or an editing host, is not an inline node,
+ // and has no children, call createElement("br") on the context object
+ // and append the result as the last child of parent."
+ if ((isEditable(parent_) || isEditingHost(parent_))
+ && !isInlineNode(parent_)
+ && !parent_.hasChildNodes()) {
+ parent_.appendChild(document.createElement("br"));
+ }
+ }
+
+ // "If end node is an editable Text node, call deleteData(0, end offset) on
+ // it."
+ if (isEditable(endNode)
+ && endNode.nodeType == Node.TEXT_NODE) {
+ endNode.deleteData(0, endOffset);
+ }
+
+ // "Canonicalize whitespace at range's start."
+ canonicalizeWhitespace(range.startContainer, range.startOffset);
+
+ // "Canonicalize whitespace at range's end."
+ canonicalizeWhitespace(range.endContainer, range.endOffset);
// "If start block or end block is null, or start block is not in the same
// editing host as end block, or start block and end block are the same,
--- a/source.html Tue Jul 05 12:06:30 2011 -0600
+++ b/source.html Tue Jul 05 14:00:32 2011 -0600
@@ -3397,72 +3397,131 @@
<p>To <dfn>canonicalize whitespace</dfn> at (<var>node</var>,
<var>offset</var>):
-<p class=XXX>This algorithm fails in all kinds of common cases, like any
-non-text node, or whitespace that spans multiple text nodes. Needs lots of
-fixing.
-
<ol>
- <li>If <var>node</var> is not a [[text]] node, or is not
- <span>editable</span>, or its [[parent]]'s [[compval]] for "white-space" is
- "pre" or "pre-wrap", abort these steps.
+ <li>If <var>node</var> is neither <span>editable</span> nor an <span>editing
+ host</span>, abort these steps.
+
+ <li>Let <var>start node</var> equal <var>node</var> and let <var>start
+ offset</var> equal <var>offset</var>.
<!-- First go to the beginning of the current whitespace run. -->
- <li>Let <var>start offset</var> equal <var>offset</var>.
-
- <li>While <var>start offset</var> is positive and the (<var>start
- offset</var> − 1)st [[strel]] of <var>node</var>'s [[cddata]] is a
- space (0x0020) or non-breaking space (0x00A0), subtract one from <var>start
- offset</var>.
+ <li>Repeat the following steps:
+
+ <ol>
+ <li>If <var>start node</var> has a [[child]] <span>in the same editing
+ host</span> with [[index]] <var>start offset</var> minus one, set
+ <var>start node</var> to that [[child]], then set <var>start offset</var>
+ to <var>start node</var>'s [[length]].
+
+ <li>Otherwise, if <var>start offset</var> is zero and <var>start node</var>
+ does not <span title="follows a line break">follow a line break</span> and
+ <var>start node</var>'s [[parent]] is <span>in the same editing
+ host</span>, set <var>start offset</var> to <var>start node</var>'s
+ [[index]], then set <var>start node</var> to its [[parent]].
+
+ <p class=XXX>Following a line break is unlikely to be the right criterion.
+
+ <li>Otherwise, if <var>start node</var> is a [[text]] node and its
+ [[parent]]'s [[compval]] for "white-space" is neither "pre" nor "pre-wrap"
+ and <var>start offset</var> is not zero and the (<var>start offset</var>
+ − 1)st [[strel]] of <var>start node</var>'s [[cddata]] is a space
+ (0x0020) or non-breaking space (0x00A0), subtract one from <var>start
+ offset</var>.
+
+ <li>Otherwise, break from this loop.
+ </ol>
<!-- Now collapse any consecutive spaces. -->
- <li>Let <var>end offset</var> equal <var>start offset</var>.
-
- <li>While <var>end offset</var> is less than <var>node</var>'s [[strlen]],
- and the <var>end offset</var>th [[strel]] of <var>node</var>'s [[cddata]] is
- 0x0020 or 0x00A0:
+ <li>Let <var>end node</var> equal <var>start node</var> and <var>end
+ offset</var> equal <var>start offset</var>.
+
+ <li>Let <var>length</var> equal zero.
+
+ <li>Let <var>follows space</var> be false.
+
+ <li>Repeat the following steps:
<ol>
- <li>Let <var>length</var> equal zero.
-
- <li>While <var>end offset</var> plus <var>length</var> is less than
- <var>node</var>'s [[cdlength]], and the (<var>end offset</var> +
- <var>length</var>)th [[strel]] of <var>node</var>'s [[cddata]] is 0x0020,
- add one to <var>length</var>.
-
- <li>If <var>length</var> is greater than one, call [[deletedata|<var>end
- offset</var> + 1, <var>length</var> − 1]] on <var>node</var>.
-
- <li>Add one to <var>end offset</var>.
+ <li>If <var>end node</var> has a [[child]] <span>in the same editing
+ host</span> with [[index]] <var>end offset</var>, set <var>end node</var>
+ to that [[child]], then set <var>end offset</var> to zero.
+
+ <li>Otherwise, if <var>end offset</var> is <var>end node</var>'s [[length]]
+ and <var>end node</var> does not <span title="precedes a line
+ break">precede a line break</span> and <var>end node</var>'s [[parent]] is
+ <span>in the same editing host</span>, set <var>end offset</var> to one
+ plus <var>end node</var>'s [[index]], then set <var>end node</var> to its
+ [[parent]].
+
+ <p class=XXX>Preceding a line break is unlikely to be the right criterion.
+
+ <li>Otherwise, if <var>end node</var> is a [[text]] node and its
+ [[parent]]'s [[compval]] for "white-space" is neither "pre" nor "pre-wrap"
+ and <var>end offset</var> is not <var>end node</var>'s [[length]] and the
+ <var>end offset</var>th [[strel]] of <var>end node</var>'s [[cddata]] is a
+ space (0x0020) or non-breaking space (0x00A0):
+
+ <ol>
+ <li>If <var>follows space</var> is true and the <var>end offset</var>th
+ [[strel]] of <var>end node</var>'s [[cddata]] is a space (0x0020), call
+ [[deletedata|<var>end offset</var>, 1]] on <var>end node</var>, then
+ continue this loop from the beginning.
+
+ <li>Set <var>follows space</var> to true if the <var>end offset</var>th
+ [[strel]] of <var>end node</var>'s [[cddata]] is a space (0x0020), false
+ otherwise.
+
+ <li>Add one to <var>end offset</var>.
+
+ <li>Add one to <var>length</var>.
+ </ol>
+
+ <li>Otherwise, break from this loop.
</ol>
<!-- Now replace with the canonical sequence. -->
<li>Let <var>replacement whitespace</var> be the <span>canonical space
- sequence</span> of length <var>end offset</var> minus <var>start
- offset</var>. <var>non-breaking start</var> is true if <var>start
- offset</var> is zero and false otherwise, and <var>non-breaking end</var> is
- true if <var>end offset</var> is <var>node</var>'s [[cdlength]] and false
- otherwise.
-
- <li>While <var>start offset</var> is less than <var>end offset</var>:
+ sequence</span> of length <var>length</var>. <var>non-breaking start</var>
+ is true if <var>start offset</var> is zero and <var>start node</var>
+ <span>follows a line break</span>, and false otherwise. <var>non-breaking
+ end</var> is true if <var>end offset</var> is <var>end node</var>'s
+ [[cdlength]] and <var>end node</var> <span>precedes a line break</span>, and
+ false otherwise.
+
+ <li>While (<var>start node</var>, <var>start offset</var>) is [[bpbefore]]
+ (<var>end node</var>, <var>end offset</var>):
<ol>
- <li>Remove the first [[strel]] from <var>replacement whitespace</var>, and
- let <var>element</var> be that [[strel]].
-
- <li>If <var>element</var> is not the same as the <var>start offset</var>th
- [[strel]] of <var>node</var>'s [[cddata]]:
+ <li>If <var>start node</var> has a [[child]] with [[index]] <var>start
+ offset</var>, set <var>start node</var> to that [[child]], then set
+ <var>start offset</var> to zero.
+
+ <li>Otherwise, if <var>start node</var> is not a [[text]] node or if
+ <var>start offset</var> is <var>start node</var>'s [[length]], set
+ <var>start offset</var> to one plus <var>start node</var>'s [[index]], then
+ set <var>start node</var> to its [[parent]].
+
+ <li>Otherwise:
<ol>
- <!-- We need to insert then delete, so that we don't change range
- boundary points. -->
- <li>Call [[insertdata|<var>start offset</var>, <var>element</var>]] on
- <var>node</var>.
-
- <li>Call [[deletedata|<var>start offset</var> + 1, 1]] on
- <var>node</var>.
+ <li>Remove the first [[strel]] from <var>replacement whitespace</var>,
+ and let <var>element</var> be that [[strel]].
+
+ <li>If <var>element</var> is not the same as the <var>start
+ offset</var>th [[strel]] of <var>start node</var>'s [[cddata]]:
+
+ <ol>
+ <!-- We need to insert then delete, so that we don't change range
+ boundary points. -->
+ <li>Call [[insertdata|<var>start offset</var>, <var>element</var>]] on
+ <var>start node</var>.
+
+ <li>Call [[deletedata|<var>start offset</var> + 1, 1]] on
+ <var>start node</var>.
+ </ol>
+
+ <li>Add one to <var>start offset</var>.
</ol>
-
- <li>Add one to <var>start offset</var>.
</ol>
</ol>
@@ -3896,58 +3955,61 @@
<li><span>Canonicalize whitespace</span> at (<var>start node</var>,
<var>start offset</var>).
+
+ <li>Set <var>range</var>'s [[rangeend]] to its [[rangestart]].
+
+ <li>Abort these steps.
</ol>
- <li>Otherwise:
+ <li>If <var>start node</var> is an <span>editable</span> [[text]] node, call
+ [[deletedata|]] on it, with <var>start offset</var> as the first argument and
+ ([[nodelength]] of <var>start node</var> − <var>start offset</var>) as
+ the second argument.
+
+ <li>Let <var>node list</var> be a list of [[nodes]], initially empty.
+
+ <li>For each <var>node</var> [[contained]] in <var>range</var>, append
+ <var>node</var> to <var>node list</var> if the last member of <var>node
+ list</var> (if any) is not an [[ancestor]] of <var>node</var>;
+ <var>node</var> is <span>editable</span>; and <var>node</var> is not a
+ [[thead]], [[tbody]], [[tfoot]], [[tr]], [[th]], or [[td]].
+ <!--
+ IE9 doesn't seem to let you do any intercell deletions: the delete key does
+ nothing if you select across multiple cells. Firefox 5.0a2 and Opera 11.11
+ behave as the spec says, not removing any table things. Chrome 13 dev will
+ remove entire rows if selected. Note that IE, Firefox, Word 2007, and
+ OpenOffice.org 3.2.1 Ubuntu all switch to a magic cell-selection mode when
+ you try to select between cells, at least in some cases, instead of selecting
+ letter-by-letter.
+ -->
+
+ <li>For each <var>node</var> in <var>node list</var>:
<ol>
- <li>If <var>start node</var> is an <span>editable</span> [[text]] node,
- call [[deletedata|]] on it, with <var>start offset</var> as the first
- argument and ([[nodelength]] of <var>start node</var> − <var>start
- offset</var>) as the second argument. Then <span>canonicalize
- whitespace</span> at (<var>start node</var>, <var>start offset</var>).
-
- <li>Let <var>node list</var> be a list of [[nodes]], initially empty.
-
- <li>For each <var>node</var> [[contained]] in <var>range</var>, append
- <var>node</var> to <var>node list</var> if the last member of <var>node
- list</var> (if any) is not an [[ancestor]] of <var>node</var>;
- <var>node</var> is <span>editable</span>; and <var>node</var> is not a
- [[thead]], [[tbody]], [[tfoot]], [[tr]], [[th]], or [[td]].
- <!--
- IE9 doesn't seem to let you do any intercell deletions: the delete key does
- nothing if you select across multiple cells. Firefox 5.0a2 and Opera 11.11
- behave as the spec says, not removing any table things. Chrome 13 dev will
- remove entire rows if selected. Note that IE, Firefox, Word 2007, and
- OpenOffice.org 3.2.1 Ubuntu all switch to a magic cell-selection mode when
- you try to select between cells, at least in some cases, instead of
- selecting letter-by-letter.
- -->
-
- <li>For each <var>node</var> in <var>node list</var>:
-
- <ol>
- <li>Let <var>parent</var> be the [[parent]] of <var>node</var>.
-
- <li>Remove <var>node</var> from <var>parent</var>.
-
- <li>While <var>parent</var> is an <span>editable</span> <span>inline
- node</span> with [[nodelength]] 0, let <var>grandparent</var> be the
- [[parent]] of <var>parent</var>, then remove <var>parent</var> from
- <var>grandparent</var>, then set <var>parent</var> to
- <var>grandparent</var>.
-
- <li>If <var>parent</var> is <span>editable</span> or an <span>editing
- host</span>, is not an <span>inline node</span>, and has no [[children]],
- call [[createelement|"br"]] on the [[contextobject]] and append the
- result as the last [[child]] of <var>parent</var>.
- </ol>
-
- <li>If <var>end node</var> is an <span>editable</span> [[text]] node, call
- [[deletedata|0, <var>end offset</var>]] on it, then <span>canonicalize
- whitespace</span> at (<var>end node</var>, 0).
+ <li>Let <var>parent</var> be the [[parent]] of <var>node</var>.
+
+ <li>Remove <var>node</var> from <var>parent</var>.
+
+ <li>While <var>parent</var> is an <span>editable</span> <span>inline
+ node</span> with [[nodelength]] 0, let <var>grandparent</var> be the
+ [[parent]] of <var>parent</var>, then remove <var>parent</var> from
+ <var>grandparent</var>, then set <var>parent</var> to
+ <var>grandparent</var>.
+
+ <li>If <var>parent</var> is <span>editable</span> or an <span>editing
+ host</span>, is not an <span>inline node</span>, and has no [[children]],
+ call [[createelement|"br"]] on the [[contextobject]] and append the result
+ as the last [[child]] of <var>parent</var>.
</ol>
+ <li>If <var>end node</var> is an <span>editable</span> [[text]] node, call
+ [[deletedata|0, <var>end offset</var>]] on it.
+
+ <li><span>Canonicalize whitespace</span> at <var>range</var>'s
+ [[rangestart]].
+
+ <li><span>Canonicalize whitespace</span> at <var>range</var>'s [[rangeend]].
+
<!--
Now we need to merge blocks. The simplest case is something like
@@ -6479,9 +6541,8 @@
<li>Call [[insertnode|<var>text</var>]] on the <span>active range</span>.
- <li>Call [[selcollapse|<var>text</var>, <var>length</var>]] on the
- [[contextobject]]'s [[selection]], where <var>length</var> is the [[length]]
- of <var>text</var>.
+ <li>Call [[selcollapse|<var>text</var>, 1]] on the [[contextobject]]'s
+ [[selection]].
</ol>
<!-- @} -->
--- a/tests.js Tue Jul 05 12:06:30 2011 -0600
+++ b/tests.js Tue Jul 05 14:00:32 2011 -0600
@@ -2019,6 +2019,10 @@
[' ', '{}<br>'],
[' ', '<p>{}<br>'],
+ [' ', '<p>foo[]<p>bar'],
+ [' ', '<p>foo []<p>bar'],
+ [' ', '<p>foo[]<p> bar'],
+
[' ', 'foo[]'],
'foo[]bar',