Define state for insert*List, document research
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Mon, 27 Jun 2011 12:56:46 -0600
changeset 323 31db5f77c92d
parent 322 1d74af5b8d37
child 324 3d6fc8f9a040
Define state for insert*List, document research
editcommands.html
implementation.js
source.html
--- a/editcommands.html	Mon Jun 27 12:02:23 2011 -0600
+++ b/editcommands.html	Mon Jun 27 12:56:46 2011 -0600
@@ -38,7 +38,7 @@
 <body class=draft>
 <div class=head id=head>
 <h1>HTML Editing Commands</h1>
-<h2 class="no-num no-toc" id=work-in-progress-&mdash;-last-update-23-june-2011>Work in Progress &mdash; Last Update 23 June 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-&mdash;-last-update-27-june-2011>Work in Progress &mdash; Last Update 27 June 2011</h2>
 <dl>
  <dt>Editor
  <dd>Aryeh Gregor &lt;ayg+spec@aryeh.name&gt;
@@ -2017,10 +2017,17 @@
 is <a href=#effectively-contained>effectively contained</a> in the <a href=#active-range>active range</a> has
 <a href=#effective-value>effective value</a> at least 700, and there is at least one such
 <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.  Otherwise false.
-<!-- For bold and similar commands, IE 9 RC seems to consider the state true or
+<!--
+For bold and similar commands, IE 9 RC seems to consider the state true or
 false depending on the first element.  All other browsers follow the same
 general idea as the spec, considering a range bold only if all text in it is
-bold, and this seems to match at least OpenOffice.org's bold feature. -->
+bold, and this seems to match at least OpenOffice.org's bold feature.  Opera
+11.11 seemingly doesn't take CSS into account, and only looks at whether
+something descends from a <b>.  I couldn't properly test IE9 because it threw
+exceptions (Error: Unspecified error.) on most of the tests I ran.  But what I
+have here seems to match Firefox 6.0a2 in every case, and Chrome 14 dev in all
+cases with a few exceptions.
+-->
 
 <p><a href=#relevant-css-property>Relevant CSS property</a>: "font-weight"
 
@@ -2077,6 +2084,13 @@
   <var title="">value</var>.
 </ol>
 
+<!--
+The state is always false in Chrome 14 dev and Opera 11.11.  Firefox 6.0a2
+throws an exception, and IE9 seems to always either return false or throw an
+exception.  Therefore we make the state always false, although this doesn't
+seem very useful.
+-->
+
 <!-- I'd have expected the value to be the URL, but guess not: it's always
 false. -->
 
@@ -5489,6 +5503,43 @@
 <p><a href=#action>Action</a>: <a href=#toggle-lists>Toggle lists</a> with <var title="">tag name</var>
 "ol".
 
+<p><a href=#state>State</a>:
+<!--
+Logically, this should return true if running the command would remove ordered
+lists, false if it would add them, just like for bold etc.  So I copy-paste the
+logic from there.  Note that when we actually run the command, we'll normalize
+sublists, but not just when we query.  This probably doesn't make a difference,
+but I'm not totally sure.
+
+IE9 throws exceptions in most cases, Firefox 6.0a2 in some cases as well, for
+no apparent reason.  Ignoring those, the spec basically matches all browsers,
+except with a few weird random mismatches that looked like browser bugs to me.
+-->
+<p class=XXX>Does the fact that we don't normalize sublists before running this
+mean that it might produce results that don't match the way the action will
+behave?
+
+<ol>
+  <li><a href=#block-extend>Block-extend</a> the <a href=#active-range>active range</a>, and let <var title="">new
+  range</var> be the result.
+
+  <li>Let <var title="">node list</var> be a list of <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a>, initially empty.
+
+  <li>For each <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> <var title="">node</var> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">new range</var>,
+  if <var title="">node</var> is <a href=#editable>editable</a>; the last member of <var title="">node
+  list</var> (if any) is not an <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 <var title="">node</var>;
+  <var title="">node</var> is not a <a href=#potential-indentation-element>potential indentation element</a>; and
+  either <var title="">node</var> is an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, or 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> is an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code>
+  or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, or it is an <a href=#allowed-child>allowed child</a> of "li"; then append
+  <var title="">node</var> to <var title="">node list</var>.
+
+  <li>If every member of <var title="">node list</var> is equal to or the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of
+  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> "ol", and no member of
+  <var title="">node list</var> is equal to or 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 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> "ul", then return true.  Otherwise, return
+  false.
+</ol>
+
 
 <h3 id=the-insertparagraph-command><span class=secno>7.18 </span><dfn>The <code title="">insertParagraph</code> command</dfn></h3>
 
@@ -5934,6 +5985,33 @@
 <p><a href=#action>Action</a>: <a href=#toggle-lists>Toggle lists</a> with <var title="">tag name</var>
 "ul".
 
+<p><a href=#state>State</a>:
+<!-- See insertOrderedList for comments. -->
+<p class=XXX>Does the fact that we don't normalize sublists before running this
+mean that it might produce results that don't match the way the action will
+behave?
+
+<ol>
+  <li><a href=#block-extend>Block-extend</a> the <a href=#active-range>active range</a>, and let <var title="">new
+  range</var> be the result.
+
+  <li>Let <var title="">node list</var> be a list of <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a>, initially empty.
+
+  <li>For each <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> <var title="">node</var> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">new range</var>,
+  if <var title="">node</var> is <a href=#editable>editable</a>; the last member of <var title="">node
+  list</var> (if any) is not an <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 <var title="">node</var>;
+  <var title="">node</var> is not a <a href=#potential-indentation-element>potential indentation element</a>; and
+  either <var title="">node</var> is an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code> or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, or 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> is an <code class=external data-anolis-spec=html title="the ol element"><a href=http://www.whatwg.org/html/#the-ol-element>ol</a></code>
+  or <code class=external data-anolis-spec=html title="the ul element"><a href=http://www.whatwg.org/html/#the-ul-element>ul</a></code>, or it is an <a href=#allowed-child>allowed child</a> of "li"; then append
+  <var title="">node</var> to <var title="">node list</var>.
+
+  <li>If every member of <var title="">node list</var> is equal to or the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> of
+  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> "ul", and no member of
+  <var title="">node list</var> is equal to or 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 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> "ol", then return true.  Otherwise, return
+  false.
+</ol>
+
 
 <h3 id=the-justifycenter-command><span class=secno>7.21 </span><dfn>The <code title="">justifyCenter</code> command</dfn></h3>
 
--- a/implementation.js	Mon Jun 27 12:02:23 2011 -0600
+++ b/implementation.js	Mon Jun 27 12:56:46 2011 -0600
@@ -5732,7 +5732,36 @@
 //@{
 commands.insertorderedlist = {
 	// "Toggle lists with tag name "ol"."
-	action: function() { toggleLists("ol") }
+	action: function() { toggleLists("ol") },
+	state: function() {
+		// "Block-extend the active range, and let new range be the result."
+		var newRange = blockExtendRange(getActiveRange());
+
+		// "Let node list be a list of nodes, initially empty."
+		//
+		// "For each node node contained in new range, if node is editable; the
+		// last member of node list (if any) is not an ancestor of node; node
+		// is not a potential indentation element; and either node is an ol or
+		// ul, or its parent is an ol or ul, or it is an allowed child of "li";
+		// then append node to node list."
+		var nodeList = collectContainedNodes(newRange, function(node) {
+			return isEditable(node)
+				&& !isPotentialIndentationElement(node)
+				&& (isHtmlElement(node, ["ol", "ul"])
+				|| isHtmlElement(node.parentNode, ["ol", "ul"])
+				|| isAllowedChild(node, "li"));
+		});
+
+		// "If every member of node list is equal to or the child of an HTML
+		// element with local name "ol", and no member of node list is equal to
+		// or the ancestor of an HTML element with local name "ul", then return
+		// true. Otherwise, return false."
+		return nodeList.every(function(node) {
+			return (isHtmlElement(node, "ol") || isHtmlElement(node.parentNode, "ol"))
+				&& !isHtmlElement(node, "ul")
+				&& !node.querySelector("ul");
+		});
+	},
 };
 //@}
 
@@ -6113,7 +6142,36 @@
 //@{
 commands.insertunorderedlist = {
 	// "Toggle lists with tag name "ul"."
-	action: function() { toggleLists("ul") }
+	action: function() { toggleLists("ul") },
+	state: function() {
+		// "Block-extend the active range, and let new range be the result."
+		var newRange = blockExtendRange(getActiveRange());
+
+		// "Let node list be a list of nodes, initially empty."
+		//
+		// "For each node node contained in new range, if node is editable; the
+		// last member of node list (if any) is not an ancestor of node; node
+		// is not a potential indentation element; and either node is an ol or
+		// ul, or its parent is an ol or ul, or it is an allowed child of "li";
+		// then append node to node list."
+		var nodeList = collectContainedNodes(newRange, function(node) {
+			return isEditable(node)
+				&& !isPotentialIndentationElement(node)
+				&& (isHtmlElement(node, ["ol", "ul"])
+				|| isHtmlElement(node.parentNode, ["ol", "ul"])
+				|| isAllowedChild(node, "li"));
+		});
+
+		// "If every member of node list is equal to or the child of an HTML
+		// element with local name "ul", and no member of node list is equal to
+		// or the ancestor of an HTML element with local name "ol", then return
+		// true. Otherwise, return false."
+		return nodeList.every(function(node) {
+			return (isHtmlElement(node, "ul") || isHtmlElement(node.parentNode, "ul"))
+				&& !isHtmlElement(node, "ol")
+				&& !node.querySelector("ol");
+		});
+	},
 };
 //@}
 
--- a/source.html	Mon Jun 27 12:02:23 2011 -0600
+++ b/source.html	Mon Jun 27 12:56:46 2011 -0600
@@ -1993,10 +1993,17 @@
 is <span>effectively contained</span> in the <span>active range</span> has
 <span>effective value</span> at least 700, and there is at least one such
 [[text]] node.  Otherwise false.
-<!-- For bold and similar commands, IE 9 RC seems to consider the state true or
+<!--
+For bold and similar commands, IE 9 RC seems to consider the state true or
 false depending on the first element.  All other browsers follow the same
 general idea as the spec, considering a range bold only if all text in it is
-bold, and this seems to match at least OpenOffice.org's bold feature. -->
+bold, and this seems to match at least OpenOffice.org's bold feature.  Opera
+11.11 seemingly doesn't take CSS into account, and only looks at whether
+something descends from a <b>.  I couldn't properly test IE9 because it threw
+exceptions (Error: Unspecified error.) on most of the tests I ran.  But what I
+have here seems to match Firefox 6.0a2 in every case, and Chrome 14 dev in all
+cases with a few exceptions.
+-->
 
 <p><span>Relevant CSS property</span>: "font-weight"
 <!-- @} -->
@@ -2053,6 +2060,13 @@
   <var>value</var>.
 </ol>
 
+<!--
+The state is always false in Chrome 14 dev and Opera 11.11.  Firefox 6.0a2
+throws an exception, and IE9 seems to always either return false or throw an
+exception.  Therefore we make the state always false, although this doesn't
+seem very useful.
+-->
+
 <!-- I'd have expected the value to be the URL, but guess not: it's always
 false. -->
 <!-- @} -->
@@ -5500,6 +5514,43 @@
 <!-- @{ -->
 <p><span>Action</span>: <span>Toggle lists</span> with <var>tag name</var>
 "ol".
+
+<p><span>State</span>:
+<!--
+Logically, this should return true if running the command would remove ordered
+lists, false if it would add them, just like for bold etc.  So I copy-paste the
+logic from there.  Note that when we actually run the command, we'll normalize
+sublists, but not just when we query.  This probably doesn't make a difference,
+but I'm not totally sure.
+
+IE9 throws exceptions in most cases, Firefox 6.0a2 in some cases as well, for
+no apparent reason.  Ignoring those, the spec basically matches all browsers,
+except with a few weird random mismatches that looked like browser bugs to me.
+-->
+<p class=XXX>Does the fact that we don't normalize sublists before running this
+mean that it might produce results that don't match the way the action will
+behave?
+
+<ol>
+  <li><span>Block-extend</span> the <span>active range</span>, and let <var>new
+  range</var> be the result.
+
+  <li>Let <var>node list</var> be a list of [[nodes]], initially empty.
+
+  <li>For each [[node]] <var>node</var> [[contained]] in <var>new range</var>,
+  if <var>node</var> is <span>editable</span>; the last member of <var>node
+  list</var> (if any) is not an [[ancestor]] of <var>node</var>;
+  <var>node</var> is not a <span>potential indentation element</span>; and
+  either <var>node</var> is an [[ol]] or [[ul]], or its [[parent]] is an [[ol]]
+  or [[ul]], or it is an <span>allowed child</span> of "li"; then append
+  <var>node</var> to <var>node list</var>.
+
+  <li>If every member of <var>node list</var> is equal to or the [[child]] of
+  an <span>HTML element</span> with [[localname]] "ol", and no member of
+  <var>node list</var> is equal to or the [[ancestor]] of an <span>HTML
+  element</span> with [[localname]] "ul", then return true.  Otherwise, return
+  false.
+</ol>
 <!-- @} -->
 
 <h3><dfn>The <code title>insertParagraph</code> command</dfn></h3>
@@ -5953,6 +6004,33 @@
 <!-- @{ -->
 <p><span>Action</span>: <span>Toggle lists</span> with <var>tag name</var>
 "ul".
+
+<p><span>State</span>:
+<!-- See insertOrderedList for comments. -->
+<p class=XXX>Does the fact that we don't normalize sublists before running this
+mean that it might produce results that don't match the way the action will
+behave?
+
+<ol>
+  <li><span>Block-extend</span> the <span>active range</span>, and let <var>new
+  range</var> be the result.
+
+  <li>Let <var>node list</var> be a list of [[nodes]], initially empty.
+
+  <li>For each [[node]] <var>node</var> [[contained]] in <var>new range</var>,
+  if <var>node</var> is <span>editable</span>; the last member of <var>node
+  list</var> (if any) is not an [[ancestor]] of <var>node</var>;
+  <var>node</var> is not a <span>potential indentation element</span>; and
+  either <var>node</var> is an [[ol]] or [[ul]], or its [[parent]] is an [[ol]]
+  or [[ul]], or it is an <span>allowed child</span> of "li"; then append
+  <var>node</var> to <var>node list</var>.
+
+  <li>If every member of <var>node list</var> is equal to or the [[child]] of
+  an <span>HTML element</span> with [[localname]] "ul", and no member of
+  <var>node list</var> is equal to or the [[ancestor]] of an <span>HTML
+  element</span> with [[localname]] "ol", then return true.  Otherwise, return
+  false.
+</ol>
 <!-- @} -->
 
 <h3><dfn>The <code title>justifyCenter</code> command</dfn></h3>