--- a/editcommands.html Mon May 30 12:01:09 2011 -0600
+++ b/editcommands.html Mon May 30 12:26:20 2011 -0600
@@ -715,9 +715,67 @@
return null. This can be used to only merge with adjacent siblings, in case
you don't want to create a new parent if that fails. -->
- <li>If <var title="">new parent</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 null, insert <var title="">new
- parent</var> into 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 the first member of <var title="">node list</var>
- immediately before the first member of <var title="">node list</var>.
+ <li>If <var title="">new parent</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 null:
+
+ <ol>
+ <li>Insert <var title="">new parent</var> into 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 the first member of
+ <var title="">node list</var> immediately before the first member of <var title="">node
+ list</var>.
+
+ <li>If any <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a> has a <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point title=concept-boundary-point>boundary point</a> with <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a> equal to 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="">new parent</var> and <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a> equal to the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a>
+ of <var title="">new parent</var>, add one to that <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point title=concept-boundary-point>boundary point</a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a>.
+ <!--
+ Basically, we want any boundary points around the wrapped nodes to go
+ inside the wrapper. Without this step, wrapping "{}<br>" in a blockquote
+ would go like
+
+ {}<br>
+ -> {}<blockquote></blockquote><br>
+ -> {}<blockquote></blockquote><br>.
+
+ The second line is due to range mutation rules: a boundary point with an
+ offset equal to the index of a newly-inserted node stays put, so it remains
+ before it. With this step, it goes like
+
+ {}<br>
+ -> {}<blockquote></blockquote><br>
+ -> <blockquote></blockquote>{}<br>
+ -> <blockquote>{}<br></blockquote>.
+
+ The difference in the final step is because we move the <br> "preserving
+ ranges". This means that adjacent boundary points get swept along with it.
+ Previously, the <blockquote> intervened, so a boundary point after it would
+ get taken along but one before it would not.
+
+ Another solution that one might be tempted to consider would be to just put
+ the wrapper after the wrapped elements. Then the boundary points would
+ stay put, before the wrapper, so they'd still be adjacent to the nodes to
+ be wrapped, like:
+
+ {<p>foo</p>}
+ -> {<p>foo</p>}<blockquote></blockquote>
+ -> <blockquote>{<p>foo</p>}</blockquote>.
+
+ The problem is that this completely breaks if you're wrapping multiple
+ things and not all are selected. It would go like this:
+
+ <p>foo</p>{<p>bar</p>}
+ -> <p>foo</p>{<p>bar</p>}<blockquote></blockquote>
+ -> <p>foo</p><blockquote>{<p>bar</p>}</blockquote>
+ -> <blockquote>{<p>foo</p><p>bar</p>}</blockquote>.
+
+ The last step is again because of the range mutation rules: the boundary
+ point stays put when a new node is inserted. They're fundamentally
+ asymmetric.
+
+ An alternative solution would be to define the concept of moving a list of
+ adjacent sibling nodes while preserving ranges, and handle this explicitly
+ at a more abstract level.
+ -->
+
+ <p class=XXX>Not clear this is the best solution. See comment.
+ </ol>
<li>Let <var title="">original 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 the first member of
<var title="">node list</var>.
@@ -4240,13 +4298,6 @@
criteria</a> matching nothing and <a href=#new-parent-instructions>new parent instructions</a>
returning the result of calling <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(<var title="">tag</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>. Set <var title="">container</var> to the result.
-
- <li>If <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> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a> is not <var title="">container</var>, set
- <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> and <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
- (<var title="">container</var>, 0).
-
- <p class=XXX>This is a hack to work around range mutation rules not working
- the way I'd like them to. Should be fixed more sensibly.
</ol>
<li>If <var title="">container</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> is "address" or "pre":
--- a/implementation.js Mon May 30 12:01:09 2011 -0600
+++ b/implementation.js Mon May 30 12:26:20 2011 -0600
@@ -600,11 +600,25 @@
return null;
}
- // "If new parent's parent is null, insert new parent into the parent of
- // the first member of node list immediately before the first member of
- // node list."
+ // "If new parent's parent is null:"
if (!newParent.parentNode) {
+ // "Insert new parent into the parent of the first member of node list
+ // immediately before the first member of node list."
nodeList[0].parentNode.insertBefore(newParent, nodeList[0]);
+
+ // "If any range has a boundary point with node equal to the parent of
+ // new parent and offset equal to the index of new parent, add one to
+ // that boundary point's offset."
+ //
+ // Only try to fix the global range.
+ if (globalRange.startContainer == newParent.parentNode
+ && globalRange.startOffset == getNodeIndex(newParent)) {
+ globalRange.setStart(globalRange.startContainer, globalRange.startOffset + 1);
+ }
+ if (globalRange.endContainer == newParent.parentNode
+ && globalRange.endOffset == getNodeIndex(newParent)) {
+ globalRange.setEnd(globalRange.endContainer, globalRange.endOffset + 1);
+ }
}
// "Let original parent be the parent of the first member of node list."
@@ -3242,13 +3256,6 @@
function() { return false },
function() { return document.createElement(tag) }
);
-
- // "If range's start node is not container, set range's start and
- // end to (container, 0)."
- if (range.startContainer != container) {
- range.setStart(container, 0);
- range.setEnd(container, 0);
- }
}
// "If container's local name is "address" or "pre":"
--- a/source.html Mon May 30 12:01:09 2011 -0600
+++ b/source.html Mon May 30 12:26:20 2011 -0600
@@ -674,9 +674,67 @@
return null. This can be used to only merge with adjacent siblings, in case
you don't want to create a new parent if that fails. -->
- <li>If <var>new parent</var>'s [[parent]] is null, insert <var>new
- parent</var> into the [[parent]] of the first member of <var>node list</var>
- immediately before the first member of <var>node list</var>.
+ <li>If <var>new parent</var>'s [[parent]] is null:
+
+ <ol>
+ <li>Insert <var>new parent</var> into the [[parent]] of the first member of
+ <var>node list</var> immediately before the first member of <var>node
+ list</var>.
+
+ <li>If any [[range]] has a [[boundarypoint]] with [[bpnode]] equal to the
+ [[parent]] of <var>new parent</var> and [[bpoffset]] equal to the [[index]]
+ of <var>new parent</var>, add one to that [[boundarypoint]]'s [[bpoffset]].
+ <!--
+ Basically, we want any boundary points around the wrapped nodes to go
+ inside the wrapper. Without this step, wrapping "{}<br>" in a blockquote
+ would go like
+
+ {}<br>
+ -> {}<blockquote></blockquote><br>
+ -> {}<blockquote></blockquote><br>.
+
+ The second line is due to range mutation rules: a boundary point with an
+ offset equal to the index of a newly-inserted node stays put, so it remains
+ before it. With this step, it goes like
+
+ {}<br>
+ -> {}<blockquote></blockquote><br>
+ -> <blockquote></blockquote>{}<br>
+ -> <blockquote>{}<br></blockquote>.
+
+ The difference in the final step is because we move the <br> "preserving
+ ranges". This means that adjacent boundary points get swept along with it.
+ Previously, the <blockquote> intervened, so a boundary point after it would
+ get taken along but one before it would not.
+
+ Another solution that one might be tempted to consider would be to just put
+ the wrapper after the wrapped elements. Then the boundary points would
+ stay put, before the wrapper, so they'd still be adjacent to the nodes to
+ be wrapped, like:
+
+ {<p>foo</p>}
+ -> {<p>foo</p>}<blockquote></blockquote>
+ -> <blockquote>{<p>foo</p>}</blockquote>.
+
+ The problem is that this completely breaks if you're wrapping multiple
+ things and not all are selected. It would go like this:
+
+ <p>foo</p>{<p>bar</p>}
+ -> <p>foo</p>{<p>bar</p>}<blockquote></blockquote>
+ -> <p>foo</p><blockquote>{<p>bar</p>}</blockquote>
+ -> <blockquote>{<p>foo</p><p>bar</p>}</blockquote>.
+
+ The last step is again because of the range mutation rules: the boundary
+ point stays put when a new node is inserted. They're fundamentally
+ asymmetric.
+
+ An alternative solution would be to define the concept of moving a list of
+ adjacent sibling nodes while preserving ranges, and handle this explicitly
+ at a more abstract level.
+ -->
+
+ <p class=XXX>Not clear this is the best solution. See comment.
+ </ol>
<li>Let <var>original parent</var> be the [[parent]] of the first member of
<var>node list</var>.
@@ -4275,13 +4333,6 @@
criteria</span> matching nothing and <span>new parent instructions</span>
returning the result of calling [[createelement|<var>tag</var>]] on the
[[contextobject]]. Set <var>container</var> to the result.
-
- <li>If <var>range</var>'s [[startnode]] is not <var>container</var>, set
- <var>range</var>'s [[rangestart]] and [[rangeend]] to
- (<var>container</var>, 0).
-
- <p class=XXX>This is a hack to work around range mutation rules not working
- the way I'd like them to. Should be fixed more sensibly.
</ol>
<li>If <var>container</var>'s [[localname]] is "address" or "pre":