--- a/editcommands.html Thu Jul 21 15:03:28 2011 -0600
+++ b/editcommands.html Thu Jul 21 15:03:51 2011 -0600
@@ -38,7 +38,7 @@
<body class=draft>
<div class=head id=head>
<h1>HTML Editing Commands</h1>
-<h2 class="no-num no-toc" id=work-in-progress-—-last-update-18-july-2011>Work in Progress — Last Update 18 July 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-—-last-update-20-july-2011>Work in Progress — Last Update 20 July 2011</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <<a href=mailto:ayg@aryeh.name>ayg@aryeh.name</a>>
@@ -322,6 +322,8 @@
<li>Have to make sure that in all the places where we set a selection, it's
valid.
+
+ <li>Redefine things in terms of ranges, not selections.
</ul>
<p class=XXX>A variety of other issues are also noted in the text, formatted
@@ -853,6 +855,12 @@
<p class=XXX>Figure out exactly what commands need to preserve state/value
overrides.
+<p>A <dfn id=command-with-insertion-affecting-state>command with insertion-affecting state</dfn> is "bold", "italic",
+"strikethrough", "subscript", "superscript", or "underline".
+
+<p>A <dfn id=command-with-insertion-affecting-value>command with insertion-affecting value</dfn> is "createLink",
+"fontName", "fontSize", "foreColor", or "hiliteColor".
+
<p>When the user agent is instructed to run a particular method, it must follow
the steps defined for that method in the appropriate specification, not act as
though the method had actually been called from JavaScript. In particular,
@@ -971,6 +979,51 @@
<a href=#remove-extraneous-line-breaks-before>remove extraneous line breaks before</a> it, then <a href=#remove-extraneous-line-breaks-at-the-end-of>remove
extraneous line breaks at the end of</a> it.
+<p>To <dfn id=record-current-states-and-values>record current states and values</dfn>:
+
+<ol>
+ <li>Let <var title="">states</var> be a dictionary mapping <a href=#command title=command>commands</a> to booleans, initially empty.
+
+ <li>For each <a href=#command-with-insertion-affecting-state>command with insertion-affecting state</a>
+ <var title="">command</var>, in order, add an entry to <var title="">states</var> mapping
+ <var title="">command</var> to the result of <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState(<var title="">command</var>)</a></code>.
+
+ <li>Let <var title="">values</var> be a dictionary mapping <a href=#command title=command>commands</a> to strings, initially empty.
+
+ <li>For each <a href=#command-with-insertion-affecting-value>command with insertion-affecting value</a>
+ <var title="">command</var>, in order, add an entry to <var title="">values</var> mapping
+ <var title="">command</var> to the result of <code title=queryCommandValue()><a href=#querycommandvalue()>queryCommandValue(<var title="">command</var>)</a></code>.
+
+ <li>Return (<var title="">states</var>, <var title="">values</var>).
+</ol>
+
+<p>To <dfn id=restore-states-and-values>restore states and values</dfn> specified by dictionaries
+(<var title="">states</var>, <var title="">values</var>) returned by the <a href=#record-current-states-and-values>record current
+states and values</a> algorithm:
+
+<ol>
+ <li>For each <var title="">command</var> that is a key in <var title="">states</var>, in order:
+
+ <ol>
+ <li>Let <var title="">state</var> be the value of <var title="">command</var> in
+ <var title="">states</var>.
+
+ <li>If <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState(<var title="">command</var>)</a></code>
+ returns something different from <var title="">state</var>, call <code title=execCommand()><a href=#execcommand()>execCommand(<var title="">command</var>)</a></code>.
+ </ol>
+
+ <li>For each <var title="">command</var> that is a key in <var title="">values</var>, in order:
+
+ <ol>
+ <li>Let <var title="">value</var> be the value of <var title="">command</var> in
+ <var title="">values</var>.
+
+ <li>If <code title=queryCommandValue()><a href=#querycommandvalue()>queryCommandValue(<var title="">command</var>)</a></code>
+ returns something different from <var title="">value</var>, call <code title=execCommand()><a href=#execcommand()>execCommand(<var title="">command</var>, false,
+ <var title="">value</var>)</a></code>.
+ </ol>
+</ol>
+
<h3 id=wrapping-a-list-of-nodes><span class=secno>6.2 </span>Wrapping a list of nodes</h3>
@@ -3606,8 +3659,6 @@
<!-- TODO: Consider what should happen for block merging in corner cases like
display: inline-table. -->
-<p class=XXX>Needs to preserve state/value in some cases?
-
<ol>
<li>If <var title="">range</var> is null, abort these steps and do nothing.
@@ -3777,6 +3828,9 @@
<var title="">end block</var>, or <var title="">end block</var> is a <code class=external data-anolis-spec=html title="the td element"><a href=http://www.whatwg.org/html/#the-td-element>td</a></code> or <code class=external data-anolis-spec=html title="the th element"><a href=http://www.whatwg.org/html/#the-th-element>th</a></code>, set
<var title="">end block</var> to null.
+ <li><a href=#record-current-states-and-values>Record current states and values</a>, and let <var title="">record</var>
+ be the result.
+
<!-- This is based on deleteContents() in DOM Range. -->
<li>If <var title="">start node</var> and <var title="">end node</var> are the same, and
<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:
@@ -3790,6 +3844,11 @@
<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><a href=#restore-states-and-values>Restore states and values</a> from <var title="">record</var>.
+ <!-- This is needed to restore any overrides that would otherwise be lost.
+ TODO: In this and similar cases, we could optimize by saving only
+ overrides, not the full state/value. -->
+
<li>Abort these steps.
</ol>
@@ -3866,8 +3925,15 @@
<li>If <var title="">block merging</var> is false, or <var title="">start block</var> or
<var title="">end block</var> is null, or <var title="">start block</var> is not <a href=#in-the-same-editing-host>in the
same editing host</a> as <var title="">end block</var>, or <var title="">start block</var>
- and <var title="">end block</var> are the same, 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> and then abort these steps.
+ and <var title="">end block</var> are the same:
+
+ <ol>
+ <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><a href=#restore-states-and-values>Restore states and values</a> from <var title="">record</var>.
+
+ <li>Abort these steps.
+ </ol>
<!--
We might have added a br to the start/end block in an earlier step. Now
@@ -3912,11 +3978,14 @@
<li>If <var title="">end block</var> is <a href=#editable>editable</a>, remove it from 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><a href=#restore-states-and-values>Restore states and values</a> from <var title="">record</var>.
+
<li>Abort these steps.
</ol>
<li>If <var title="">end block</var>'s <code class=external data-anolis-spec=domcore title=dom-Node-firstChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-firstchild>firstChild</a></code> is not an <a href=#inline-node>inline
- node</a>, abort these steps.
+ node</a>, <a href=#restore-states-and-values>restore states and values</a> from <var title="">record</var>,
+ then abort these steps.
<li>Let <var title="">children</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.
@@ -4006,6 +4075,8 @@
<li>If <var title="">start block</var> 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="">start block</var>.
+
+ <li><a href=#restore-states-and-values>Restore states and values</a> from <var title="">record</var>.
</ol>
@@ -6724,12 +6795,6 @@
exactly as far as I can tell; Chrome 14 dev and Opera 11.11 might match it in
theory, but normalize the selection first, so they don't match it in practice.
-->
-<p>A <dfn id=command-with-insertion-affecting-state>command with insertion-affecting state</dfn> is "bold", "italic",
-"strikethrough", "subscript", "superscript", or "underline".
-
-<p>A <dfn id=command-with-insertion-affecting-value>command with insertion-affecting value</dfn> is "createLink",
-"fontName", "fontSize", "foreColor", or "hiliteColor".
-
<p><a href=#action>Action</a>:
<!--
@@ -6864,11 +6929,8 @@
"pre-wrap", set <var title="">value</var> to a non-breaking space (U+00A0).
<!-- This may change to a space when we canonicalize. -->
- <li>For each <a href=#command-with-insertion-affecting-state>command with insertion-affecting state</a>, in order,
- call <code><a href=#querycommandstate()>queryCommandState()</a></code> and record the result.
-
- <li>For each <a href=#command-with-insertion-affecting-value>command with insertion-affecting value</a>, in order,
- call <code><a href=#querycommandvalue()>queryCommandValue()</a></code> and record the result.
+ <li><a href=#record-current-states-and-values>Record current states and values</a>, and let <var title="">record</var>
+ be the result.
<li>If <var title="">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:
@@ -6903,29 +6965,7 @@
<code class=external data-anolis-spec=domrange><a href=http://html5.org/specs/dom-range.html#selection>Selection</a></code>.
</ol>
- <li>For each <a href=#command-with-insertion-affecting-state>command with insertion-affecting state</a>
- <var title="">command</var>, in order:
-
- <ol>
- <li>Call <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState(<var title="">command</var>)</a></code>.
-
- <li>If the result of the last step does not match the recorded
- <a href=#state>state</a>, call <code title=execCommand()><a href=#execcommand()>execCommand(<var title="">command</var>)</a></code>.
- </ol>
-
- <li>For each <a href=#command-with-insertion-affecting-value>command with insertion-affecting value</a>
- <var title="">command</var>, in order:
-
- <ol>
- <li>Let <var title="">recorded value</var> be the recorded <a href=#value>value</a> for
- <var title="">command</var>.
-
- <li>Call <code title=queryCommandValue()><a href=#querycommandvalue()>queryCommandValue(<var title="">command</var>)</a></code>.
-
- <li>If the result of the last step is not <var title="">recorded value</var>, call
- <code title=execCommand()><a href=#execcommand()>execCommand(<var title="">command</var>, false,
- <var title="">recorded value</var>)</a></code>.
- </ol>
+ <li><a href=#restore-states-and-values>Restore states and values</a> from <var title="">record</var>.
<li><a href=#canonicalize-whitespace>Canonicalize whitespace</a> at the <a href=#active-range>active range</a>'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/implementation.js Thu Jul 21 15:03:28 2011 -0600
+++ b/implementation.js Thu Jul 21 15:03:51 2011 -0600
@@ -1051,6 +1051,17 @@
delete valueOverrides[command];
}
})();
+
+// "A command with insertion-affecting state is "bold", "italic",
+// "strikethrough", "subscript", "superscript", or "underline"."
+var commandsWithInsertionAffectingState = ["bold", "italic", "strikethrough",
+ "subscript", "superscript", "underline"];
+
+// "A command with insertion-affecting value is "createLink", "fontName",
+// "fontSize", "forecolor", or "hiliteColor"."
+var commandsWithInsertionAffectingValue = ["createlink", "fontname",
+ "fontsize", "forecolor", "hilitecolor"];
+
//@}
/////////////////////////////
@@ -1235,6 +1246,61 @@
removeExtraneousLineBreaksAtTheEndOf(node);
}
+function recordCurrentStatesAndValues() {
+ // "Let states be a dictionary mapping commands to booleans, initially
+ // empty."
+ var states = {};
+
+ // "For each command with insertion-affecting state command, in order, add
+ // an entry to states mapping command to the result of
+ // queryCommandState(command)."
+ commandsWithInsertionAffectingState.forEach(function(command) {
+ states[command] = myQueryCommandState(command);
+ });
+
+ // "Let values be a dictionary mapping commands to strings, initially
+ // empty."
+ var values = {};
+
+ // "For each command with insertion-affecting value command, in order, add
+ // an entry to values mapping command to the result of
+ // queryCommandValue(command)."
+ commandsWithInsertionAffectingValue.forEach(function(command) {
+ values[command] = myQueryCommandValue(command);
+ });
+
+ // "Return (states, values)."
+ return [states, values];
+}
+
+function restoreStatesAndValues(record) {
+ var states = record[0];
+ var values = record[1];
+
+ // "For each command that is a key in states, in order:"
+ for (var command in states) {
+ // "Let state be the value of command in states."
+ var state = states[command];
+
+ // "If queryCommandState(command) returns something different from
+ // state, call execCommand(command)."
+ if (myQueryCommandState(command) !== state) {
+ myExecCommand(command);
+ }
+ }
+
+ // "For each command that is a key in values, in order:"
+ for (var command in values) {
+ // "Let value be the value of command in values."
+ var value = values[command];
+
+ // "If queryCommandValue(command) returns something different from
+ // value, call execCommand(command, false, value)."
+ if (myQueryCommandValue(command) !== value) {
+ myExecCommand(command, false, value);
+ }
+ }
+}
//@}
///// Wrapping a list of nodes /////
@@ -4201,6 +4267,9 @@
endBlock = null;
}
+ // "Record current states and values, and let record be the result."
+ var record = recordCurrentStatesAndValues();
+
// "If start node and end node are the same, and start node is an editable
// Text node:"
if (startNode == endNode
@@ -4216,6 +4285,9 @@
// "Set range's end to its start."
range.setEnd(range.startContainer, range.startOffset);
+ // "Restore states and values from record."
+ restoreStatesAndValues(record);
+
// "Abort these steps."
return;
}
@@ -4286,14 +4358,19 @@
// "If block merging is false, or 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, set range's end to its start and then abort
- // these steps."
+ // and end block are the same:"
if (!blockMerging
|| !startBlock
|| !endBlock
|| !inSameEditingHost(startBlock, endBlock)
|| startBlock == endBlock) {
+ // "Set range's end to its start."
range.setEnd(range.startContainer, range.startOffset);
+
+ // "Restore states and values from record."
+ restoreStatesAndValues(record);
+
+ // "Abort these steps."
return;
}
@@ -4357,13 +4434,17 @@
endBlock.parentNode.removeChild(endBlock);
}
+ // "Restore states and values from record."
+ restoreStatesAndValues(record);
+
// "Abort these steps."
return;
}
- // "If end block's firstChild is not an inline node, abort these
- // steps."
+ // "If end block's firstChild is not an inline node, restore states and
+ // values from record, then abort these steps."
if (!isInlineNode(endBlock.firstChild)) {
+ restoreStatesAndValues(record);
return;
}
@@ -4498,6 +4579,9 @@
if (!startBlock.hasChildNodes()) {
startBlock.appendChild(document.createElement("br"));
}
+
+ // "Restore states and values from record."
+ restoreStatesAndValues(record);
}
@@ -6870,16 +6954,6 @@
//@}
///// The insertText command /////
//@{
-// "A command with insertion-affecting state is "bold", "italic",
-// "strikethrough", "subscript", "superscript", or "underline"."
-var commandsWithInsertionAffectingState = ["bold", "italic", "strikethrough",
- "subscript", "superscript", "underline"];
-
-// "A command with insertion-affecting value is "createLink", "fontName",
-// "fontSize", "forecolor", or "hiliteColor"."
-var commandsWithInsertionAffectingValue = ["createlink", "fontname",
- "fontsize", "forecolor", "hilitecolor"];
-
commands.inserttext = {
action: function(value) {
// "Delete the contents of the active range."
@@ -6951,19 +7025,8 @@
value = "\xa0";
}
- // "For each command with insertion-affecting state, in order, call
- // queryCommandState() and record the result."
- var recordedStates = {};
- commandsWithInsertionAffectingState.forEach(function(command) {
- recordedStates[command] = myQueryCommandState(command, getActiveRange());
- });
-
- // "For each command with insertion-affecting value, in order, call
- // queryCommandValue() and record the result."
- var recordedValues = {};
- commandsWithInsertionAffectingValue.forEach(function(command) {
- recordedValues[command] = myQueryCommandValue(command, getActiveRange());
- })
+ // "Record current states and values, and let record be the result."
+ var record = recordCurrentStatesAndValues();
// "If node is a Text node:"
if (node.nodeType == Node.TEXT_NODE) {
@@ -7003,30 +7066,8 @@
getActiveRange().setEnd(text, 1);
}
- // "For each command with insertion-affecting state command, in order:"
- commandsWithInsertionAffectingState.forEach(function(command) {
- // "Call queryCommandState(command)."
- //
- // "If the result of the last step does not match the recorded
- // state, call execCommand(command)."
- if (myQueryCommandState(command, getActiveRange()) !== recordedStates[command]) {
- myExecCommand(command, false, "", getActiveRange());
- }
- });
-
- // "For each command with insertion-affecting value command, in order:"
- commandsWithInsertionAffectingValue.forEach(function(command) {
- // "Let recorded value be the recorded value for command."
- var recordedValue = recordedValues[command];
-
- // "Call queryCommandValue(command)."
- //
- // "If the result of the last step is not recorded value, call
- // execCommand(command, false, recorded value)."
- if (myQueryCommandValue(command, getActiveRange()) !== recordedValue) {
- myExecCommand(command, false, recordedValue, getActiveRange());
- }
- });
+ // "Restore states and values from record."
+ restoreStatesAndValues(record);
// "Canonicalize whitespace at the active range's start."
canonicalizeWhitespace(getActiveRange().startContainer, getActiveRange().startOffset);
--- a/source.html Thu Jul 21 15:03:28 2011 -0600
+++ b/source.html Thu Jul 21 15:03:51 2011 -0600
@@ -254,6 +254,8 @@
<li>Have to make sure that in all the places where we set a selection, it's
valid.
+
+ <li>Redefine things in terms of ranges, not selections.
</ul>
<p class=XXX>A variety of other issues are also noted in the text, formatted
@@ -805,6 +807,12 @@
<p class=XXX>Figure out exactly what commands need to preserve state/value
overrides.
+<p>A <dfn>command with insertion-affecting state</dfn> is "bold", "italic",
+"strikethrough", "subscript", "superscript", or "underline".
+
+<p>A <dfn>command with insertion-affecting value</dfn> is "createLink",
+"fontName", "fontSize", "foreColor", or "hiliteColor".
+
<p>When the user agent is instructed to run a particular method, it must follow
the steps defined for that method in the appropriate specification, not act as
though the method had actually been called from JavaScript. In particular,
@@ -925,6 +933,59 @@
<span>remove extraneous line breaks before</span> it, then <span>remove
extraneous line breaks at the end of</span> it.
+<p>To <dfn>record current states and values</dfn>:
+
+<ol>
+ <li>Let <var>states</var> be a dictionary mapping <span
+ title=command>commands</span> to booleans, initially empty.
+
+ <li>For each <span>command with insertion-affecting state</span>
+ <var>command</var>, in order, add an entry to <var>states</var> mapping
+ <var>command</var> to the result of <code
+ title=queryCommandState()>queryCommandState(<var>command</var>)</code>.
+
+ <li>Let <var>values</var> be a dictionary mapping <span
+ title=command>commands</span> to strings, initially empty.
+
+ <li>For each <span>command with insertion-affecting value</span>
+ <var>command</var>, in order, add an entry to <var>values</var> mapping
+ <var>command</var> to the result of <code
+ title=queryCommandValue()>queryCommandValue(<var>command</var>)</code>.
+
+ <li>Return (<var>states</var>, <var>values</var>).
+</ol>
+
+<p>To <dfn>restore states and values</dfn> specified by dictionaries
+(<var>states</var>, <var>values</var>) returned by the <span>record current
+states and values</span> algorithm:
+
+<ol>
+ <li>For each <var>command</var> that is a key in <var>states</var>, in order:
+
+ <ol>
+ <li>Let <var>state</var> be the value of <var>command</var> in
+ <var>states</var>.
+
+ <li>If <code
+ title=queryCommandState()>queryCommandState(<var>command</var>)</code>
+ returns something different from <var>state</var>, call <code
+ title=execCommand()>execCommand(<var>command</var>)</code>.
+ </ol>
+
+ <li>For each <var>command</var> that is a key in <var>values</var>, in order:
+
+ <ol>
+ <li>Let <var>value</var> be the value of <var>command</var> in
+ <var>values</var>.
+
+ <li>If <code
+ title=queryCommandValue()>queryCommandValue(<var>command</var>)</code>
+ returns something different from <var>value</var>, call <code
+ title=execCommand()>execCommand(<var>command</var>, false,
+ <var>value</var>)</code>.
+ </ol>
+</ol>
+
<!-- @} -->
<h3>Wrapping a list of nodes</h3>
<!-- @{ -->
@@ -3593,8 +3654,6 @@
<!-- TODO: Consider what should happen for block merging in corner cases like
display: inline-table. -->
-<p class=XXX>Needs to preserve state/value in some cases?
-
<ol>
<li>If <var>range</var> is null, abort these steps and do nothing.
@@ -3764,6 +3823,9 @@
<var>end block</var>, or <var>end block</var> is a [[td]] or [[th]], set
<var>end block</var> to null.
+ <li><span>Record current states and values</span>, and let <var>record</var>
+ be the result.
+
<!-- This is based on deleteContents() in DOM Range. -->
<li>If <var>start node</var> and <var>end node</var> are the same, and
<var>start node</var> is an <span>editable</span> [[text]] node:
@@ -3777,6 +3839,11 @@
<li>Set <var>range</var>'s [[rangeend]] to its [[rangestart]].
+ <li><span>Restore states and values</span> from <var>record</var>.
+ <!-- This is needed to restore any overrides that would otherwise be lost.
+ TODO: In this and similar cases, we could optimize by saving only
+ overrides, not the full state/value. -->
+
<li>Abort these steps.
</ol>
@@ -3853,8 +3920,15 @@
<li>If <var>block merging</var> is false, or <var>start block</var> or
<var>end block</var> is null, or <var>start block</var> is not <span>in the
same editing host</span> as <var>end block</var>, or <var>start block</var>
- and <var>end block</var> are the same, set <var>range</var>'s [[rangeend]] to
- its [[rangestart]] and then abort these steps.
+ and <var>end block</var> are the same:
+
+ <ol>
+ <li>Set <var>range</var>'s [[rangeend]] to its [[rangestart]].
+
+ <li><span>Restore states and values</span> from <var>record</var>.
+
+ <li>Abort these steps.
+ </ol>
<!--
We might have added a br to the start/end block in an earlier step. Now
@@ -3899,11 +3973,14 @@
<li>If <var>end block</var> is <span>editable</span>, remove it from its
[[parent]].
+ <li><span>Restore states and values</span> from <var>record</var>.
+
<li>Abort these steps.
</ol>
<li>If <var>end block</var>'s [[firstchild]] is not an <span>inline
- node</span>, abort these steps.
+ node</span>, <span>restore states and values</span> from <var>record</var>,
+ then abort these steps.
<li>Let <var>children</var> be a list of [[nodes]], initially empty.
@@ -3993,6 +4070,8 @@
<li>If <var>start block</var> has no [[children]], call
[[createelement|"br"]] on the [[contextobject]] and append the result as the
last [[child]] of <var>start block</var>.
+
+ <li><span>Restore states and values</span> from <var>record</var>.
</ol>
<!-- @} -->
@@ -6726,12 +6805,6 @@
exactly as far as I can tell; Chrome 14 dev and Opera 11.11 might match it in
theory, but normalize the selection first, so they don't match it in practice.
-->
-<p>A <dfn>command with insertion-affecting state</dfn> is "bold", "italic",
-"strikethrough", "subscript", "superscript", or "underline".
-
-<p>A <dfn>command with insertion-affecting value</dfn> is "createLink",
-"fontName", "fontSize", "foreColor", or "hiliteColor".
-
<p><span>Action</span>:
<!--
@@ -6866,11 +6939,8 @@
"pre-wrap", set <var>value</var> to a non-breaking space (U+00A0).
<!-- This may change to a space when we canonicalize. -->
- <li>For each <span>command with insertion-affecting state</span>, in order,
- call <code>queryCommandState()</code> and record the result.
-
- <li>For each <span>command with insertion-affecting value</span>, in order,
- call <code>queryCommandValue()</code> and record the result.
+ <li><span>Record current states and values</span>, and let <var>record</var>
+ be the result.
<li>If <var>node</var> is a [[text]] node:
@@ -6907,32 +6977,7 @@
[[selection]].
</ol>
- <li>For each <span>command with insertion-affecting state</span>
- <var>command</var>, in order:
-
- <ol>
- <li>Call <code
- title=queryCommandState()>queryCommandState(<var>command</var>)</code>.
-
- <li>If the result of the last step does not match the recorded
- <span>state</span>, call <code
- title=execCommand()>execCommand(<var>command</var>)</code>.
- </ol>
-
- <li>For each <span>command with insertion-affecting value</span>
- <var>command</var>, in order:
-
- <ol>
- <li>Let <var>recorded value</var> be the recorded <span>value</span> for
- <var>command</var>.
-
- <li>Call <code
- title=queryCommandValue()>queryCommandValue(<var>command</var>)</code>.
-
- <li>If the result of the last step is not <var>recorded value</var>, call
- <code title=execCommand()>execCommand(<var>command</var>, false,
- <var>recorded value</var>)</code>.
- </ol>
+ <li><span>Restore states and values</span> from <var>record</var>.
<li><span>Canonicalize whitespace</span> at the <span>active range</span>'s
[[rangestart]].