--- a/editcommands.html Mon Jul 18 15:26:31 2011 -0600
+++ b/editcommands.html Mon Jul 18 15:48:09 2011 -0600
@@ -850,6 +850,9 @@
different, the <a href=#state-override>state override</a> and <a href=#value-override>value override</a> must
be unset for every <a href=#command>command</a>.
+<p class=XXX>Figure out exactly what commands need to preserve state/value
+overrides.
+
<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,
@@ -3603,6 +3606,8 @@
<!-- 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.
@@ -3699,9 +3704,9 @@
offset</var> to 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="">reference node</var>.
</ol>
- <li>If (<var title="">end node</var>, <var title="">end 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="">start
- node</var>, <var title="">start offset</var>), 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 abort these steps.
+ <li>If (<var title="">end node</var>, <var title="">end offset</var>) is not <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-bp-after title=concept-bp-after>after</a>
+ (<var title="">start node</var>, <var title="">start offset</var>), 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 abort these steps.
<li>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 <var title="">start offset</var>
is 0, set <var title="">start offset</var> 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="">start node</var>,
@@ -6719,8 +6724,11 @@
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 class=XXX>Needs to handle overridden state/value.
+<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>:
@@ -6856,38 +6864,76 @@
"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>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:
<ol>
<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="">offset</var>, <var title="">value</var>)</a></code> on
<var title="">node</var>.
- <li>Add <var title="">value</var>'s <a href=http://es5.github.com/#x15.5.5.1>length</a> to <var title="">offset</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="">node</var>, <var title="">offset</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>.
- <li><a href=#canonicalize-whitespace>Canonicalize whitespace</a> at (<var title="">node</var>,
- <var title="">offset</var> − 1).
-
- <li><a href=#canonicalize-whitespace>Canonicalize whitespace</a> at (<var title="">node</var>,
- <var title="">offset</var>).
-
- <li>Abort these steps.
+ <li>Call <code class=external data-anolis-spec=domrange title=dom-Selection-extend><a href=http://html5.org/specs/dom-range.html#dom-selection-extend>extend(<var title="">node</var>, <var title="">offset</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>
- <!-- If some text is inserted into <p><br></p> or similar, we no longer need
- the <br>. -->
- <li>If <var title="">node</var> has only one <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>, which is a <a href=#collapsed-line-break>collapsed
- line break</a>, remove its <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> from it.
-
- <li>Let <var title="">text</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Document-createTextNode><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createtextnode>createTextNode(<var title="">value</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>.
-
- <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>, 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>.
+ <li>Otherwise:
+
+ <ol>
+ <!-- If some text is inserted into <p><br></p> or similar, we no longer need
+ the <br>. -->
+ <li>If <var title="">node</var> has only one <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>, which is a <a href=#collapsed-line-break>collapsed
+ line break</a>, remove its <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> from it.
+
+ <li>Let <var title="">text</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Document-createTextNode><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createtextnode>createTextNode(<var title="">value</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>.
+
+ <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>, 0)</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>.
+
+ <li>Call <code class=external data-anolis-spec=domrange title=dom-Selection-extend><a href=http://html5.org/specs/dom-range.html#dom-selection-extend>extend(<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>
+
+ <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=#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>.
+
+ <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-end title=concept-range-end>end</a>.
+
+ <li>Call <code class=external data-anolis-spec=domrange title=dom-Selection-collapseToEnd><a href=http://html5.org/specs/dom-range.html#dom-selection-collapsetoend>collapseToEnd()</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 Mon Jul 18 15:26:31 2011 -0600
+++ b/implementation.js Mon Jul 18 15:48:09 2011 -0600
@@ -4123,13 +4123,9 @@
endOffset = getNodeLength(referenceNode);
}
- // "If (end node, end offset) is before (start node, start offset), set
+ // "If (end node, end offset) is not after (start node, start offset), set
// range's end to its start and abort these steps."
- var startPoint = document.createRange();
- startPoint.setStart(startNode, startOffset);
- var endPoint = document.createRange();
- endPoint.setStart(endNode, endOffset);
- if (startPoint.compareBoundaryPoints(Range.START_TO_START, endPoint) == 1) {
+ if (getPosition(endNode, endOffset, startNode, startOffset) !== "after") {
range.setEnd(range.startContainer, range.startOffset);
return;
}
@@ -6862,6 +6858,16 @@
//@}
///// 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."
@@ -6933,48 +6939,91 @@
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());
+ })
+
// "If node is a Text node:"
if (node.nodeType == Node.TEXT_NODE) {
// "Call insertData(offset, value) on node."
node.insertData(offset, value);
- // "Add the length of value to offset."
- offset += value.length;
-
// "Call collapse(node, offset) on the context object's Selection."
+ //
+ // "Call extend(node, offset + 1) on the context object's
+ // Selection."
getActiveRange().setStart(node, offset);
- getActiveRange().setEnd(node, offset);
-
- // "Canonicalize whitespace at (node, offset − 1)."
- canonicalizeWhitespace(node, offset - 1);
-
- // "Canonicalize whitespace at (node, offset)."
- canonicalizeWhitespace(node, offset);
-
- // "Abort these steps."
- return;
- }
-
- // "If node has only one child, which is a collapsed line break, remove
- // its child from it."
- //
- // FIXME: IE incorrectly returns false here instead of true sometimes?
- if (node.childNodes.length == 1
- && isCollapsedLineBreak(node.firstChild)) {
- node.removeChild(node.firstChild);
- }
-
- // "Let text be the result of calling createTextNode(value) on the
- // context object."
- var text = document.createTextNode(value);
-
- // "Call insertNode(text) on the active range."
- getActiveRange().insertNode(text);
-
- // "Call collapse(text, length) on the context object's Selection,
- // where length is the length of text."
- getActiveRange().setStart(text, text.length);
- getActiveRange().setEnd(text, text.length);
+ getActiveRange().setEnd(node, offset + 1);
+
+ // "Otherwise:"
+ } else {
+ // "If node has only one child, which is a collapsed line break,
+ // remove its child from it."
+ //
+ // FIXME: IE incorrectly returns false here instead of true
+ // sometimes?
+ if (node.childNodes.length == 1
+ && isCollapsedLineBreak(node.firstChild)) {
+ node.removeChild(node.firstChild);
+ }
+
+ // "Let text be the result of calling createTextNode(value) on the
+ // context object."
+ var text = document.createTextNode(value);
+
+ // "Call insertNode(text) on the active range."
+ getActiveRange().insertNode(text);
+
+ // "Call collapse(text, 0) on the context object's Selection."
+ //
+ // "Call extend(text, 1) on the context object's Selection."
+ getActiveRange().setStart(text, 0);
+ 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());
+ }
+ });
+
+ // "Canonicalize whitespace at the active range's start."
+ canonicalizeWhitespace(getActiveRange().startContainer, getActiveRange().startOffset);
+
+ // "Canonicalize whitespace at the active range's end."
+ canonicalizeWhitespace(getActiveRange().endContainer, getActiveRange().endOffset);
+
+ // "Call collapseToEnd() on the context object's Selection."
+ getActiveRange().collapse(false);
}
};
--- a/preprocess Mon Jul 18 15:26:31 2011 -0600
+++ b/preprocess Mon Jul 18 15:48:09 2011 -0600
@@ -26,6 +26,7 @@
'cdlength': '<code data-anolis-spec=domcore title=dom-CharacterData-length>length</code>',
'child': '<span data-anolis-spec=domcore title=concept-tree-child>child</span>',
'children': '<span data-anolis-spec=domcore title=concept-tree-child>children</span>',
+ 'collapsetoend': '<code data-anolis-spec=domrange title=dom-Selection-collapseToEnd>collapseToEnd()</code>',
'collection': '<span data-anolis-spec=domcore title=concept-collection>collection</span>',
'contained': '<span data-anolis-spec=domrange>contained</span>',
'comment': '<code data-anolis-spec=domcore>Comment</code>',
--- a/source.html Mon Jul 18 15:26:31 2011 -0600
+++ b/source.html Mon Jul 18 15:48:09 2011 -0600
@@ -802,6 +802,9 @@
different, the <span>state override</span> and <span>value override</span> must
be unset for every <span>command</span>.
+<p class=XXX>Figure out exactly what commands need to preserve state/value
+overrides.
+
<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,
@@ -3590,6 +3593,8 @@
<!-- 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.
@@ -3686,10 +3691,9 @@
offset</var> to the [[nodelength]] of <var>reference node</var>.
</ol>
- <li>If (<var>end node</var>, <var>end offset</var>) is <span
- data-anolis-spec=domrange title=concept-bp-before>before</span> (<var>start
- node</var>, <var>start offset</var>), set <var>range</var>'s [[rangeend]] to
- its [[rangestart]] and abort these steps.
+ <li>If (<var>end node</var>, <var>end offset</var>) is not [[bpafter]]
+ (<var>start node</var>, <var>start offset</var>), set <var>range</var>'s
+ [[rangeend]] to its [[rangestart]] and abort these steps.
<li>If <var>start node</var> is a [[text]] node and <var>start offset</var>
is 0, set <var>start offset</var> to the [[index]] of <var>start node</var>,
@@ -6722,8 +6726,11 @@
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 class=XXX>Needs to handle overridden state/value.
+<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>:
@@ -6859,40 +6866,81 @@
"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>If <var>node</var> is a [[text]] node:
<ol>
<li>Call [[insertdata|<var>offset</var>, <var>value</var>]] on
<var>node</var>.
- <li>Add <var>value</var>'s [[strlen]] to <var>offset</var>.
-
<li>Call [[selcollapse|<var>node</var>, <var>offset</var>]] on the
[[contextobject]]'s [[selection]].
- <li><span>Canonicalize whitespace</span> at (<var>node</var>,
- <var>offset</var> − 1).
-
- <li><span>Canonicalize whitespace</span> at (<var>node</var>,
- <var>offset</var>).
-
- <li>Abort these steps.
+ <li>Call [[extend|<var>node</var>, <var>offset</var> + 1]] on the
+ [[contextobject]]'s [[selection]].
</ol>
- <!-- If some text is inserted into <p><br></p> or similar, we no longer need
- the <br>. -->
- <li>If <var>node</var> has only one [[child]], which is a <span>collapsed
- line break</span>, remove its [[child]] from it.
-
- <li>Let <var>text</var> be the result of calling <code
- data-anolis-spec=domcore
- title=dom-Document-createTextNode>createTextNode(<var>value</var>)</code> on
- the [[contextobject]].
-
- <li>Call [[insertnode|<var>text</var>]] on the <span>active range</span>.
-
- <li>Call [[selcollapse|<var>text</var>, 1]] on the [[contextobject]]'s
- [[selection]].
+ <li>Otherwise:
+
+ <ol>
+ <!-- If some text is inserted into <p><br></p> or similar, we no longer need
+ the <br>. -->
+ <li>If <var>node</var> has only one [[child]], which is a <span>collapsed
+ line break</span>, remove its [[child]] from it.
+
+ <li>Let <var>text</var> be the result of calling <code
+ data-anolis-spec=domcore
+ title=dom-Document-createTextNode>createTextNode(<var>value</var>)</code> on
+ the [[contextobject]].
+
+ <li>Call [[insertnode|<var>text</var>]] on the <span>active range</span>.
+
+ <li>Call [[selcollapse|<var>text</var>, 0]] on the [[contextobject]]'s
+ [[selection]].
+
+ <li>Call [[extend|<var>text</var>, 1]] on the [[contextobject]]'s
+ [[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>Canonicalize whitespace</span> at the <span>active range</span>'s
+ [[rangestart]].
+
+ <li><span>Canonicalize whitespace</span> at the <span>active range</span>'s
+ [[rangeend]].
+
+ <li>Call [[collapsetoend]] on the [[contextobject]]'s [[selection]].
</ol>
<!-- @} -->