--- a/autoimplementation.html Thu Jun 02 12:43:16 2011 -0600
+++ b/autoimplementation.html Thu Jun 02 14:34:46 2011 -0600
@@ -1455,6 +1455,162 @@
'foo [bar <i>baz] qoz</i> quz sic',
'foo bar <i>baz [qoz</i> quz] sic',
],
+ justifycenter: [
+ 'foo[]bar<p>extra',
+ '<span>foo</span>{}<span>bar</span><p>extra',
+ '<span>foo[</span><span>]bar</span><p>extra',
+ 'foo[bar]baz<p>extra',
+ 'foo[bar<b>baz]qoz</b>quz<p>extra',
+ '<p>foo[]bar<p>extra',
+ '<p>foo[bar]baz<p>extra',
+ '<h1>foo[bar]baz</h1><p>extra',
+ '<pre>foo[bar]baz</pre><p>extra',
+ '<xmp>foo[bar]baz</xmp><p>extra',
+ '{<table><tr><td>foo<td>bar</table>}<p>extra',
+ '<center><p>[foo]<p>bar</center><p>extra',
+ '<center><p>[foo<p>bar]</center><p>extra',
+
+ '<div align=center><p>[foo]<p>bar</div><p>extra',
+ '<div align=center><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:center><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:center><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=justify><p>[foo]<p>bar</div><p>extra',
+ '<div align=justify><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:justify><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:justify><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=left><p>[foo]<p>bar</div><p>extra',
+ '<div align=left><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:left><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:left><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=right><p>[foo]<p>bar</div><p>extra',
+ '<div align=right><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:right><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:right><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=nonsense><p>[foo]</div><p>extra',
+ '<div style=text-align:inherit><p>[foo]</div><p>extra',
+ '<quasit align=right><p>[foo]</p></quasit><p>extra',
+ ],
+ justifyfull: [
+ 'foo[]bar<p>extra',
+ '<span>foo</span>{}<span>bar</span><p>extra',
+ '<span>foo[</span><span>]bar</span><p>extra',
+ 'foo[bar]baz<p>extra',
+ 'foo[bar<b>baz]qoz</b>quz<p>extra',
+ '<p>foo[]bar<p>extra',
+ '<p>foo[bar]baz<p>extra',
+ '<h1>foo[bar]baz</h1><p>extra',
+ '<pre>foo[bar]baz</pre><p>extra',
+ '<xmp>foo[bar]baz</xmp><p>extra',
+ '{<table><tr><td>foo<td>bar</table>}<p>extra',
+ '<center><p>[foo]<p>bar</center><p>extra',
+ '<center><p>[foo<p>bar]</center><p>extra',
+
+ '<div align=center><p>[foo]<p>bar</div><p>extra',
+ '<div align=center><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:center><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:center><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=justify><p>[foo]<p>bar</div><p>extra',
+ '<div align=justify><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:justify><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:justify><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=left><p>[foo]<p>bar</div><p>extra',
+ '<div align=left><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:left><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:left><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=right><p>[foo]<p>bar</div><p>extra',
+ '<div align=right><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:right><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:right><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=nonsense><p>[foo]</div><p>extra',
+ '<div style=text-align:inherit><p>[foo]</div><p>extra',
+ '<quasit align=center><p>[foo]</p></quasit><p>extra',
+ ],
+ justifyleft: [
+ 'foo[]bar<p>extra',
+ '<span>foo</span>{}<span>bar</span><p>extra',
+ '<span>foo[</span><span>]bar</span><p>extra',
+ 'foo[bar]baz<p>extra',
+ 'foo[bar<b>baz]qoz</b>quz<p>extra',
+ '<p>foo[]bar<p>extra',
+ '<p>foo[bar]baz<p>extra',
+ '<h1>foo[bar]baz</h1><p>extra',
+ '<pre>foo[bar]baz</pre><p>extra',
+ '<xmp>foo[bar]baz</xmp><p>extra',
+ '{<table><tr><td>foo<td>bar</table>}<p>extra',
+ '<center><p>[foo]<p>bar</center><p>extra',
+ '<center><p>[foo<p>bar]</center><p>extra',
+
+ '<div align=center><p>[foo]<p>bar</div><p>extra',
+ '<div align=center><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:center><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:center><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=justify><p>[foo]<p>bar</div><p>extra',
+ '<div align=justify><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:justify><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:justify><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=left><p>[foo]<p>bar</div><p>extra',
+ '<div align=left><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:left><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:left><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=right><p>[foo]<p>bar</div><p>extra',
+ '<div align=right><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:right><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:right><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=nonsense><p>[foo]</div><p>extra',
+ '<div style=text-align:inherit><p>[foo]</div><p>extra',
+ '<quasit align=center><p>[foo]</p></quasit><p>extra',
+ ],
+ justifyright: [
+ 'foo[]bar<p>extra',
+ '<span>foo</span>{}<span>bar</span><p>extra',
+ '<span>foo[</span><span>]bar</span><p>extra',
+ 'foo[bar]baz<p>extra',
+ 'foo[bar<b>baz]qoz</b>quz<p>extra',
+ '<p>foo[]bar<p>extra',
+ '<p>foo[bar]baz<p>extra',
+ '<h1>foo[bar]baz</h1><p>extra',
+ '<pre>foo[bar]baz</pre><p>extra',
+ '<xmp>foo[bar]baz</xmp><p>extra',
+ '{<table><tr><td>foo<td>bar</table>}<p>extra',
+ '<center><p>[foo]<p>bar</center><p>extra',
+ '<center><p>[foo<p>bar]</center><p>extra',
+
+ '<div align=center><p>[foo]<p>bar</div><p>extra',
+ '<div align=center><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:center><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:center><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=justify><p>[foo]<p>bar</div><p>extra',
+ '<div align=justify><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:justify><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:justify><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=left><p>[foo]<p>bar</div><p>extra',
+ '<div align=left><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:left><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:left><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=right><p>[foo]<p>bar</div><p>extra',
+ '<div align=right><p>[foo<p>bar}</div><p>extra',
+ '<div style=text-align:right><p>[foo]<p>bar</div><p>extra',
+ '<div style=text-align:right><p>[foo<p>bar]</div><p>extra',
+
+ '<div align=nonsense><p>[foo]</div><p>extra',
+ '<div style=text-align:inherit><p>[foo]</div><p>extra',
+ '<quasit align=center><p>[foo]</p></quasit><p>extra',
+ ],
outdent: [
// These mimic existing indentation in various browsers, to see how
// they cope with outdenting various things. This is spec, Gecko
@@ -1964,6 +2120,10 @@
"fontsize",
"forecolor",
"italic",
+ "justifycenter",
+ "justifyfull",
+ "justifyleft",
+ "justifyright",
"strikethrough",
"subscript",
"superscript",
--- a/editcommands.html Thu Jun 02 12:43:16 2011 -0600
+++ b/editcommands.html Thu Jun 02 14:34: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-—-last-update-31-may-2011>Work in Progress — Last Update 31 May 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-—-last-update-2-june-2011>Work in Progress — Last Update 2 June 2011</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <ayg+spec@aryeh.name>
@@ -104,13 +104,18 @@
<li><a href=#block-formatting-a-node-list><span class=secno>7.4 </span>Block-formatting a node list</a></li>
<li><a href=#outdenting-a-node><span class=secno>7.5 </span>Outdenting a node</a></li>
<li><a href=#toggling-lists><span class=secno>7.6 </span>Toggling lists</a></li>
- <li><a href=#the-formatblock-command><span class=secno>7.7 </span>The <code title="">formatBlock</code> command</a></li>
- <li><a href=#the-indent-command><span class=secno>7.8 </span>The <code title="">indent</code> command</a></li>
- <li><a href=#the-inserthorizontalrule-command><span class=secno>7.9 </span>The <code title="">insertHorizontalRule</code> command</a></li>
- <li><a href=#the-insertorderedlist-command><span class=secno>7.10 </span>The <code title="">insertOrderedList</code> command</a></li>
- <li><a href=#the-insertparagraph-command><span class=secno>7.11 </span>The <code title="">insertParagraph</code> command</a></li>
- <li><a href=#the-insertunorderedlist-command><span class=secno>7.12 </span>The <code title="">insertUnorderedList</code> command</a></li>
- <li><a href=#the-outdent-command><span class=secno>7.13 </span>The <code title="">outdent</code> command</a></ol></li>
+ <li><a href=#justifying-the-selection><span class=secno>7.7 </span>Justifying the selection</a></li>
+ <li><a href=#the-formatblock-command><span class=secno>7.8 </span>The <code title="">formatBlock</code> command</a></li>
+ <li><a href=#the-indent-command><span class=secno>7.9 </span>The <code title="">indent</code> command</a></li>
+ <li><a href=#the-inserthorizontalrule-command><span class=secno>7.10 </span>The <code title="">insertHorizontalRule</code> command</a></li>
+ <li><a href=#the-insertorderedlist-command><span class=secno>7.11 </span>The <code title="">insertOrderedList</code> command</a></li>
+ <li><a href=#the-insertparagraph-command><span class=secno>7.12 </span>The <code title="">insertParagraph</code> command</a></li>
+ <li><a href=#the-insertunorderedlist-command><span class=secno>7.13 </span>The <code title="">insertUnorderedList</code> command</a></li>
+ <li><a href=#the-justifycenter-command><span class=secno>7.14 </span>The <code title="">justifyCenter</code> command</a></li>
+ <li><a href=#the-justifyfull-command><span class=secno>7.15 </span>The <code title="">justifyFull</code> command</a></li>
+ <li><a href=#the-justifyleft-command><span class=secno>7.16 </span>The <code title="">justifyLeft</code> command</a></li>
+ <li><a href=#the-justifyright-command><span class=secno>7.17 </span>The <code title="">justifyRight</code> command</a></li>
+ <li><a href=#the-outdent-command><span class=secno>7.18 </span>The <code title="">outdent</code> command</a></ol></li>
<li><a href=#miscellaneous-commands><span class=secno>8 </span>Miscellaneous commands</a>
<ol>
<li><a href=#the-stylewithcss-command><span class=secno>8.1 </span>The <code title="">styleWithCSS</code> command</a></li>
@@ -1106,14 +1111,11 @@
There's code for these in WebKit, Source/WebCore/editing/EditorCommand.cpp,
but I didn't see them mentioned elsewhere. Some might be worth adding.
-Things I haven't looked at:
+Things I haven't looked at that multiple browsers implement:
* copy, cut, paste: Needs attention to security.
* delete, redo, undo: Needs review of the Google work on this; will probably be
quite complicated.
-* justifyCenter, justifyFull, justifyLeft, justifyRight: These look important
- and should be similar to work I've already done, so they're
- next on my list.
* selectAll, unselect: Should be easy, although they seem redundant to just
calling methods of the Selection.
-->
@@ -4058,7 +4060,123 @@
</ol>
-<h3 id=the-formatblock-command><span class=secno>7.7 </span><dfn>The <code title="">formatBlock</code> command</dfn></h3>
+<h3 id=justifying-the-selection><span class=secno>7.7 </span>Justifying the selection</h3>
+<!--
+There are two basic ways it works: using the align attribute, and using CSS
+text-align. IE9 and Opera 11.11 use only the align attribute, Chrome 13 dev
+uses only text-align, and Firefox 5.0a2 varies based on styleWithCSS. The two
+ways produce entirely different results, which is a real problem, so I don't
+think Firefox's approach is tenable. text-align is more valid, and for typical
+contenteditable cases it works the same. But for cases where you have
+fixed-width blocks, like tables or just divs with a width set, it behaves
+differently, and in those cases the align attribute is more useful.
+-->
+
+<p>To <dfn id=justify-the-selection>justify the selection</dfn> to a string <var title="">alignment</var> (either
+"center", "justify", "left", or "right"):
+
+<p class=XXX>text-align doesn't behave as expected if there are descendant
+blocks with non-100% width, like tables. The align attribute behaves a lot
+more nicely in such cases, but it's not valid. Not clear what to do. For now
+I've stuck with text-align, just because the cases where it misbehaves can't be
+created by any sequence of stock execCommand()s that I know of, but this needs
+more careful consideration. Gecko in CSS mode seems to special-case tables,
+adding auto margins to the table element to get it to align correctly.
+
+<p class=XXX>Need to do something along the lines of pushing down values here
+(although no browser does). In fact, it's very likely this can be rewritten in
+terms of the inline formatting command primitives, but it's not clear if it
+would be worth the added complexity.
+
+<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="">element list</var> be a list of all <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#element>Element</a></code>s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">new range</var> that either has an
+ attribute in the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#html-namespace>HTML namespace</a> whose <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-local-name title=concept-attr-local-name>local name</a> is "align", or has
+ a <code class=external data-anolis-spec=html title="the style attribute"><a href=http://www.whatwg.org/html/#the-style-attribute>style</a></code> attribute that sets "text-align", or is a <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#center>center</a></code>.
+ <!-- No browser actually removes center, but it makes sense to do so. -->
+
+ <li>For each <var title="">element</var> in <var title="">element list</var>:
+
+ <ol>
+ <li>If <var title="">element</var> has an attribute in the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#html-namespace>HTML namespace</a> whose
+ <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-local-name title=concept-attr-local-name>local name</a> is "align", remove that attribute.
+
+ <li>Unset the CSS property "text-align" on <var title="">element</var>, if it's set
+ by a <code class=external data-anolis-spec=html title="the style attribute"><a href=http://www.whatwg.org/html/#the-style-attribute>style</a></code> attribute.
+
+ <li>If <var title="">element</var> is a <code class=external data-anolis-spec=html title="the div element"><a href=http://www.whatwg.org/html/#the-div-element>div</a></code> or <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#center>center</a></code> with no attributes, remove it,
+ <a href=#preserving-its-descendants>preserving its descendants</a>.
+
+ <li>If <var title="">element</var> is a <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#center>center</a></code>
+ with one or more attributes, <a href=#set-the-tag-name>set the tag name</a> of
+ <var title="">element</var> to "div".
+ </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.
+ <!-- This could theoretically be necessary, like if it converted "<div
+ align=right>foo</div>bar" to "foo<br>bar". Now we need to select "foo<br>",
+ nor just "foo". -->
+
+ <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>,
+ append <var title="">node</var> to <var title="">node list</var> if 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 <a href=#editable>editable</a>; and either <var title="">node</var> is an
+ <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code> and the CSS property "text-align" does not compute to
+ <var title="">alignment</var> on it, or it is not an <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code>, but 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=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code>, and the CSS property "text-align" does not compute to
+ <var title="">alignment</var> on 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>.
+ <!-- Of tested browsers, only Chrome 13 dev seems to not apply the alignment
+ to nodes that are already aligned. Even then, it does apply it if the
+ alignment is just inherited from the root. -->
+
+ <p class=XXX>What does this imply when text-align is "start" or "end"? As
+ with lots of CSS stuff in this spec, needs to be clarified.
+
+ <li>While <var title="">node list</var> is not empty:
+
+ <ol>
+ <li>Let <var title="">sublist</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>Remove the first member of <var title="">node list</var> and append it to
+ <var title="">sublist</var>.
+
+ <li>While <var title="">node list</var> is not empty, and the first member of
+ <var title="">node list</var> is the <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code> of the last member of
+ <var title="">sublist</var>, remove the first member of <var title="">node list</var> and
+ append it to <var title="">sublist</var>.
+
+ <li><a href=#wrap>Wrap</a> <var title="">sublist</var>. <a href=#sibling-criteria>Sibling criteria</a>
+ match any <code class=external data-anolis-spec=html title="the div element"><a href=http://www.whatwg.org/html/#the-div-element>div</a></code> that has one or both of the following two attributes, and
+ no other attributes:
+
+ <ul>
+ <li>An <code class=external data-anolis-spec=html title=attr-div-align><a href=http://www.whatwg.org/html/#attr-div-align>align</a></code>
+ attribute whose <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-value title=concept-attr-value>value</a> is an <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> match for <var title="">alignment</var>.
+
+ <li>A <code class=external data-anolis-spec=html title="the style attribute"><a href=http://www.whatwg.org/html/#the-style-attribute>style</a></code> attribute which sets exactly one CSS property (including
+ unrecognized or invalid attributes), which is "text-align", which is set
+ to <var title="">alignment</var>.
+ </ul>
+
+ <a href=#new-parent-instructions>New parent instructions</a> are to call <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("div")</a></code> on
+ the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>, then set its CSS property "text-align" to
+ <var title="">alignment</var>, and return the result.
+ <!-- As for inline formatting, I only ever create new elements, and don't
+ ever modify existing ones. This doesn't match how any browser behaves
+ in this case, but for inline formatting it matches everyone but Gecko's CSS
+ mode. -->
+ </ol>
+</ol>
+
+
+<h3 id=the-formatblock-command><span class=secno>7.8 </span><dfn>The <code title="">formatBlock</code> command</dfn></h3>
<!--
Tested browser versions: IE9, Firefox 4.0, Chrome 13 dev, Opera 11.10.
@@ -4142,7 +4260,7 @@
</ol>
-<h3 id=the-indent-command><span class=secno>7.8 </span><dfn>The <code title="">indent</code> command</dfn></h3>
+<h3 id=the-indent-command><span class=secno>7.9 </span><dfn>The <code title="">indent</code> command</dfn></h3>
<!--
IE9: Outputs <blockquote style="margin-right: 0px" dir="ltr">, or when
surrounding RTL blocks, <blockquote style="margin-left: 0px" dir="rtl">. The
@@ -4245,7 +4363,7 @@
</ol>
-<h3 id=the-inserthorizontalrule-command><span class=secno>7.9 </span><dfn>The <code title="">insertHorizontalRule</code> command</dfn></h3>
+<h3 id=the-inserthorizontalrule-command><span class=secno>7.10 </span><dfn>The <code title="">insertHorizontalRule</code> command</dfn></h3>
<p><a href=#action>Action</a>:
@@ -4299,13 +4417,13 @@
</ol>
-<h3 id=the-insertorderedlist-command><span class=secno>7.10 </span><dfn>The <code title="">insertOrderedList</code> command</dfn></h3>
+<h3 id=the-insertorderedlist-command><span class=secno>7.11 </span><dfn>The <code title="">insertOrderedList</code> command</dfn></h3>
<p><a href=#action>Action</a>: <a href=#toggle-lists>Toggle lists</a> with <var title="">tag name</var>
"ol".
-<h3 id=the-insertparagraph-command><span class=secno>7.11 </span><dfn>The <code title="">insertParagraph</code> command</dfn></h3>
+<h3 id=the-insertparagraph-command><span class=secno>7.12 </span><dfn>The <code title="">insertParagraph</code> command</dfn></h3>
<!--
There are three major behaviors here. Firefox 5.0a2 behaves identically to
execCommand("formatBlock", false, "p"), which is not really useful. IE9
@@ -4523,13 +4641,37 @@
</ol>
-<h3 id=the-insertunorderedlist-command><span class=secno>7.12 </span><dfn>The <code title="">insertUnorderedList</code> command</dfn></h3>
+<h3 id=the-insertunorderedlist-command><span class=secno>7.13 </span><dfn>The <code title="">insertUnorderedList</code> command</dfn></h3>
<p><a href=#action>Action</a>: <a href=#toggle-lists>Toggle lists</a> with <var title="">tag name</var>
"ul".
-<h3 id=the-outdent-command><span class=secno>7.13 </span><dfn>The <code title="">outdent</code> command</dfn></h3>
+<h3 id=the-justifycenter-command><span class=secno>7.14 </span><dfn>The <code title="">justifyCenter</code> command</dfn></h3>
+
+<p><a href=#action>Action</a>: <a href=#justify-the-selection>Justify the selection</a> with
+<var title="">alignment</var> "center".
+
+
+<h3 id=the-justifyfull-command><span class=secno>7.15 </span><dfn>The <code title="">justifyFull</code> command</dfn></h3>
+
+<p><a href=#action>Action</a>: <a href=#justify-the-selection>Justify the selection</a> with
+<var title="">alignment</var> "justify".
+
+
+<h3 id=the-justifyleft-command><span class=secno>7.16 </span><dfn>The <code title="">justifyLeft</code> command</dfn></h3>
+
+<p><a href=#action>Action</a>: <a href=#justify-the-selection>Justify the selection</a> with
+<var title="">alignment</var> "left".
+
+
+<h3 id=the-justifyright-command><span class=secno>7.17 </span><dfn>The <code title="">justifyRight</code> command</dfn></h3>
+
+<p><a href=#action>Action</a>: <a href=#justify-the-selection>Justify the selection</a> with
+<var title="">alignment</var> "right".
+
+
+<h3 id=the-outdent-command><span class=secno>7.18 </span><dfn>The <code title="">outdent</code> command</dfn></h3>
<p><a href=#action>Action</a>:
--- a/implementation.js Thu Jun 02 12:43:16 2011 -0600
+++ b/implementation.js Thu Jun 02 14:34:46 2011 -0600
@@ -355,6 +355,47 @@
return nodeList;
}
+/**
+ * As above, but includes nodes with an ancestor that's already been returned.
+ */
+function collectAllContainedNodes(range, condition) {
+ if (typeof condition == "undefined") {
+ condition = function() { return true };
+ }
+ var node = range.startContainer;
+ if (node.hasChildNodes()
+ && range.startOffset < node.childNodes.length) {
+ // A child is contained
+ node = node.childNodes[range.startOffset];
+ } else if (range.startOffset == getNodeLength(node)) {
+ // No descendant can be contained
+ node = nextNodeDescendants(node);
+ } else {
+ // No children; this node at least can't be contained
+ node = nextNode(node);
+ }
+
+ var stop = range.endContainer;
+ if (stop.hasChildNodes()
+ && range.endOffset < stop.childNodes.length) {
+ // The node after the last contained node is a child
+ stop = stop.childNodes[range.endOffset];
+ } else {
+ // This node and/or some of its children might be contained
+ stop = nextNodeDescendants(node);
+ }
+
+ var nodeList = [];
+ while (isBefore(node, stop)) {
+ if (isContained(node, range)
+ && condition(node)) {
+ nodeList.push(node);
+ }
+ node = nextNode(node);
+ }
+ return nodeList;
+}
+
function parseSimpleColor(color) {
// This is stupid, but otherwise my automated tests will have places where
@@ -3451,6 +3492,22 @@
}
break;
+ case "justifycenter":
+ justifySelection("center");
+ break;
+
+ case "justifyfull":
+ justifySelection("justify");
+ break;
+
+ case "justifyleft":
+ justifySelection("left");
+ break;
+
+ case "justifyright":
+ justifySelection("right");
+ break;
+
case "outdent":
// "Let items be a list of all lis that are ancestor containers of the
// range's start and/or end node."
@@ -4303,6 +4360,141 @@
}
}
+function justifySelection(alignment) {
+ // "Block-extend the active range, and let new range be the result."
+ var newRange = blockExtendRange(globalRange);
+
+ // "Let element list be a list of all editable Elements contained in new
+ // range that either has an attribute in the HTML namespace whose local
+ // name is "align", or has a style attribute that sets "text-align", or is
+ // a center."
+ var elementList = collectAllContainedNodes(newRange, function(node) {
+ return node.nodeType == Node.ELEMENT_NODE
+ && isEditable(node)
+ // Ignoring namespaces here
+ && (
+ node.hasAttribute("align")
+ || node.style.textAlign != ""
+ || isHtmlElement(node, "center")
+ );
+ });
+
+ // "For each element in element list:"
+ for (var i = 0; i < elementList.length; i++) {
+ var element = elementList[i];
+
+ // "If element has an attribute in the HTML namespace whose local name
+ // is "align", remove that attribute."
+ element.removeAttribute("align");
+
+ // "Unset the CSS property "text-align" on element, if it's set by a
+ // style attribute."
+ element.style.textAlign = "";
+ if (element.getAttribute("style") == "") {
+ element.removeAttribute("style");
+ }
+
+ // "If element is a div or center with no attributes, remove it,
+ // preserving its descendants."
+ if (isHtmlElement(element, ["div", "center"])
+ && !element.attributes.length) {
+ removePreservingDescendants(element);
+ }
+
+ // "If element is a center with one or more attributes, set the tag
+ // name of element to "div"."
+ if (isHtmlElement(element, "center")
+ && element.attributes.length) {
+ setTagName(element, "div");
+ }
+ }
+
+ // "Block-extend the active range, and let new range be the result."
+ newRange = blockExtendRange(globalRange);
+
+ // "Let node list be a list of nodes, initially empty."
+ var nodeList = [];
+
+ // "For each node node contained in new range, append node to node list if
+ // the last member of node list (if any) is not an ancestor of node; node
+ // is editable; and either node is an Element and the CSS property
+ // "text-align" does not compute to alignment on it, or it is not an
+ // Element, but its parent is an Element, and the CSS property "text-align"
+ // does not compute to alignment on its parent."
+ nodeList = collectContainedNodes(newRange, function(node) {
+ if (!isEditable(node)) {
+ return false;
+ }
+ // Gecko and WebKit have lots of fun here confusing us with
+ // vendor-specific values, and in Gecko's case "start".
+ var element = node.nodeType == Node.ELEMENT_NODE
+ ? node
+ : node.parentNode;
+ if (!element || element.nodeType != Node.ELEMENT_NODE) {
+ return false;
+ }
+ var computedAlign = getComputedStyle(element).textAlign
+ .replace(/^-(moz|webkit)-/, "");
+ if (computedAlign == "auto" || computedAlign == "start") {
+ // Depends on directionality. Note: this is a serious hack.
+ do {
+ var dir = element.dir.toLowerCase();
+ element = element.parentNode;
+ } while (element && element.nodeType == Node.ELEMENT_NODE && dir != "ltr" && dir != "rtl");
+ if (dir == "rtl") {
+ computedAlign = "right";
+ } else {
+ computedAlign = "left";
+ }
+ }
+ return computedAlign != alignment;
+ });
+
+ // "While node list is not empty:"
+ while (nodeList.length) {
+ // "Let sublist be a list of nodes, initially empty."
+ var sublist = [];
+
+ // "Remove the first member of node list and append it to sublist."
+ sublist.push(nodeList.shift());
+
+ // "While node list is not empty, and the first member of node list is
+ // the nextSibling of the last member of sublist, remove the first
+ // member of node list and append it to sublist."
+ while (nodeList.length
+ && nodeList[0] == sublist[sublist.length - 1].nextSibling) {
+ sublist.push(nodeList.shift());
+ }
+
+ // "Wrap sublist. Sibling criteria match any div that has one or both
+ // of the following two attributes, and no other attributes:
+ //
+ // * "An align attribute whose value is an ASCII case-insensitive
+ // match for alignment.
+ // * "A style attribute which sets exactly one CSS property
+ // (including unrecognized or invalid attributes), which is
+ // "text-align", which is set to alignment.
+ //
+ // "New parent instructions are to call createElement("div") on the
+ // context object, then set its CSS property "text-align" to alignment,
+ // and return the result."
+ wrap(sublist,
+ function(node) {
+ return isHtmlElement(node, "div")
+ && div.attributes.every(function(attr) {
+ return (attr.name == "align" && attr.value.toLowerCase() == alignment)
+ || (attr.name == "style" && node.style.length == 1 && node.style.textAlign == alignment);
+ });
+ },
+ function() {
+ var newParent = document.createElement("div");
+ newParent.setAttribute("style", "text-align: " + alignment);
+ return newParent;
+ }
+ );
+ }
+}
+
// "A potential indentation element is either a blockquote, or a div that has a
// style attribute that sets "margin" or some subproperty of it."
function isPotentialIndentationElement(node) {
--- a/source.html Thu Jun 02 12:43:16 2011 -0600
+++ b/source.html Thu Jun 02 14:34:46 2011 -0600
@@ -1076,14 +1076,11 @@
There's code for these in WebKit, Source/WebCore/editing/EditorCommand.cpp,
but I didn't see them mentioned elsewhere. Some might be worth adding.
-Things I haven't looked at:
+Things I haven't looked at that multiple browsers implement:
* copy, cut, paste: Needs attention to security.
* delete, redo, undo: Needs review of the Google work on this; will probably be
quite complicated.
-* justifyCenter, justifyFull, justifyLeft, justifyRight: These look important
- and should be similar to work I've already done, so they're
- next on my list.
* selectAll, unselect: Should be easy, although they seem redundant to just
calling methods of the Selection.
-->
@@ -4080,6 +4077,124 @@
</ol>
+<h3>Justifying the selection</h3>
+<!--
+There are two basic ways it works: using the align attribute, and using CSS
+text-align. IE9 and Opera 11.11 use only the align attribute, Chrome 13 dev
+uses only text-align, and Firefox 5.0a2 varies based on styleWithCSS. The two
+ways produce entirely different results, which is a real problem, so I don't
+think Firefox's approach is tenable. text-align is more valid, and for typical
+contenteditable cases it works the same. But for cases where you have
+fixed-width blocks, like tables or just divs with a width set, it behaves
+differently, and in those cases the align attribute is more useful.
+-->
+
+<p>To <dfn>justify the selection</dfn> to a string <var>alignment</var> (either
+"center", "justify", "left", or "right"):
+
+<p class=XXX>text-align doesn't behave as expected if there are descendant
+blocks with non-100% width, like tables. The align attribute behaves a lot
+more nicely in such cases, but it's not valid. Not clear what to do. For now
+I've stuck with text-align, just because the cases where it misbehaves can't be
+created by any sequence of stock execCommand()s that I know of, but this needs
+more careful consideration. Gecko in CSS mode seems to special-case tables,
+adding auto margins to the table element to get it to align correctly.
+
+<p class=XXX>Need to do something along the lines of pushing down values here
+(although no browser does). In fact, it's very likely this can be rewritten in
+terms of the inline formatting command primitives, but it's not clear if it
+would be worth the added complexity.
+
+<ol>
+ <li><span>Block-extend</span> the <span>active range</span>, and let <var>new
+ range</var> be the result.
+
+ <li>Let <var>element list</var> be a list of all <span>editable</span>
+ [[element]]s [[contained]] in <var>new range</var> that either has an
+ attribute in the [[htmlnamespace]] whose [[attrlocalname]] is "align", or has
+ a [[style]] attribute that sets "text-align", or is a <code
+ data-anolis-spec=html>center</code>.
+ <!-- No browser actually removes center, but it makes sense to do so. -->
+
+ <li>For each <var>element</var> in <var>element list</var>:
+
+ <ol>
+ <li>If <var>element</var> has an attribute in the [[htmlnamespace]] whose
+ [[attrlocalname]] is "align", remove that attribute.
+
+ <li>Unset the CSS property "text-align" on <var>element</var>, if it's set
+ by a [[style]] attribute.
+
+ <li>If <var>element</var> is a [[div]] or <code
+ data-anolis-spec=html>center</code> with no attributes, remove it,
+ <span>preserving its descendants</span>.
+
+ <li>If <var>element</var> is a <code data-anolis-spec=html>center</code>
+ with one or more attributes, <span>set the tag name</span> of
+ <var>element</var> to "div".
+ </ol>
+
+ <li><span>Block-extend</span> the <span>active range</span>, and let <var>new
+ range</var> be the result.
+ <!-- This could theoretically be necessary, like if it converted "<div
+ align=right>foo</div>bar" to "foo<br>bar". Now we need to select "foo<br>",
+ nor just "foo". -->
+
+ <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>,
+ append <var>node</var> to <var>node list</var> if the last member of
+ <var>node list</var> (if any) is not an [[ancestor]] of <var>node</var>;
+ <var>node</var> is <span>editable</span>; and either <var>node</var> is an
+ [[element]] and the CSS property "text-align" does not compute to
+ <var>alignment</var> on it, or it is not an [[element]], but its [[parent]]
+ is an [[element]], and the CSS property "text-align" does not compute to
+ <var>alignment</var> on its [[parent]].
+ <!-- Of tested browsers, only Chrome 13 dev seems to not apply the alignment
+ to nodes that are already aligned. Even then, it does apply it if the
+ alignment is just inherited from the root. -->
+
+ <p class=XXX>What does this imply when text-align is "start" or "end"? As
+ with lots of CSS stuff in this spec, needs to be clarified.
+
+ <li>While <var>node list</var> is not empty:
+
+ <ol>
+ <li>Let <var>sublist</var> be a list of [[nodes]], initially empty.
+
+ <li>Remove the first member of <var>node list</var> and append it to
+ <var>sublist</var>.
+
+ <li>While <var>node list</var> is not empty, and the first member of
+ <var>node list</var> is the [[nextsibling]] of the last member of
+ <var>sublist</var>, remove the first member of <var>node list</var> and
+ append it to <var>sublist</var>.
+
+ <li><span>Wrap</span> <var>sublist</var>. <span>Sibling criteria</span>
+ match any [[div]] that has one or both of the following two attributes, and
+ no other attributes:
+
+ <ul>
+ <li>An <code data-anolis-spec=html title=attr-div-align>align</code>
+ attribute whose [[attrvalue]] is an <span data-anolis-spec=domcore>ASCII
+ case-insensitive</span> match for <var>alignment</var>.
+
+ <li>A [[style]] attribute which sets exactly one CSS property (including
+ unrecognized or invalid attributes), which is "text-align", which is set
+ to <var>alignment</var>.
+ </ul>
+
+ <span>New parent instructions</span> are to call [[createelement|"div"]] on
+ the [[contextobject]], then set its CSS property "text-align" to
+ <var>alignment</var>, and return the result.
+ <!-- As for inline formatting, I only ever create new elements, and don't
+ ever modify existing ones. This doesn't match how any browser behaves
+ in this case, but for inline formatting it matches everyone but Gecko's CSS
+ mode. -->
+ </ol>
+</ol>
+
+
<h3><dfn>The <code title>formatBlock</code> command</dfn></h3>
<!--
Tested browser versions: IE9, Firefox 4.0, Chrome 13 dev, Opera 11.10.
@@ -4564,6 +4679,30 @@
"ul".
+<h3><dfn>The <code title>justifyCenter</code> command</dfn></h3>
+
+<p><span>Action</span>: <span>Justify the selection</span> with
+<var>alignment</var> "center".
+
+
+<h3><dfn>The <code title>justifyFull</code> command</dfn></h3>
+
+<p><span>Action</span>: <span>Justify the selection</span> with
+<var>alignment</var> "justify".
+
+
+<h3><dfn>The <code title>justifyLeft</code> command</dfn></h3>
+
+<p><span>Action</span>: <span>Justify the selection</span> with
+<var>alignment</var> "left".
+
+
+<h3><dfn>The <code title>justifyRight</code> command</dfn></h3>
+
+<p><span>Action</span>: <span>Justify the selection</span> with
+<var>alignment</var> "right".
+
+
<h3><dfn>The <code title>outdent</code> command</dfn></h3>
<p><span>Action</span>: