--- a/editcommands.html Thu Jul 14 14:27:17 2011 -0600
+++ b/editcommands.html Thu Jul 14 15:40:44 2011 -0600
@@ -686,8 +686,8 @@
<div class=note>
<p>The methods in this section have mostly been designed so that the following
-invariants hold after <code><a href=#execcommand()>execCommand()</a></code> is called, assuming it didn't
-throw an exception:
+invariants hold after <code title="">execCommand()</code> is called, assuming it
+didn't throw an exception:
<ul>
<li><code title="">queryCommandIndeterm()</code> will return false (or throw an
@@ -705,11 +705,12 @@
<p>The first two points do not always hold for <code title="">strikethrough</code>
or <code title="">underline</code>, because it can be impossible to unset
text-decoration in CSS. Also, by design, the state of <code title="">insertOrderedList</code> and <code title="">insertOrderedList</code> might
-not be the opposite after calling as before calling. Finally, the state of the
-various <code title="">justify</code> commands should always be true after
-calling, and the value should always be the appropriate string ("center",
-"justify", "left", or "right"). Any other deviations from these invariants are
-bugs in the specification.
+be true both before and after calling, because they only remove one level of
+indentation. <code title="">unlink</code> should set the value to null. And
+finally, the state of the various <code title="">justify</code> commands should
+always be true after calling, and the value should always be the appropriate
+string ("center", "justify", "left", or "right"). Any other deviations from
+these invariants are bugs in the specification.
</div>
@@ -2510,7 +2511,23 @@
<li><a href="#set-the-selection's-value">Set the selection's value</a> to <var title="">value</var>.
</ol>
-<p class=XXX>Define state and value, although browsers don't.
+<!-- IE10PP2, Firefox 7.0a2, Chrome 14 dev, and Opera 11.50 all do not support
+indeterminate, state, or value for createLink or unlink. I define
+indeterminate and value anyway because they make sense. -->
+<p><a href=#indeterminate>Indeterminate</a>: True if among <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>
+nodes that are <a href=#effectively-contained>effectively contained</a> in the <a href=#active-range>active
+range</a>, there are two that have distinct <a href=#effective-command-value title="effective command
+value">effective command values</a>. Otherwise false.
+
+<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the first
+<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 that is <a href=#effectively-contained>effectively contained</a>
+in the <a href=#active-range>active range</a>, or if there is no such node, the
+<a href=#effective-command-value>effective command value</a> of 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 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>.
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
<h3 id=the-fontname-command><span class=secno>7.10 </span><dfn>The <code title="">fontName</code> command</dfn></h3>
@@ -3254,6 +3271,25 @@
<li><a href=#clear-the-value>Clear the value</a> of each member of <var title="">hyperlinks</var>.
</ol>
+<!-- IE10PP2, Firefox 7.0a2, Chrome 14 dev, and Opera 11.50 all do not support
+indeterminate, state, or value for createLink or unlink. I define
+indeterminate and value anyway because they make sense. -->
+<p><a href=#indeterminate>Indeterminate</a>: True if among <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>
+nodes that are <a href=#effectively-contained>effectively contained</a> in the <a href=#active-range>active
+range</a>, there are two that have distinct <a href=#effective-command-value title="effective command
+value">effective command values</a>. Otherwise false.
+
+<p><a href=#value>Value</a>: The <a href=#effective-command-value>effective command value</a> of the first
+<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 that is <a href=#effectively-contained>effectively contained</a>
+in the <a href=#active-range>active range</a>, or if there is no such node, the
+<a href=#effective-command-value>effective command value</a> of 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 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>.
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
+
+
<h2 id=block-formatting-commands><span class=secno>8 </span>Block formatting commands</h2>
@@ -5677,6 +5713,9 @@
sense for <address>/<h*>/<pre>, but other browsers don't do it.
-->
+<p>A <dfn id=formattable-block-name>formattable block name</dfn> is "address", "dd", "div", "dt", "h1",
+"h2", "h3", "h4", "h5", "h6", "p", or "pre".
+
<p><a href=#action>Action</a>:
<ol>
@@ -5688,8 +5727,8 @@
<li>Let <var title="">value</var> be <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#converted-to-ascii-lowercase>converted to
ASCII lowercase</a>.
- <li>If <var title="">value</var> is not "address", "dd", "div", "dt", "h1", "h2",
- "h3", "h4", "h5", "h6", "p", or "pre", raise a <code class=external data-anolis-spec=domcore title=dom-DOMException-SYNTAX_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-syntax_err>SYNTAX_ERR</a></code> exception.
+ <li>If <var title="">value</var> is not a <a href=#formattable-block-name>formattable block name</a>, raise a
+ <code class=external data-anolis-spec=domcore title=dom-DOMException-SYNTAX_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-syntax_err>SYNTAX_ERR</a></code> exception.
<!--
Opera 11.10 throws NOT_SUPPORTED_ERR for bad elements, all other tested
browsers ignore the input. Testing in IE9, Firefox 4.0, Chrome 13 dev, and
@@ -5728,11 +5767,10 @@
<li>For each <var title="">node</var> in <var title="">node list</var>, while <var title="">node</var>
is the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendant</a> of an <a href=#editable>editable</a> <a href=#html-element>HTML element</a>
- <a href=#in-the-same-editing-host>in the same editing host</a>, which has <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> "address",
- "dd", "div", "dt", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", and
- which is not the <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 a <a href=#prohibited-paragraph-child>prohibited paragraph child</a>,
- <a href=#split-the-parent>split the parent</a> of the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting of
- <var title="">node</var>.
+ <a href=#in-the-same-editing-host>in the same editing host</a>, whose <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 a
+ <a href=#formattable-block-name>formattable block name</a>, and which is not the <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 a
+ <a href=#prohibited-paragraph-child>prohibited paragraph child</a>, <a href=#split-the-parent>split the parent</a> of the
+ one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting of <var title="">node</var>.
<!--
This tries to avoid misnesting if only some lines of an element are selected,
so <h1>[foo]<br>bar</h1> becomes <p>[foo]</p><h1>bar</h1> instead of
@@ -5867,15 +5905,15 @@
<ol>
<li>While <var title="">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=#editable>editable</a> and
<a href=#in-the-same-editing-host>in the same editing host</a> as <var title="">node</var>, and
- <var title="">node</var> is not an <a href=#html-element>HTML element</a> with <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>
- "address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", set
- <var title="">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>.
+ <var title="">node</var> is not an <a href=#html-element>HTML element</a> whose <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 a <a href=#formattable-block-name>formattable block name</a>, set <var title="">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>Let <var title="">current type</var> be the empty string.
<li>If <var title="">node</var> is an <a href=#editable>editable</a> <a href=#html-element>HTML
- element</a> with <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> "address", "div", "h1", "h2", "h3", "h4",
- "h5", "h6", "p", or "pre", and <var title="">node</var> is not the <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 a
+ element</a> whose <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 a <a href=#formattable-block-name>formattable block
+ name</a>, and <var title="">node</var> is not the <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 a
<a href=#prohibited-paragraph-child>prohibited paragraph child</a>, set <var title="">current type</var> to
<var title="">node</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>.
@@ -5915,15 +5953,15 @@
<li>While <var title="">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=#editable>editable</a> and <a href=#in-the-same-editing-host>in
the same editing host</a> as <var title="">node</var>, and <var title="">node</var> is not
- an <a href=#html-element>HTML element</a> with <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> "address", "div", "h1", "h2",
- "h3", "h4", "h5", "h6", "p", or "pre", set <var title="">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>.
+ an <a href=#html-element>HTML element</a> whose <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 a <a href=#formattable-block-name>formattable block
+ name</a>, set <var title="">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>.
<!-- Opera 11.11 doesn't require it be editable, so it will return "DIV"
instead of "" for <div contenteditable>foo</div>. -->
<li>If <var title="">node</var> is an <a href=#editable>editable</a> <a href=#html-element>HTML element</a>
- with <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> "address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p",
- or "pre", and <var title="">node</var> is not the <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 a <a href=#prohibited-paragraph-child>prohibited
- paragraph child</a>, return <var title="">node</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>, <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#converted-to-ascii-lowercase>converted to ASCII lowercase</a>.
+ whose <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 a <a href=#formattable-block-name>formattable block name</a>, and
+ <var title="">node</var> is not the <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 a <a href=#prohibited-paragraph-child>prohibited paragraph
+ child</a>, return <var title="">node</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>, <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#converted-to-ascii-lowercase>converted to ASCII lowercase</a>.
<!--
Chrome 14 dev will report "div" for <div><ol><li>foo</ol></div> or such.
Opera 11.11 reports "". IE and Firefox didn't cooperate with testing. Opera
--- a/implementation.js Thu Jul 14 14:27:17 2011 -0600
+++ b/implementation.js Thu Jul 14 15:40:44 2011 -0600
@@ -134,6 +134,10 @@
// test implementation. It's not clear how all this should actually be specced
// in practice, since CSS defines no notion of equality, does it?
function valuesEqual(command, val1, val2) {
+ if (commands[command].relevantCssProperty === null) {
+ return val1 === val2;
+ }
+
if (val1 === null || val2 === null) {
return val1 === val2;
}
@@ -150,15 +154,6 @@
|| (val2.toLowerCase() == "normal" && val1 == "400");
}
- // This code path should probably only be hit by queryOutputHelper() in
- // tests.js. Anything else is most likely a bug.
- if (command == "fontname" && /^[1-7]$/.test(val1)) {
- val1 = [, "xx-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large"][val1];
- }
- if (command == "fontname" && /^[1-7]$/.test(val2)) {
- val2 = [, "xx-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large"][val2];
- }
-
var property = commands[command].relevantCssProperty;
var test1 = document.createElement("span");
test1.style[property] = val1;
@@ -3065,6 +3060,28 @@
// "Set the selection's value to value."
setSelectionValue("createlink", value);
+ }, indeterm: function() {
+ // "True if among editable Text nodes that are effectively contained in
+ // the active range, there are two that have distinct effective command
+ // values. Otherwise false."
+ return getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+ return isEditable(node) && node.nodeType == Node.TEXT_NODE;
+ }).map(function(node) {
+ return getEffectiveCommandValue(node, "createlink");
+ }).filter(function(value, i, arr) {
+ return arr.slice(0, i).indexOf(value) == -1;
+ }).length >= 2;
+ }, value: function() {
+ // "The effective command value of the first editable Text node that is
+ // effectively contained in the active range, or if there is no such
+ // node, the effective command value of the active range's start node."
+ var node = getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+ return isEditable(node) && node.nodeType == Node.TEXT_NODE;
+ })[0];
+ if (node === undefined) {
+ node = getActiveRange().startContainer;
+ }
+ return getEffectiveCommandValue(node, "createlink");
}
};
@@ -3681,6 +3698,28 @@
for (var i = 0; i < hyperlinks.length; i++) {
clearValue(hyperlinks[i], "unlink");
}
+ }, indeterm: function() {
+ // "True if among editable Text nodes that are effectively contained in
+ // the active range, there are two that have distinct effective command
+ // values. Otherwise false."
+ return getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+ return isEditable(node) && node.nodeType == Node.TEXT_NODE;
+ }).map(function(node) {
+ return getEffectiveCommandValue(node, "unlink");
+ }).filter(function(value, i, arr) {
+ return arr.slice(0, i).indexOf(value) == -1;
+ }).length >= 2;
+ }, value: function() {
+ // "The effective command value of the first editable Text node that is
+ // effectively contained in the active range, or if there is no such
+ // node, the effective command value of the active range's start node."
+ var node = getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+ return isEditable(node) && node.nodeType == Node.TEXT_NODE;
+ })[0];
+ if (node === undefined) {
+ node = getActiveRange().startContainer;
+ }
+ return getEffectiveCommandValue(node, "unlink");
}
};
@@ -5967,6 +6006,11 @@
//@}
///// The formatBlock command /////
//@{
+// "A formattable block name is "address", "dd", "div", "dt", "h1", "h2", "h3",
+// "h4", "h5", "h6", "p", or "pre"."
+var formattableBlockNames = ["address", "dd", "div", "dt", "h1", "h2", "h3",
+ "h4", "h5", "h6", "p", "pre"];
+
commands.formatblock = {
action: function(value) {
// "If value begins with a "<" character and ends with a ">" character,
@@ -5978,10 +6022,9 @@
// "Let value be converted to ASCII lowercase."
value = value.toLowerCase();
- // "If value is not "address", "dd", "div", "dt", "h1", "h2", "h3",
- // "h4", "h5", "h6", "p", or "pre", raise a SYNTAX_ERR exception."
- if (["address", "dd", "div", "dt", "h1", "h2", "h3", "h4", "h5", "h6",
- "p", "pre"].indexOf(value) == -1) {
+ // "If value is not a formattable block name, raise a SYNTAX_ERR
+ // exception."
+ if (formattableBlockNames.indexOf(value) == -1) {
throw "SYNTAX_ERR";
}
@@ -6007,17 +6050,16 @@
var values = recordValues(nodeList);
// "For each node in node list, while node is the descendant of an
- // editable HTML element in the same editing host, which has local name
- // "address", "dd", "div", "dt", "h1", "h2", "h3", "h4", "h5", "h6",
- // "p", or "pre", and which is not the ancestor of a prohibited
- // paragraph child, split the parent of the one-node list consisting of
- // node."
+ // editable HTML element in the same editing host, whose local name is
+ // a formattable block name, and which is not the ancestor of a
+ // prohibited paragraph child, split the parent of the one-node list
+ // consisting of node."
for (var i = 0; i < nodeList.length; i++) {
var node = nodeList[i];
while (getAncestors(node).some(function(ancestor) {
return isEditable(ancestor)
&& inSameEditingHost(ancestor, node)
- && isHtmlElement(ancestor, ["address", "dd", "div", "dt", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])
+ && isHtmlElement(ancestor, formattableBlockNames)
&& !getDescendants(ancestor).some(isProhibitedParagraphChild);
})) {
splitParent([node]);
@@ -6111,24 +6153,23 @@
var node = nodeList[i];
// "While node's parent is editable and in the same editing host as
- // node, and node is not an HTML element with local name "address",
- // "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", set
- // node to its parent."
+ // node, and node is not an HTML element whose local name is a
+ // formattable block name, set node to its parent."
while (isEditable(node.parentNode)
&& inSameEditingHost(node, node.parentNode)
- && !isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])) {
+ && !isHtmlElement(node, formattableBlockNames)) {
node = node.parentNode;
}
// "Let current type be the empty string."
var currentType = "";
- // "If node is an editable HTML element with local name "address",
- // "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", and
- // node is not the ancestor of a prohibited paragraph child, set
- // current type to node's local name."
+ // "If node is an editable HTML element whose local name is a
+ // formattable block name, and node is not the ancestor of a
+ // prohibited paragraph child, set current type to node's local
+ // name."
if (isEditable(node)
- && isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])
+ && isHtmlElement(node, formattableBlockNames)
&& !getDescendants(node).some(isProhibitedParagraphChild)) {
currentType = node.tagName;
}
@@ -6163,21 +6204,20 @@
var node = nodes[0];
// "While node's parent is editable and in the same editing host as
- // node, and node is not an HTML element with local name "address",
- // "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", set node
- // to its parent."
+ // node, and node is not an HTML element whose local name is a
+ // formattable block name, set node to its parent."
while (isEditable(node.parentNode)
&& inSameEditingHost(node, node.parentNode)
- && !isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])) {
+ && !isHtmlElement(node, formattableBlockNames)) {
node = node.parentNode;
}
- // "If node is an editable HTML element with local name "address",
- // "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", and node
- // is not the ancestor of a prohibited paragraph child, return node's
- // local name, converted to ASCII lowercase."
+ // "If node is an editable HTML element whose local name is a
+ // formattable block name, and node is not the ancestor of a prohibited
+ // paragraph child, return node's local name, converted to ASCII
+ // lowercase."
if (isEditable(node)
- && isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])
+ && isHtmlElement(node, formattableBlockNames)
&& !getDescendants(node).some(isProhibitedParagraphChild)) {
return node.tagName.toLowerCase();
}
--- a/source.html Thu Jul 14 14:27:17 2011 -0600
+++ b/source.html Thu Jul 14 15:40:44 2011 -0600
@@ -635,8 +635,8 @@
<div class=note>
<p>The methods in this section have mostly been designed so that the following
-invariants hold after <code>execCommand()</code> is called, assuming it didn't
-throw an exception:
+invariants hold after <code title>execCommand()</code> is called, assuming it
+didn't throw an exception:
<ul>
<li><code title>queryCommandIndeterm()</code> will return false (or throw an
@@ -655,11 +655,12 @@
or <code title>underline</code>, because it can be impossible to unset
text-decoration in CSS. Also, by design, the state of <code
title>insertOrderedList</code> and <code title>insertOrderedList</code> might
-not be the opposite after calling as before calling. Finally, the state of the
-various <code title>justify</code> commands should always be true after
-calling, and the value should always be the appropriate string ("center",
-"justify", "left", or "right"). Any other deviations from these invariants are
-bugs in the specification.
+be true both before and after calling, because they only remove one level of
+indentation. <code title>unlink</code> should set the value to null. And
+finally, the state of the various <code title>justify</code> commands should
+always be true after calling, and the value should always be the appropriate
+string ("center", "justify", "left", or "right"). Any other deviations from
+these invariants are bugs in the specification.
</div>
<!-- @} -->
@@ -2490,7 +2491,23 @@
<li><span>Set the selection's value</span> to <var>value</var>.
</ol>
-<p class=XXX>Define state and value, although browsers don't.
+<!-- IE10PP2, Firefox 7.0a2, Chrome 14 dev, and Opera 11.50 all do not support
+indeterminate, state, or value for createLink or unlink. I define
+indeterminate and value anyway because they make sense. -->
+<p><span>Indeterminate</span>: True if among <span>editable</span> [[text]]
+nodes that are <span>effectively contained</span> in the <span>active
+range</span>, there are two that have distinct <span title="effective command
+value">effective command values</span>. Otherwise false.
+
+<p><span>Value</span>: The <span>effective command value</span> of the first
+<span>editable</span> [[text]] node that is <span>effectively contained</span>
+in the <span>active range</span>, or if there is no such node, the
+<span>effective command value</span> of the <span>active range</span>'s
+[[startnode]].
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
<!-- @} -->
<h3><dfn>The <code title>fontName</code> command</dfn></h3>
@@ -3238,6 +3255,25 @@
<li><span>Clear the value</span> of each member of <var>hyperlinks</var>.
</ol>
+
+<!-- IE10PP2, Firefox 7.0a2, Chrome 14 dev, and Opera 11.50 all do not support
+indeterminate, state, or value for createLink or unlink. I define
+indeterminate and value anyway because they make sense. -->
+<p><span>Indeterminate</span>: True if among <span>editable</span> [[text]]
+nodes that are <span>effectively contained</span> in the <span>active
+range</span>, there are two that have distinct <span title="effective command
+value">effective command values</span>. Otherwise false.
+
+<p><span>Value</span>: The <span>effective command value</span> of the first
+<span>editable</span> [[text]] node that is <span>effectively contained</span>
+in the <span>active range</span>, or if there is no such node, the
+<span>effective command value</span> of the <span>active range</span>'s
+[[startnode]].
+
+<p class=note>The effective command value of the active range's start node
+cannot be null, since the boundary point node of a selection must always be
+either an element or a text node that's the child of an element.
+
<!-- @} -->
<h2>Block formatting commands</h2>
@@ -5676,6 +5712,9 @@
sense for <address>/<h*>/<pre>, but other browsers don't do it.
-->
+<p>A <dfn>formattable block name</dfn> is "address", "dd", "div", "dt", "h1",
+"h2", "h3", "h4", "h5", "h6", "p", or "pre".
+
<p><span>Action</span>:
<ol>
@@ -5687,8 +5726,8 @@
<li>Let <var>value</var> be <span data-anolis-spec=domcore>converted to
ASCII lowercase</span>.
- <li>If <var>value</var> is not "address", "dd", "div", "dt", "h1", "h2",
- "h3", "h4", "h5", "h6", "p", or "pre", raise a [[SYNTAX_ERR]] exception.
+ <li>If <var>value</var> is not a <span>formattable block name</span>, raise a
+ [[SYNTAX_ERR]] exception.
<!--
Opera 11.10 throws NOT_SUPPORTED_ERR for bad elements, all other tested
browsers ignore the input. Testing in IE9, Firefox 4.0, Chrome 13 dev, and
@@ -5727,11 +5766,10 @@
<li>For each <var>node</var> in <var>node list</var>, while <var>node</var>
is the [[descendant]] of an <span>editable</span> <span>HTML element</span>
- <span>in the same editing host</span>, which has [[localname]] "address",
- "dd", "div", "dt", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", and
- which is not the [[ancestor]] of a <span>prohibited paragraph child</span>,
- <span>split the parent</span> of the one-[[node]] list consisting of
- <var>node</var>.
+ <span>in the same editing host</span>, whose [[localname]] is a
+ <span>formattable block name</span>, and which is not the [[ancestor]] of a
+ <span>prohibited paragraph child</span>, <span>split the parent</span> of the
+ one-[[node]] list consisting of <var>node</var>.
<!--
This tries to avoid misnesting if only some lines of an element are selected,
so <h1>[foo]<br>bar</h1> becomes <p>[foo]</p><h1>bar</h1> instead of
@@ -5866,15 +5904,15 @@
<ol>
<li>While <var>node</var>'s [[parent]] is <span>editable</span> and
<span>in the same editing host</span> as <var>node</var>, and
- <var>node</var> is not an <span>HTML element</span> with [[localname]]
- "address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", set
- <var>node</var> to its [[parent]].
+ <var>node</var> is not an <span>HTML element</span> whose [[localname]]
+ is a <span>formattable block name</span>, set <var>node</var> to its
+ [[parent]].
<li>Let <var>current type</var> be the empty string.
<li>If <var>node</var> is an <span>editable</span> <span>HTML
- element</span> with [[localname]] "address", "div", "h1", "h2", "h3", "h4",
- "h5", "h6", "p", or "pre", and <var>node</var> is not the [[ancestor]] of a
+ element</span> whose [[localname]] is a <span>formattable block
+ name</span>, and <var>node</var> is not the [[ancestor]] of a
<span>prohibited paragraph child</span>, set <var>current type</var> to
<var>node</var>'s [[localname]].
@@ -5914,15 +5952,15 @@
<li>While <var>node</var>'s [[parent]] is <span>editable</span> and <span>in
the same editing host</span> as <var>node</var>, and <var>node</var> is not
- an <span>HTML element</span> with [[localname]] "address", "div", "h1", "h2",
- "h3", "h4", "h5", "h6", "p", or "pre", set <var>node</var> to its [[parent]].
+ an <span>HTML element</span> whose [[localname]] is a <span>formattable block
+ name</span>, set <var>node</var> to its [[parent]].
<!-- Opera 11.11 doesn't require it be editable, so it will return "DIV"
instead of "" for <div contenteditable>foo</div>. -->
<li>If <var>node</var> is an <span>editable</span> <span>HTML element</span>
- with [[localname]] "address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p",
- or "pre", and <var>node</var> is not the [[ancestor]] of a <span>prohibited
- paragraph child</span>, return <var>node</var>'s [[localname]], <span
+ whose [[localname]] is a <span>formattable block name</span>, and
+ <var>node</var> is not the [[ancestor]] of a <span>prohibited paragraph
+ child</span>, return <var>node</var>'s [[localname]], <span
data-anolis-spec=domcore>converted to ASCII lowercase</span>.
<!--
Chrome 14 dev will report "div" for <div><ol><li>foo</ol></div> or such.
--- a/tests.js Thu Jul 14 14:27:17 2011 -0600
+++ b/tests.js Thu Jul 14 15:40:44 2011 -0600
@@ -3393,6 +3393,13 @@
}
//@}
+function trivialPrettyPrint(value) {
+ if (typeof value == "string") {
+ return '"' + value.replace(/\\/g, "\\\\").replace(/"/g, '\\"') + '"';
+ }
+ return value;
+}
+
function queryOutputHelper(beforeIndeterm, beforeState, beforeValue, afterIndeterm, afterState, afterValue, command, value) {
//@{
var frag = document.createDocumentFragment();
@@ -3406,46 +3413,87 @@
beforeDiv.appendChild(document.createElement("span"));
afterDiv.appendChild(document.createElement("span"));
- if (afterIndeterm !== "Exception") {
+ if ("indeterm" in commands[command]) {
+ // We only know it has to be either true or false.
+ if (beforeIndeterm !== true && beforeIndeterm !== false) {
+ beforeDiv.lastChild.className = "bad-result";
+ }
+ } else {
+ // It always has to be an exception.
+ beforeDiv.lastChild.className = beforeIndeterm === "Exception"
+ ? "good-result"
+ : "bad-result";
+ }
+ // After running the command, indeterminate must always be false, except if
+ // it's an exception, or if it's insert*list and the state was true to
+ // begin with.
+ if (/^insert(un)?orderedlist$/.test(command) && beforeState) {
+ if (afterIndeterm !== true && afterIndeterm !== false) {
+ afterDiv.lastChild.className = "bad-result";
+ }
+ } else {
afterDiv.lastChild.className =
- !afterIndeterm
+ ("indeterm" in commands[command] && afterIndeterm === false)
+ || (!("indeterm" in commands[command]) && afterIndeterm === "Exception")
? "good-result"
: "bad-result";
}
- beforeDiv.lastChild.textContent = "indeterm " + beforeIndeterm;
- afterDiv.lastChild.textContent = "indeterm " + afterIndeterm;
+ beforeDiv.lastChild.textContent = "indeterm " + trivialPrettyPrint(beforeIndeterm);
+ afterDiv.lastChild.textContent = "indeterm " + trivialPrettyPrint(afterIndeterm);
beforeDiv.appendChild(document.createTextNode(", "));
afterDiv.appendChild(document.createTextNode(", "));
beforeDiv.appendChild(document.createElement("span"));
afterDiv.appendChild(document.createElement("span"));
- if ((beforeState !== "Exception" || afterState !== "Exception")
- && !/insert(un)?orderedlist|justify(center|full|left|right)/.test(command)) {
+ if (/^insert(un)?orderedlist$/.test(command)) {
+ // If the before state is true, the after state could be either true or
+ // false. But if the before state is false, the after state has to be
+ // true.
+ if (beforeState !== true && beforeState !== false) {
+ beforeDiv.lastChild.className = "bad-result";
+ }
+ if (!beforeState) {
+ afterDiv.lastChild.className = afterState === true
+ ? "good-result"
+ : "bad-result";
+ } else if (afterState !== true && afterState !== false) {
+ afterDiv.lastChild.className = "bad-result";
+ }
+ } else if (/^justify(center|full|left|right)$/.test(command)) {
+ // We don't know about the before state, but the after state is always
+ // supposed to be true.
+ if (beforeState !== true && beforeState !== false) {
+ beforeDiv.lastChild.className = "bad-result";
+ }
+ afterDiv.lastChild.className = afterState === true
+ ? "good-result"
+ : "bad-result";
+ } else {
+ // The general rule is it must either throw an exception or flip the
+ // state.
beforeDiv.lastChild.className =
afterDiv.lastChild.className =
- beforeState !== "Exception" && afterState !== "Exception" && beforeState === !afterState
+ ("state" in commands[command] && typeof beforeState == "boolean" && typeof afterState == "boolean" && beforeState === !afterState)
+ || (!("state" in commands[command]) && beforeState === "Exception" && afterState === "Exception")
? "good-result"
: "bad-result";
}
- if (/^justify(center|full|left|right)$/.test(command)) {
- afterDiv.lastChild.className =
- beforeState !== "Exception" && afterState !== "Exception" && afterState
- ? "good-result"
- : "bad-result";
- }
- beforeDiv.lastChild.textContent = "state " + beforeState;
- afterDiv.lastChild.textContent = "state " + afterState;
+ beforeDiv.lastChild.textContent = "state " + trivialPrettyPrint(beforeState);
+ afterDiv.lastChild.textContent = "state " + trivialPrettyPrint(afterState);
beforeDiv.appendChild(document.createTextNode(", "));
afterDiv.appendChild(document.createTextNode(", "));
+ beforeDiv.appendChild(document.createElement("span"));
+ afterDiv.appendChild(document.createElement("span"));
+
+ // Direct equality comparison doesn't make sense in a bunch of cases.
if (command == "backcolor" || command == "forecolor" || command == "hilitecolor") {
if (/^([0-9a-fA-F]{3}){1,2}$/.test(value)) {
value = "#" + value;
}
- }
- if (command == "fontsize") {
+ } else if (command == "fontsize") {
value = normalizeFontSize(value);
var font = document.createElement("font");
document.body.appendChild(font);
@@ -3456,27 +3504,42 @@
}
value = getLegacyFontSize(parseInt(getComputedStyle(font).fontSize));
document.body.removeChild(font);
+ } else if (command == "formatblock") {
+ value = value.replace(/^<(.*)>$/, "$1").toLowerCase();
+ } else if (command == "unlink") {
+ value = null;
}
- beforeDiv.appendChild(document.createElement("span"));
- afterDiv.appendChild(document.createElement("span"));
- if (afterValue !== "Exception"
- && typeof value != "undefined") {
+ if (/^justify(center|full|left|right)$/.test(command)) {
+ // We know there are only four correct values beforehand, and afterward
+ // the value has to be the one we set.
+ if (!/^(center|justify|left|right)$/.test(beforeValue)) {
+ beforeDiv.lastChild.className = "bad-result";
+ }
+ var expectedValue = command == "justifyfull"
+ ? "justify"
+ : command.replace("justify", "");
+ afterDiv.lastChild.className = afterValue === expectedValue
+ ? "good-result"
+ : "bad-result";
+ } else if (!("value" in commands[command])) {
+ // As usual, if it's not defined we want an exception.
+ beforeDiv.lastChild.className = beforeValue === "Exception"
+ ? "good-result"
+ : "bad-result";
+ afterDiv.lastChild.className = afterValue === "Exception"
+ ? "good-result"
+ : "bad-result";
+ } else {
+ // And in all other cases, the value afterwards has to be the one we
+ // set.
afterDiv.lastChild.className =
valuesEqual(command, afterValue, value)
? "good-result"
: "bad-result";
}
- if (/^justify(center|full|left|right)$/.test(command)) {
- var expectedValue = command == "justifyfull"
- ? "justify"
- : command.replace("justify", "");
- afterDiv.lastChild.className = afterValue == expectedValue
- ? "good-result"
- : "bad-result";
- }
- beforeDiv.lastChild.textContent = "value " + beforeValue;
- afterDiv.lastChild.textContent = "value " + afterValue;
+ beforeDiv.lastChild.textContent = "value " + trivialPrettyPrint(beforeValue);
+ afterDiv.lastChild.textContent = "value " + trivialPrettyPrint(afterValue);
return frag;
}