Better "enabled" definition
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Wed, 29 Jun 2011 13:56:28 -0600
changeset 350 911e460f1ac5
parent 349 341946338bf7
child 351 b5ccdd3f1c55
Better "enabled" definition

This actually allows everything else to be defined a bit more cleanly,
since I no longer need to say out-of-band that some commands need to not
do anything if there's no active range.
editcommands.html
implementation.js
source.html
--- a/editcommands.html	Wed Jun 29 13:24:28 2011 -0600
+++ b/editcommands.html	Wed Jun 29 13:56:28 2011 -0600
@@ -69,7 +69,11 @@
  <li><a class=no-num href=#table-of-contents>Table of contents</a></li>
  <li><a href=#introduction><span class=secno>1 </span>Introduction</a></li>
  <li><a href=#issues><span class=secno>2 </span>Issues</a></li>
- <li><a href=#basic-concepts><span class=secno>3 </span>Basic concepts</a></li>
+ <li><a href=#commands><span class=secno>3 </span>Commands</a>
+  <ol>
+   <li><a href=#properties-of-commands><span class=secno>3.1 </span>Properties of commands</a></li>
+   <li><a href=#supported-commands><span class=secno>3.2 </span>Supported commands</a></li>
+   <li><a href=#enabled-commands><span class=secno>3.3 </span>Enabled commands</a></ol></li>
  <li><a href=#methods-of-the-htmldocument-interface><span class=secno>4 </span>Methods of the <code class=external data-anolis-spec=html>HTMLDocument</code> interface</a></li>
  <li><a href=#common-definitions><span class=secno>5 </span>Common definitions</a></li>
  <li><a href=#common-algorithms><span class=secno>6 </span>Common algorithms</a>
@@ -322,7 +326,9 @@
 like this.
 
 
-<h2 id=basic-concepts><span class=secno>3 </span>Basic concepts</h2>
+<h2 id=commands><span class=secno>3 </span>Commands</h2>
+
+<h3 id=properties-of-commands><span class=secno>3.1 </span>Properties of commands</h3>
 
 <p>This specification defines a number of <dfn id=command title=command>commands</dfn>,
 identified by <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#ascii-case-insensitive>ASCII case-insensitive</a>
@@ -386,19 +392,8 @@
   <a href=#relevant-css-property>relevant CSS property</a> specified, it defaults to null.
 </ul>
 
-<p>If the <a href=#active-range>active range</a> is null, then every <a href=#command>command</a> in
-this specification must behave as though its <a href=#action>action</a> is to do
-nothing, its <a href=#indeterminate title=indeterminate>indeterminacy</a> is false (if it has
-any associated <a href=#indeterminate title=indeterminate>indeterminacy</a>), its
-<a href=#state>state</a> is false (if it has any associated <a href=#state>state</a>), and
-its <a href=#value>value</a> is the empty string (if it has any associated
-<a href=#value>value</a>).  However, the <a href=#command title=command>commands</a> listed
-under <a href=#miscellaneous-commands>Miscellaneous commands</a> must behave as
-usual even if the <a href=#active-range>active range</a> is null.
-<!--
-This matches Firefox 6.0a2 and Opera 11.11.  IE9 and Chrome 14 dev seem to
-return false for the value in this case.
--->
+
+<h3 id=supported-commands><span class=secno>3.2 </span>Supported commands</h3>
 
 <p>Some <a href=#command title=command>commands</a> will be <dfn id=supported>supported</dfn> in a
 given user agent, and some will not.  All <a href=#command title=command>commands</a>
@@ -436,37 +431,21 @@
 using <code><a href=#querycommandsupported()>queryCommandSupported()</a></code>.
 
 
-<h2 id=methods-of-the-htmldocument-interface><span class=secno>4 </span>Methods of the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface</h2>
-
-<p>When the <dfn id=execcommand() title=execCommand()><code>execCommand(<var title="">command</var>,
-<var title="">show UI</var>, <var title="">value</var>)</code></dfn> method on the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface is invoked, the user agent
-must follow the <a href=#action>action</a> instructions given in this specification
-for <var title="">command</var>, passing <var title="">value</var> to the instructions as an
-argument, then return true.  If <var title="">command</var> is not
-<a href=#supported>supported</a>, the user agent must instead raise a
-<code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.  If <var title="">command</var> is
-<a href=#supported>supported</a> but has no associated <a href=#action>action</a> (which is not
-the case for any <a href=#command>command</a> defined in this specification), the user
-agent must instead raise an <code class=external data-anolis-spec=domcore title=dom-DOMException-INVALID_ACCESS_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-invalid_access_err>INVALID_ACCESS_ERR</a></code> exception.
-<!-- I'm just speccing INVALID_ACCESS_ERR for consistency.  I don't expect
-real-world commands are likely to not have an action defined, but you never
-know. -->
-
-<p class=XXX>WebKit doesn't always return true (and maybe others also).  Needs
-investigation: should we ever return false, and if so when?
-
-<p class=XXX>Define behavior for <var title="">show UI</var>.
-
-<p>When the <dfn id=querycommandenabled() title=queryCommandEnabled()><code>queryCommandEnabled(<var title="">command</var>)</code></dfn>
-method on the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface is
-invoked, the user agent must return true.  If <var title="">command</var> is not
-<a href=#supported>supported</a>, the user agent must instead raise a
-<code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.
-
-<p class=XXX>This is useless and not how anyone behaves, but no one's behavior
-is very useful anyway.  For this to make sense would require a significant
-amount of work and it's not clear it's worth it at all.  See comment for
-details.
+<h3 id=enabled-commands><span class=secno>3.3 </span>Enabled commands</h3>
+
+<p>At any given time, a <a href=#supported>supported</a> command can be either
+<dfn id=enabled>enabled</dfn> or not.  Authors can tell whether a <a href=#command>command</a> is
+currently <a href=#enabled>enabled</a> using <code><a href=#querycommandenabled()>queryCommandEnabled()</a></code>.  <a href=#command title=command>Commands</a> that are not <a href=#enabled>enabled</a> do nothing, as
+described in the definitions of the various methods that invoke <a href=#command title=command>commands</a>.
+
+<p>Among <a href=#command title=command>commands</a> defined in this specification,
+those listed in <a href=#miscellaneous-commands>Miscellaneous commands</a> are
+always <a href=#enabled>enabled</a>.  The other <a href=#command title=command>commands</a>
+defined here are <a href=#enabled>enabled</a> if the <a href=#active-range>active range</a> is not
+null, and are not <a href=#enabled>enabled</a> if it is.
+
+<p class=XXX>Not clear that this definition is right.  It doesn't match any
+browser.  Needs more testing and thought.
 <!--
 Testing with bold and formatBlock:
 
@@ -486,19 +465,76 @@
 even if there's some non-editable stuff around.
 
 What we really want this to do is return true if we'd do something when you run
-the command, false otherwise.  This will actually vary by command, and is
-nontrivial, and I'm not sure what the use-case is.  So for now I'll go with
-Opera, but I'll return to it later.
+the command, false otherwise.  But that's impractically complicated for little
+benefit.  Some approximation closer to IE or Chrome is likely in order.
 -->
 
+
+
+<h2 id=methods-of-the-htmldocument-interface><span class=secno>4 </span>Methods of the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface</h2>
+
+<p>When the <dfn id=execcommand() title=execCommand()><code>execCommand(<var title="">command</var>,
+<var title="">show UI</var>, <var title="">value</var>)</code></dfn> method on the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface is invoked, the user agent
+must run the following steps:
+
+<ol>
+  <li>If <var title="">command</var> is not <a href=#supported>supported</a>, raise a
+  <code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.
+
+  <li>If <var title="">command</var> has no <a href=#action>action</a>, raise an
+  <code class=external data-anolis-spec=domcore title=dom-DOMException-INVALID_ACCESS_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-invalid_access_err>INVALID_ACCESS_ERR</a></code> exception.
+
+  <p class=note>No such <a href=#command>command</a> is defined in this specification.
+  <!-- I'm just speccing INVALID_ACCESS_ERR for consistency.  I don't expect
+  real-world commands are likely to not have an action defined, but you never
+  know. -->
+
+  <li>If <var title="">command</var> is not <a href=#enabled>enabled</a>, return false.
+  <!--
+  I didn't research this closely, but at a first glance, this is possibly how
+  Chrome 14 dev and Opera 11.11 behave.  Maybe also Firefox 6.0a2, except it
+  throws if the command isn't enabled, I think.  IE9 returns true in at least
+  some cases even if the command is disabled.
+  -->
+  <p class=XXX>Is this right?  Maybe we should be returning false in other
+  cases too?
+
+  <li>Take the <a href=#action>action</a> for <var title="">command</var>, passing
+  <var title="">value</var> to the instructions as an argument.
+
+  <li>Return true.
+</ol>
+
+<p class=XXX>Define behavior for <var title="">show UI</var>.
+
+<p>When the <dfn id=querycommandenabled() title=queryCommandEnabled()><code>queryCommandEnabled(<var title="">command</var>)</code></dfn>
+method on the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface is
+invoked, the user agent must run the following steps:
+
+<ol>
+  <li>If <var title="">command</var> is not <a href=#supported>supported</a>, raise a
+  <code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.
+
+  <li>Return true if <var title="">command</var> is <a href=#enabled>enabled</a>, false
+  otherwise.
+</ol>
+
 <p>When the <dfn id=querycommandindeterm() title=queryCommandIndeterm()><code>queryCommandIndeterm(<var title="">command</var>)</code></dfn>
 method on the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface is
-invoked, the user agent must return true if <var title="">command</var> is
-<a href=#indeterminate>indeterminate</a>, otherwise false.  If <var title="">command</var> is not
-<a href=#supported>supported</a>, the user agent must instead raise a
-<code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.  If <var title="">command</var> is
-<a href=#supported>supported</a> but has no associated <a href=#indeterminate title=indeterminate>indeterminacy</a> definition, the user agent must
-instead raise an <code class=external data-anolis-spec=domcore title=dom-DOMException-INVALID_ACCESS_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-invalid_access_err>INVALID_ACCESS_ERR</a></code> exception.
+invoked, the user agent must run the following steps:
+
+<ol>
+  <li>If <var title="">command</var> is not <a href=#supported>supported</a>, raise a
+  <code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.
+
+  <li>If <var title="">command</var> has no <a href=#indeterminate title=indeterminate>indeterminacy</a>, raise an <code class=external data-anolis-spec=domcore title=dom-DOMException-INVALID_ACCESS_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-invalid_access_err>INVALID_ACCESS_ERR</a></code>
+  exception.
+
+  <li>If <var title="">command</var> is not <a href=#enabled>enabled</a>, return false.
+
+  <li>Return true if <var title="">command</var> is <a href=#indeterminate>indeterminate</a>,
+  otherwise false.
+</ol>
 <!--
 What happens if you call queryCommand(Indeterm|State|Value)() on a command
 where it makes no sense?
@@ -526,12 +562,20 @@
 
 <p>When the <dfn id=querycommandstate() title=queryCommandState()><code>queryCommandState(<var title="">command</var>)</code></dfn>
 method on the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface is
-invoked, the user agent must return the <a href=#state>state</a> for
-<var title="">command</var>.  If <var title="">command</var> is not <a href=#supported>supported</a>, the
-user agent must instead raise a <code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.  If
-<var title="">command</var> is <a href=#supported>supported</a> but has no associated
-<a href=#state>state</a>, the user agent must instead raise an <code class=external data-anolis-spec=domcore title=dom-DOMException-INVALID_ACCESS_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-invalid_access_err>INVALID_ACCESS_ERR</a></code>
-exception.
+invoked, the user agent must run the following steps:
+
+<ol>
+  <li>If <var title="">command</var> is not <a href=#supported>supported</a>, raise a
+  <code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.
+
+  <li>If <var title="">command</var> has no <a href=#state>state</a>, raise an
+  <code class=external data-anolis-spec=domcore title=dom-DOMException-INVALID_ACCESS_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-invalid_access_err>INVALID_ACCESS_ERR</a></code> exception.
+
+  <li>If <var title="">command</var> is not <a href=#enabled>enabled</a>, return false.
+
+  <li>Return true if <var title="">command</var>'s <a href=#state>state</a> is true, otherwise
+  false.
+</ol>
 
 <p>When the <dfn id=querycommandsupported() title=queryCommandSupported()><code>queryCommandSupported(<var title="">command</var>)</code></dfn>
 method on the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface is
@@ -550,12 +594,23 @@
 
 <p>When the <dfn id=querycommandvalue() title=queryCommandValue()><code>queryCommandValue(<var title="">command</var>)</code></dfn>
 method on the <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#htmldocument>HTMLDocument</a></code> interface is
-invoked, the user agent must return the <a href=#value>value</a> for
-<var title="">command</var>.  If <var title="">command</var> is not <a href=#supported>supported</a>, the
-user agent must instead raise a <code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.  If
-<var title="">command</var> is <a href=#supported>supported</a> but has no associated
-<a href=#value>value</a>, the user agent must instead raise an <code class=external data-anolis-spec=domcore title=dom-DOMException-INVALID_ACCESS_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-invalid_access_err>INVALID_ACCESS_ERR</a></code>
-exception.
+invoked, the user agent must run the following steps:
+
+<ol>
+  <li>If <var title="">command</var> is not <a href=#supported>supported</a>, raise a
+  <code class=external data-anolis-spec=domcore title=dom-DOMException-NOT_SUPPORTED_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-not_supported_err>NOT_SUPPORTED_ERR</a></code> exception.
+
+  <li>If <var title="">command</var> has no <a href=#value>value</a>, raise an
+  <code class=external data-anolis-spec=domcore title=dom-DOMException-INVALID_ACCESS_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-invalid_access_err>INVALID_ACCESS_ERR</a></code> exception.
+
+  <li>If <var title="">command</var> is not <a href=#enabled>enabled</a>, return the empty
+  string.
+  <!-- This is what Firefox 6.0a2 and Opera 11.11 seem to do.  Chrome 14 dev
+  seems to return the string "false", and IE9 seems to return boolean false.
+  -->
+
+  <li>Return <var title="">command</var>'s <a href=#value>value</a>.
+</ol>
 
 <p>All of these methods must treat their <var title="">command</var> argument <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#ascii-case-insensitive title="ASCII case-insensitive">ASCII
 case-insensitively</a>.
--- a/implementation.js	Wed Jun 29 13:24:28 2011 -0600
+++ b/implementation.js	Wed Jun 29 13:56:28 2011 -0600
@@ -499,12 +499,7 @@
 /////////////////////////////////////////////////
 //@{
 
-// Helper function for common behavior.  First throws exceptions if the command
-// is unrecognized or doesn't have the thing we want defined (action, indeterm,
-// state, or value).  If we get past that, return false if the global range is
-// null and we're a non-miscellaneous command, otherwise true.  Called by
-// myExecCommand(), myQueryCommandIndeterm(), myQueryCommandState(),
-// myQueryCommandValue(), since they all have this behavior.
+// Helper function for common behavior.
 function setupEditCommandMethod(command, prop, range) {
 	// Set up our global range magic
 	if (typeof range != "undefined") {
@@ -513,115 +508,132 @@
 		globalRange = getActiveRange();
 	}
 
-	// In all cases we throw NOT_SUPPORTED_ERR here.  Of course we can't
-	// actually do that, so we just throw a string.
+	// "If command is not supported, raise a NOT_SUPPORTED_ERR exception."
+	//
+	// We can't throw a real one, but a string will do for our purposes.
 	if (!(command in commands)) {
 		throw "NOT_SUPPORTED_ERR";
 	}
 
-	// Likewise, here we throw INVALID_ACCESS_ERR for all four callers.
+	// "If command has no action, raise an INVALID_ACCESS_ERR exception."
+	// "If command has no indeterminacy, raise an INVALID_ACCESS_ERR
+	// exception."
+	// "If command has no state, raise an INVALID_ACCESS_ERR exception."
+	// "If command has no value, raise an INVALID_ACCESS_ERR exception."
 	if (!(prop in commands[command])) {
 		throw "INVALID_ACCESS_ERR";
 	}
-
-	// "If the active range is null, then every command in this specification
-	// must behave as though its action is to do nothing, its indeterminacy is
-	// false (if it has any associated indeterminacy), its state is false (if
-	// it has any associated state), and its value is the empty string (if it
-	// has any associated value). However, the commands listed under
-	// Miscellaneous commands must behave as usual even if the active range is
-	// null."
-	//
-	// We convey this by returning false.
-	return globalRange || ["copy", "cut", "paste", "selectall", "stylewithcss", "usecss"].indexOf(command) != -1;
 }
 
-// "When the execCommand(command, show UI, value) method on the HTMLDocument
-// interface is invoked, the user agent must follow the action instructions
-// given in this specification for command, passing value to the instructions
-// as an argument, then return true. If command is not supported, the user
-// agent must instead raise a NOT_SUPPORTED_ERR exception. If command is
-// supported but has no associated action (which is not the case for any
-// command defined in this specification), the user agent must instead raise an
-// INVALID_ACCESS_ERR exception."
-//
-// "All of these methods must treat their command argument ASCII
-// case-insensitively."
 function myExecCommand(command, showUi, value, range) {
+	// "All of these methods must treat their command argument ASCII
+	// case-insensitively."
 	command = command.toLowerCase();
 
-	if (setupEditCommandMethod(command, "action", range)) {
-		commands[command].action(value);
-	}
-
+	// "If command is not supported, raise a NOT_SUPPORTED_ERR exception."
+	//
+	// "If command has no action, raise an INVALID_ACCESS_ERR exception."
+	setupEditCommandMethod(command, "action", range);
+
+	// "If command is not enabled, return false."
+	if (!myQueryCommandEnabled(command, range)) {
+		return false;
+	}
+
+	// "Take the action for command, passing value to the instructions as an
+	// argument."
+	commands[command].action(value);
+
+	// "Return true."
 	return true;
 }
 
-// "When the queryCommandEnabled(command) method on the HTMLDocument interface
-// is invoked, the user agent must return true. If command is not supported,
-// the user agent must instead raise a NOT_SUPPORTED_ERR exception."
 function myQueryCommandEnabled(command, range) {
+	// "All of these methods must treat their command argument ASCII
+	// case-insensitively."
 	command = command.toLowerCase();
 
+	// "If command is not supported, raise a NOT_SUPPORTED_ERR exception."
 	if (!(command in commands)) {
 		throw "NOT_SUPPORTED_ERR";
 	}
 
-	return true;
+	// "Return true if command is enabled, false otherwise."
+	//
+	// "Among commands defined in this specification, those listed in
+	// Miscellaneous commands are always enabled. The other commands defined
+	// here are enabled if the active range is not null, and are not enabled if
+	// it is."
+	return getActiveRange() || ["copy", "cut", "paste", "selectall", "stylewithcss", "usecss"].indexOf(command) != -1;
 }
 
-// "When the queryCommandIndeterm(command) method on the HTMLDocument interface
-// is invoked, the user agent must return true if command is indeterminate,
-// otherwise false. If command is not supported, the user agent must instead
-// raise a NOT_SUPPORTED_ERR exception. If command is supported but has no
-// associated indeterminacy definition, the user agent must instead raise an
-// INVALID_ACCESS_ERR exception."
 function myQueryCommandIndeterm(command, range) {
+	// "All of these methods must treat their command argument ASCII
+	// case-insensitively."
 	command = command.toLowerCase();
 
-	if (setupEditCommandMethod(command, "indeterm", range)) {
-		return commands[command].indeterm();
-	} else {
+	// "If command is not supported, raise a NOT_SUPPORTED_ERR exception."
+	//
+	// "If command has no indeterminacy, raise an INVALID_ACCESS_ERR
+	// exception."
+	setupEditCommandMethod(command, "indeterm", range);
+
+	// "If command is not enabled, return false."
+	if (!myQueryCommandEnabled(command, range)) {
 		return false;
 	}
+
+	// "Return true if command is indeterminate, otherwise false."
+	return commands[command].indeterm();
 }
 
-// "When the queryCommandState(command) method on the HTMLDocument interface is
-// invoked, the user agent must return the state for command. If command is not
-// supported, the user agent must instead raise a NOT_SUPPORTED_ERR exception.
-// If command is supported but has no associated state, the user agent must
-// instead raise an INVALID_ACCESS_ERR exception."
 function myQueryCommandState(command, range) {
+	// "All of these methods must treat their command argument ASCII
+	// case-insensitively."
 	command = command.toLowerCase();
 
-	if (setupEditCommandMethod(command, "state", range)) {
-		return commands[command].state();
-	} else {
+	// "If command is not supported, raise a NOT_SUPPORTED_ERR exception."
+	//
+	// "If command has no state, raise an INVALID_ACCESS_ERR exception."
+	setupEditCommandMethod(command, "state", range);
+
+	// "If command is not enabled, return false."
+	if (!myQueryCommandEnabled(command, range)) {
 		return false;
 	}
+
+	// "Return true if command's state is true, otherwise false."
+	return commands[command].state();
 }
 
 // "When the queryCommandSupported(command) method on the HTMLDocument
 // interface is invoked, the user agent must return true if command is
 // supported, and false otherwise."
-function myQueryCommandSupported(command, range) {
+function myQueryCommandSupported(command) {
+	// "All of these methods must treat their command argument ASCII
+	// case-insensitively."
 	command = command.toLowerCase();
+
 	return command in commands;
 }
 
-// "When the queryCommandValue(command) method on the HTMLDocument interface is
-// invoked, the user agent must return the value for command. If command is not
-// supported, the user agent must instead raise a NOT_SUPPORTED_ERR exception.
-// If command is supported but has no associated value, the user agent must
-// instead raise an INVALID_ACCESS_ERR exception."
 function myQueryCommandValue(command, range) {
+	// "All of these methods must treat their command argument ASCII
+	// case-insensitively."
 	command = command.toLowerCase();
 
-	if (setupEditCommandMethod(command, "value", range)) {
-		return commands[command].value();
-	} else {
+	// "If command is not supported, raise a NOT_SUPPORTED_ERR exception."
+	//
+	// "If command has no value, raise an INVALID_ACCESS_ERR exception."
+	setupEditCommandMethod(command, "value", range);
+
+	// "If command is not enabled, return the empty string."
+	if (!myQueryCommandEnabled(command, range)) {
 		return "";
 	}
+
+	// "Return command's value."
+	return commands[command].value();
 }
 //@}
 
--- a/source.html	Wed Jun 29 13:24:28 2011 -0600
+++ b/source.html	Wed Jun 29 13:56:28 2011 -0600
@@ -255,7 +255,9 @@
 like this.
 <!-- @} -->
 
-<h2>Basic concepts</h2>
+<h2>Commands</h2>
+
+<h3>Properties of commands</h3>
 <!-- @{ -->
 <p>This specification defines a number of <dfn title=command>commands</dfn>,
 identified by <span data-anolis-spec=domcore>ASCII case-insensitive</span>
@@ -324,21 +326,10 @@
   and is not exposed to authors.  If a <span>command</span> does not have a
   <span>relevant CSS property</span> specified, it defaults to null.
 </ul>
-
-<p>If the <span>active range</span> is null, then every <span>command</span> in
-this specification must behave as though its <span>action</span> is to do
-nothing, its <span title=indeterminate>indeterminacy</span> is false (if it has
-any associated <span title=indeterminate>indeterminacy</span>), its
-<span>state</span> is false (if it has any associated <span>state</span>), and
-its <span>value</span> is the empty string (if it has any associated
-<span>value</span>).  However, the <span title=command>commands</span> listed
-under <a href=#miscellaneous-commands>Miscellaneous commands</a> must behave as
-usual even if the <span>active range</span> is null.
-<!--
-This matches Firefox 6.0a2 and Opera 11.11.  IE9 and Chrome 14 dev seem to
-return false for the value in this case.
--->
-
+<!-- @} -->
+
+<h3>Supported commands</h3>
+<!-- @{ -->
 <p>Some <span title=command>commands</span> will be <dfn>supported</dfn> in a
 given user agent, and some will not.  All <span title=command>commands</span>
 defined in this specification must be <span>supported</span>, except optionally
@@ -376,39 +367,23 @@
 using <code>queryCommandSupported()</code>.
 <!-- @} -->
 
-<h2>Methods of the <code data-anolis-spec=html>HTMLDocument</code> interface</h2>
+<h3>Enabled commands</h3>
 <!-- @{ -->
-<p>When the <dfn title=execCommand()><code>execCommand(<var>command</var>,
-<var>show UI</var>, <var>value</var>)</code></dfn> method on the <code
-data-anolis-spec=html>HTMLDocument</code> interface is invoked, the user agent
-must follow the <span>action</span> instructions given in this specification
-for <var>command</var>, passing <var>value</var> to the instructions as an
-argument, then return true.  If <var>command</var> is not
-<span>supported</span>, the user agent must instead raise a
-[[NOT_SUPPORTED_ERR]] exception.  If <var>command</var> is
-<span>supported</span> but has no associated <span>action</span> (which is not
-the case for any <span>command</span> defined in this specification), the user
-agent must instead raise an [[INVALID_ACCESS_ERR]] exception.
-<!-- I'm just speccing INVALID_ACCESS_ERR for consistency.  I don't expect
-real-world commands are likely to not have an action defined, but you never
-know. -->
-
-<p class=XXX>WebKit doesn't always return true (and maybe others also).  Needs
-investigation: should we ever return false, and if so when?
-
-<p class=XXX>Define behavior for <var>show UI</var>.
-
-<p>When the <dfn
-title=queryCommandEnabled()><code>queryCommandEnabled(<var>command</var>)</code></dfn>
-method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
-invoked, the user agent must return true.  If <var>command</var> is not
-<span>supported</span>, the user agent must instead raise a
-[[NOT_SUPPORTED_ERR]] exception.
-
-<p class=XXX>This is useless and not how anyone behaves, but no one's behavior
-is very useful anyway.  For this to make sense would require a significant
-amount of work and it's not clear it's worth it at all.  See comment for
-details.
+<p>At any given time, a <span>supported</span> command can be either
+<dfn>enabled</dfn> or not.  Authors can tell whether a <span>command</span> is
+currently <span>enabled</span> using <code>queryCommandEnabled()</code>.  <span
+title=command>Commands</span> that are not <span>enabled</span> do nothing, as
+described in the definitions of the various methods that invoke <span
+title=command>commands</span>.
+
+<p>Among <span title=command>commands</span> defined in this specification,
+those listed in <a href=#miscellaneous-commands>Miscellaneous commands</a> are
+always <span>enabled</span>.  The other <span title=command>commands</span>
+defined here are <span>enabled</span> if the <span>active range</span> is not
+null, and are not <span>enabled</span> if it is.
+
+<p class=XXX>Not clear that this definition is right.  It doesn't match any
+browser.  Needs more testing and thought.
 <!--
 Testing with bold and formatBlock:
 
@@ -428,21 +403,80 @@
 even if there's some non-editable stuff around.
 
 What we really want this to do is return true if we'd do something when you run
-the command, false otherwise.  This will actually vary by command, and is
-nontrivial, and I'm not sure what the use-case is.  So for now I'll go with
-Opera, but I'll return to it later.
+the command, false otherwise.  But that's impractically complicated for little
+benefit.  Some approximation closer to IE or Chrome is likely in order.
 -->
+<!-- @} -->
+
+
+<h2>Methods of the <code data-anolis-spec=html>HTMLDocument</code> interface</h2>
+<!-- @{ -->
+<p>When the <dfn title=execCommand()><code>execCommand(<var>command</var>,
+<var>show UI</var>, <var>value</var>)</code></dfn> method on the <code
+data-anolis-spec=html>HTMLDocument</code> interface is invoked, the user agent
+must run the following steps:
+
+<ol>
+  <li>If <var>command</var> is not <span>supported</span>, raise a
+  [[NOT_SUPPORTED_ERR]] exception.
+
+  <li>If <var>command</var> has no <span>action</span>, raise an
+  [[INVALID_ACCESS_ERR]] exception.
+
+  <p class=note>No such <span>command</span> is defined in this specification.
+  <!-- I'm just speccing INVALID_ACCESS_ERR for consistency.  I don't expect
+  real-world commands are likely to not have an action defined, but you never
+  know. -->
+
+  <li>If <var>command</var> is not <span>enabled</span>, return false.
+  <!--
+  I didn't research this closely, but at a first glance, this is possibly how
+  Chrome 14 dev and Opera 11.11 behave.  Maybe also Firefox 6.0a2, except it
+  throws if the command isn't enabled, I think.  IE9 returns true in at least
+  some cases even if the command is disabled.
+  -->
+  <p class=XXX>Is this right?  Maybe we should be returning false in other
+  cases too?
+
+  <li>Take the <span>action</span> for <var>command</var>, passing
+  <var>value</var> to the instructions as an argument.
+
+  <li>Return true.
+</ol>
+
+<p class=XXX>Define behavior for <var>show UI</var>.
+
+<p>When the <dfn
+title=queryCommandEnabled()><code>queryCommandEnabled(<var>command</var>)</code></dfn>
+method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
+invoked, the user agent must run the following steps:
+
+<ol>
+  <li>If <var>command</var> is not <span>supported</span>, raise a
+  [[NOT_SUPPORTED_ERR]] exception.
+
+  <li>Return true if <var>command</var> is <span>enabled</span>, false
+  otherwise.
+</ol>
 
 <p>When the <dfn
 title=queryCommandIndeterm()><code>queryCommandIndeterm(<var>command</var>)</code></dfn>
 method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
-invoked, the user agent must return true if <var>command</var> is
-<span>indeterminate</span>, otherwise false.  If <var>command</var> is not
-<span>supported</span>, the user agent must instead raise a
-[[NOT_SUPPORTED_ERR]] exception.  If <var>command</var> is
-<span>supported</span> but has no associated <span
-title=indeterminate>indeterminacy</span> definition, the user agent must
-instead raise an [[INVALID_ACCESS_ERR]] exception.
+invoked, the user agent must run the following steps:
+
+<ol>
+  <li>If <var>command</var> is not <span>supported</span>, raise a
+  [[NOT_SUPPORTED_ERR]] exception.
+
+  <li>If <var>command</var> has no <span
+  title=indeterminate>indeterminacy</span>, raise an [[INVALID_ACCESS_ERR]]
+  exception.
+
+  <li>If <var>command</var> is not <span>enabled</span>, return false.
+
+  <li>Return true if <var>command</var> is <span>indeterminate</span>,
+  otherwise false.
+</ol>
 <!--
 What happens if you call queryCommand(Indeterm|State|Value)() on a command
 where it makes no sense?
@@ -471,12 +505,20 @@
 <p>When the <dfn
 title=queryCommandState()><code>queryCommandState(<var>command</var>)</code></dfn>
 method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
-invoked, the user agent must return the <span>state</span> for
-<var>command</var>.  If <var>command</var> is not <span>supported</span>, the
-user agent must instead raise a [[NOT_SUPPORTED_ERR]] exception.  If
-<var>command</var> is <span>supported</span> but has no associated
-<span>state</span>, the user agent must instead raise an [[INVALID_ACCESS_ERR]]
-exception.
+invoked, the user agent must run the following steps:
+
+<ol>
+  <li>If <var>command</var> is not <span>supported</span>, raise a
+  [[NOT_SUPPORTED_ERR]] exception.
+
+  <li>If <var>command</var> has no <span>state</span>, raise an
+  [[INVALID_ACCESS_ERR]] exception.
+
+  <li>If <var>command</var> is not <span>enabled</span>, return false.
+
+  <li>Return true if <var>command</var>'s <span>state</span> is true, otherwise
+  false.
+</ol>
 
 <p>When the <dfn
 title=queryCommandSupported()><code>queryCommandSupported(<var>command</var>)</code></dfn>
@@ -497,12 +539,23 @@
 <p>When the <dfn
 title=queryCommandValue()><code>queryCommandValue(<var>command</var>)</code></dfn>
 method on the <code data-anolis-spec=html>HTMLDocument</code> interface is
-invoked, the user agent must return the <span>value</span> for
-<var>command</var>.  If <var>command</var> is not <span>supported</span>, the
-user agent must instead raise a [[NOT_SUPPORTED_ERR]] exception.  If
-<var>command</var> is <span>supported</span> but has no associated
-<span>value</span>, the user agent must instead raise an [[INVALID_ACCESS_ERR]]
-exception.
+invoked, the user agent must run the following steps:
+
+<ol>
+  <li>If <var>command</var> is not <span>supported</span>, raise a
+  [[NOT_SUPPORTED_ERR]] exception.
+
+  <li>If <var>command</var> has no <span>value</span>, raise an
+  [[INVALID_ACCESS_ERR]] exception.
+
+  <li>If <var>command</var> is not <span>enabled</span>, return the empty
+  string.
+  <!-- This is what Firefox 6.0a2 and Opera 11.11 seem to do.  Chrome 14 dev
+  seems to return the string "false", and IE9 seems to return boolean false.
+  -->
+
+  <li>Return <var>command</var>'s <span>value</span>.
+</ol>
 
 <p>All of these methods must treat their <var>command</var> argument <span
 data-anolis-spec=domcore title="ASCII case-insensitive">ASCII