--- a/editing.html Thu Jul 28 15:24:15 2011 -0600
+++ b/editing.html Fri Jul 29 14:43:56 2011 -0600
@@ -38,7 +38,7 @@
<body class=draft>
<div class=head id=head>
<h1>HTML Editing APIs</h1>
-<h2 class="no-num no-toc" id=work-in-progress-—-last-update-28-july-2011>Work in Progress — Last Update 28 July 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-—-last-update-29-july-2011>Work in Progress — Last Update 29 July 2011</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <<a href=mailto:ayg@aryeh.name>ayg@aryeh.name</a>>
@@ -239,9 +239,7 @@
<ul>
<li>Need to make CSS terminology more precise, about setting/unsetting CSS
properties. The intent is to modify the style attribute, CSSOM-style.
- Likewise, CSS value comparisons need to be done after serializing both
- values, so "bold" == "700" and "red" == "#f00" and so on. Suggestions
- appreciated on how I should spec this.
+ Suggestions appreciated on how I should spec this.
<li>I use <a href=http://dev.w3.org/csswg/cssom/#resolved-value>resolved value</a> instead of computed or used or anything like that, just
because that's what my test implementation uses (via getComputedStyle). This
@@ -1375,6 +1373,28 @@
<p class=note>Conceptually, a simple modifiable element is a modifiable element
which specifies a value for at most one command.
+<p>Two quantities are <dfn id=equivalent-values>equivalent values</dfn> for a <a href=#command>command</a>
+if either both are null, or both are strings and they're equal and the
+<a href=#command>command</a> does not define any <a href=#equivalent-values>equivalent values</a>, or
+both are strings and the <a href=#command>command</a> defines <a href=#equivalent-values>equivalent
+values</a> and they match the definition.
+
+<p>Two quantities are <dfn id=loosely-equivalent-values>loosely equivalent values</dfn> for a
+<a href=#command>command</a> if either they are <a href=#equivalent-values>equivalent values</a> for the
+<a href=#command>command</a>, or if the <a href=#command>command</a> is <a href=#the-fontsize-command>the <code title="">fontSize</code> command</a>; one of the quantities is one of
+"xx-small", "small", "medium", "large", "x-large", "xx-large", or "xxx-large";
+and the other quantity is the <a href=http://dev.w3.org/csswg/cssom/#resolved-value>resolved value</a> of "font-size" on a <code class=external data-anolis-spec=html title=font><a href=http://www.whatwg.org/html/#font>font</a></code> element
+whose <code class=external data-anolis-spec=html title=dom-font-size><a href=http://www.whatwg.org/html/#dom-font-size>size</a></code> attribute has the corresponding value set ("1" through "7"
+respectively).
+
+<p class=note>Loose equivalence needs to be used when comparing effective
+command values to other values, while regular equivalence is used in other
+cases. The effective command value for fontSize is converted to pixels, so
+comparing it to a specified value literally would produce false negatives. But
+a <em>specified</em> value in pixels is actually different from a
+<em>specified</em> value like "small" or "x-large", because there is no precise
+mapping from such keywords to pixels.
+
<p>If a <a href=#command>command</a> has <dfn id=inline-command-activated-values>inline command activated values</dfn>
defined but nothing else defines when it is <a href=#indeterminate>indeterminate</a>, it is
<a href=#indeterminate>indeterminate</a> if among <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> nodes
@@ -1617,13 +1637,15 @@
<var title="">candidate</var> has exactly one <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, and that <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> is also a
<a href=#modifiable-element>modifiable element</a>, and <var title="">candidate</var> is not a
<a href=#simple-modifiable-element>simple modifiable element</a> or <var title="">candidate</var>'s
- <a href=#specified-command-value>specified command value</a> for <var title="">command</var> is not <var title="">new
- value</var>, set <var title="">candidate</var> to its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>.
+ <a href=#specified-command-value>specified command value</a> for <var title="">command</var> is not <a href=#equivalent-values title="equivalent values">equivalent</a> to <var title="">new value</var>, set
+ <var title="">candidate</var> to its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>.
<li>If <var title="">candidate</var> is <var title="">node</var>, or is not a <a href=#simple-modifiable-element>simple
- modifiable element</a>, or its <a href=#specified-command-value>specified command value</a> and
- <a href=#effective-command-value>effective command value</a> for <var title="">command</var> are not both
- <var title="">new value</var>, abort these steps.
+ modifiable element</a>, or its <a href=#specified-command-value>specified command value</a> is not
+ <a href=#equivalent-values title="equivalent values">equivalent</a> to <var title="">new value</var>, or
+ its <a href=#effective-command-value>effective command value</a> is not <a href=#loosely-equivalent-values title="loosely
+ equivalent values">loosely equivalent</a> to <var title="">new value</var>, abort
+ these steps.
<li>While <var title="">candidate</var> has <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>children</a>, insert the first <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 <var title="">candidate</var> into <var title="">candidate</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> immediately
@@ -1710,10 +1732,10 @@
with <var title="">new value</var> null.
<li>Otherwise, if <var title="">ancestor</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 its
- <a href=#specified-command-value>specified command value</a> for <var title="">command</var> is different
- from <var title="">value</var>, or if <var title="">ancestor</var> 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> and
- <var title="">value</var> is not null, <a href=#force-the-value>force the value</a> of
- <var title="">command</var> to <var title="">value</var> on <var title="">node</var>.
+ <a href=#specified-command-value>specified command value</a> for <var title="">command</var> is not <a href=#equivalent-values title="equivalent values">equivalent</a> to <var title="">value</var>, or if
+ <var title="">ancestor</var> 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> and <var title="">value</var> is not null,
+ <a href=#force-the-value>force the value</a> of <var title="">command</var> to <var title="">value</var> on
+ <var title="">node</var>.
</ol>
</ol>
@@ -1839,7 +1861,8 @@
algorithm. <!-- E.g., a text node child of a document fragment. -->
<li>If the <a href=#effective-command-value>effective command value</a> of <var title="">command</var> is
- <var title="">new value</var> on <var title="">node</var>, abort this algorithm.
+ <a href=#loosely-equivalent-values title="loosely equivalent values">loosely equivalent</a> to <var title="">new value</var> on <var title="">node</var>, abort this
+ algorithm.
<li>Let <var title="">current ancestor</var> be <var title="">node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
@@ -1847,9 +1870,9 @@
<li>While <var title="">current ancestor</var> is an <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>
and the <a href=#effective-command-value>effective command value</a> of <var title="">command</var> is not
- <var title="">new value</var> on it, append <var title="">current ancestor</var> to
- <var title="">ancestor list</var>, then set <var title="">current ancestor</var> to its
- <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
+ <a href=#loosely-equivalent-values title="loosely equivalent values">loosely equivalent</a> to <var title="">new value</var> on it, append <var title="">current
+ ancestor</var> to <var title="">ancestor list</var>, then set <var title="">current
+ ancestor</var> to its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>.
<li>If <var title="">ancestor list</var> is empty, abort this algorithm.
@@ -1893,8 +1916,9 @@
we're styling something that includes the first or last child).
-->
<li>If the <a href=#effective-command-value>effective command value</a> of <var title="">command</var> is not
- <var title="">new value</var> on the <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 the last member of <var title="">ancestor
- list</var>, and <var title="">new value</var> is not null, abort this algorithm.
+ <a href=#loosely-equivalent-values title="loosely equivalent values">loosely equivalent</a> to <var title="">new value</var> on the <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 the last
+ member of <var title="">ancestor list</var>, and <var title="">new value</var> is not null,
+ abort this algorithm.
<li>While <var title="">ancestor list</var> is not empty:
@@ -1922,8 +1946,8 @@
<var title="">child</var>.
<li>If <var title="">child</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> whose <a href=#specified-command-value>specified command
- value</a> for <var title="">command</var> is neither null nor equal to
- <var title="">propagated value</var>, continue with the next <var title="">child</var>.
+ value</a> for <var title="">command</var> is neither null nor <a href=#equivalent-values title="equivalent values">equivalent</a> to <var title="">propagated
+ value</var>, continue with the next <var title="">child</var>.
<!--
TODO: This will be incorrect for relative font sizes. If the font size
on the parent was removed and the font size on the child is in ems or
@@ -1982,24 +2006,24 @@
<li><a href=#wrap>Wrap</a> the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting of <var title="">node</var>,
with <a href=#sibling-criteria>sibling criteria</a> matching a <a href=#simple-modifiable-element>simple modifiable
- element</a> whose <a href=#specified-command-value>specified command value</a> and
- <a href=#effective-command-value>effective command value</a> for <var title="">command</var> are both
- <var title="">new value</var>, and with <a href=#new-parent-instructions>new parent instructions</a>
- returning null.
+ element</a> whose <a href=#specified-command-value>specified command value</a> is <a href=#equivalent-values title="equivalent values">equivalent</a>
+ to <var title="">new value</var> and whose <a href=#effective-command-value>effective command value</a> is
+ <a href=#loosely-equivalent-values title="loosely equivalent values">loosely equivalent</a> to <var title="">new value</var>, and with <a href=#new-parent-instructions>new parent
+ instructions</a> returning null.
<!-- The new parent instructions are too complicated to reasonably feed
into the wrap algorithm. -->
</ol>
<li>If the <a href=#effective-command-value>effective command value</a> of <var title="">command</var> is
- <var title="">new value</var> on <var title="">node</var>, abort this algorithm.
+ <a href=#loosely-equivalent-values title="loosely equivalent values">loosely equivalent</a> to <var title="">new value</var> on <var title="">node</var>, abort this
+ algorithm.
<li>If <var title="">node</var> is not an <a href=#allowed-child>allowed child</a> of "span":
<ol>
<li>Let <var title="">children</var> be all <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>children</a> of <var title="">node</var>,
omitting any that are <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 whose <a href=#specified-command-value>specified command
- value</a> for <var title="">command</var> is neither null nor equal to <var title="">new
- value</var>.
+ value</a> for <var title="">command</var> is neither null nor <a href=#equivalent-values title="equivalent values">equivalent</a> to <var title="">new value</var>.
<li><a href=#force-the-value>Force the value</a> of 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> in <var title="">children</var>,
with <var title="">command</var> and <var title="">new value</var> as in this invocation of
@@ -2014,7 +2038,8 @@
</ol>
<li>If the <a href=#effective-command-value>effective command value</a> of <var title="">command</var> is
- <var title="">new value</var> on <var title="">node</var>, abort this algorithm.
+ <a href=#loosely-equivalent-values title="loosely equivalent values">loosely equivalent</a> to <var title="">new value</var> on <var title="">node</var>, abort this
+ algorithm.
<li>Let <var title="">new parent</var> be null.
@@ -2145,10 +2170,13 @@
-->
<li>If the <a href=#effective-command-value>effective command value</a> of <var title="">command</var> for
- <var title="">new parent</var> is not <var title="">new value</var>, and the <a href=#relevant-css-property>relevant CSS
- property</a> for <var title="">command</var> is not null, set that CSS property of
- <var title="">new parent</var> to <var title="">new value</var> (if the new value would be
- valid).
+ <var title="">new parent</var> is not <a href=#loosely-equivalent-values title="loosely equivalent values">loosely equivalent</a> to <var title="">new value</var>,
+ and the <a href=#relevant-css-property>relevant CSS property</a> for <var title="">command</var> is not
+ null, set that CSS property of <var title="">new parent</var> to <var title="">new value</var>
+ (if the new value would be valid).
+
+ <p class=XXX>Need to be explicit. I think "if the new value would be valid"
+ means "if the new value isn't xxx-large for font-size", need to double-check.
<li>If <var title="">command</var> is "strikethrough", and <var title="">new value</var> is
"line-through", and the <a href=#effective-command-value>effective command value</a> of
@@ -2164,8 +2192,8 @@
<a href=#preserving-ranges>preserving ranges</a>.
<li>If <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 <a href=#effective-command-value>effective command
- value</a> of <var title="">command</var> for <var title="">node</var> is not <var title="">new
- value</var>:
+ value</a> of <var title="">command</var> for <var title="">node</var> is not
+ <a href=#loosely-equivalent-values title="loosely equivalent values">loosely equivalent</a> to <var title="">new value</var>:
<ol>
<li>Insert <var title="">node</var> into the <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 <var title="">new parent</var>
@@ -2175,8 +2203,7 @@
<li>Let <var title="">children</var> be all <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>children</a> of <var title="">node</var>,
omitting any that are <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 whose <a href=#specified-command-value>specified command
- value</a> for <var title="">command</var> is neither null nor equal to <var title="">new
- value</var>.
+ value</a> for <var title="">command</var> is neither null nor <a href=#equivalent-values title="equivalent values">equivalent</a> to <var title="">new value</var>.
<li><a href=#force-the-value>Force the value</a> of 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> in <var title="">children</var>,
with <var title="">command</var> and <var title="">new value</var> as in this invocation of
@@ -2280,10 +2307,6 @@
<li>If <var title="">new value</var> is null, unset the <a href=#value-override>value override</a>
(if any).
- <li>Otherwise, if <var title="">command</var> is "fontSize", set the <a href=#value-override>value
- override</a> to the <a href=#legacy-font-size-for>legacy font size for</a> the result of
- converting <var title="">new value</var> to pixels.
-
<li>Otherwise, if <var title="">command</var> has a <a href=#value>value</a> specified,
set the <a href=#value-override>value override</a> to <var title="">new value</var>.
@@ -2419,6 +2442,10 @@
<p><a href=#relevant-css-property>Relevant CSS property</a>: "background-color"
+<p><a href=#equivalent-values>Equivalent values</a>: Either both strings are valid CSS colors and
+have the same red, green, blue, and alpha components, or neither string is a
+valid CSS color.
+
<h3 id=the-bold-command><span class=secno>7.8 </span><dfn>The <code title="">bold</code> command</dfn></h3>
@@ -2453,6 +2480,9 @@
<p><a href=#relevant-css-property>Relevant CSS property</a>: "font-weight"
+<p><a href=#equivalent-values>Equivalent values</a>: Either the two strings are equal, or one is
+"bold" and the other is "700", or one is "normal" and the other is "400".
+
<h3 id=the-createlink-command><span class=secno>7.9 </span><dfn>The <code title="">createLink</code> command</dfn></h3>
@@ -2830,6 +2860,10 @@
<p><a href=#relevant-css-property>Relevant CSS property</a>: "color"
+<p><a href=#equivalent-values>Equivalent values</a>: Either both strings are valid CSS colors and
+have the same red, green, blue, and alpha components, or neither string is a
+valid CSS color.
+
<h3 id=the-hilitecolor-command><span class=secno>7.13 </span><dfn>The <code title="">hiliteColor</code> command</dfn></h3>
@@ -2873,6 +2907,10 @@
<p><a href=#relevant-css-property>Relevant CSS property</a>: "background-color"
+<p><a href=#equivalent-values>Equivalent values</a>: Either both strings are valid CSS colors and
+have the same red, green, blue, and alpha components, or neither string is a
+valid CSS color.
+
<h3 id=the-italic-command><span class=secno>7.14 </span><dfn>The <code title="">italic</code> command</dfn></h3>
@@ -3640,9 +3678,13 @@
the contents".
-->
- <li>For each <var title="">command</var> in the list "fontName", "fontSize",
- "foreColor", "hiliteColor", in order: add (<var title="">command</var>,
- <var title="">command</var>'s <a href=#value>value</a>) to <var title="">overrides</var>.
+ <li>For each <var title="">command</var> in the list "fontName", "foreColor",
+ "hiliteColor", in order: add (<var title="">command</var>, <var title="">command</var>'s
+ <a href=#value>value</a>) to <var title="">overrides</var>.
+
+ <!-- Special case for fontSize, because its values are weird. -->
+ <li>Add ("fontSize", <var title="">node</var>'s <a href=#effective-command-value>effective command value</a>
+ for "fontSize") to <var title="">overrides</var>.
<li>Return <var title="">overrides</var>.
</ol>
@@ -3652,18 +3694,30 @@
<a href=#record-current-states-and-values>record current states and values</a> algorithm:
<ol>
- <li>If there is some <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node <a href=#effectively-contained>effectively
- contained</a> in the <a href=#active-range>active range</a>, then for each
- (<var title="">command</var>, <var title="">override</var>) pair in <var title="">overrides</var>, in
- order:
+ <li>Let <var title="">node</var> be the first <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node
+ <a href=#effectively-contained>effectively contained</a> in the <a href=#active-range>active range</a>, or null
+ if there is none.
+
+ <li>If <var title="">node</var> is not null, then for each (<var title="">command</var>,
+ <var title="">override</var>) pair in <var title="">overrides</var>, in order:
<ol>
<li>If <var title="">override</var> is a boolean, and <code title=queryCommandState()><a href=#querycommandstate()>queryCommandState(<var title="">command</var>)</a></code>
returns something different from <var title="">override</var>, call <code title=execCommand()><a href=#execcommand()>execCommand(<var title="">command</var>)</a></code>.
- <li>If <var title="">override</var> is a string, and <code title=queryCommandValue()><a href=#querycommandvalue()>queryCommandValue(<var title="">command</var>)</a></code>
- returns something different from <var title="">override</var>, call <code title=execCommand()><a href=#execcommand()>execCommand(<var title="">command</var>, false,
+ <li>If <var title="">override</var> is a string, and <var title="">command</var> is not
+ "fontSize", and <code title=queryCommandValue()><a href=#querycommandvalue()>queryCommandValue(<var title="">command</var>)</a></code>
+ returns something not <a href=#equivalent-values title="equivalent values">equivalent</a> to
+ <var title="">override</var>, call <code title=execCommand()><a href=#execcommand()>execCommand(<var title="">command</var>, false,
<var title="">override</var>)</a></code>.
+
+ <li>If <var title="">override</var> is a string; and <var title="">command</var> is
+ "fontSize"; and either there is a <a href=#value-override>value override</a> for
+ "fontSize" that is not equal to <var title="">override</var>, or there is no
+ <a href=#value-override>value override</a> for "fontSize" and <var title="">node</var>'s
+ <a href=#effective-command-value>effective command value</a> for "fontSize" is not
+ <a href=#loosely-equivalent-values title="loosely equivalent values">loosely equivalent</a> to <var title="">override</var>: call
+ <code title=execCommand()><a href=#execcommand()>execCommand("fontSize", false, <var title="">override</var>)</a></code>.
</ol>
<li>Otherwise, for each (<var title="">command</var>, <var title="">override</var>) pair in
--- a/implementation.js Thu Jul 28 15:24:15 2011 -0600
+++ b/implementation.js Fri Jul 29 14:43:56 2011 -0600
@@ -129,86 +129,17 @@
}[cssVal];
}
-// This entire function is a massive hack to work around browser
-// incompatibility. It wouldn't work in real life, but it's good enough for a
-// test implementation. It's not clear how all this should actually be specced
-// in practice, since CSS defines no notion of equality, does it?
-function valuesEqual(command, val1, val2) {
- if (commands[command].relevantCssProperty === null
- || (command == "fontsize" && /^[1-7]$/.test(val1) && /^[1-7]$/.test(val2))) {
- return val1 === val2;
- }
-
- if (val1 === null || val2 === null) {
- return val1 === val2;
- }
-
- if (command == "subscript" || command == "superscript") {
- return val1 === val2;
- }
-
- if (command == "bold") {
- return val1 == val2
- || (val1.toLowerCase() == "bold" && val2 == "700")
- || (val2.toLowerCase() == "bold" && val1 == "700")
- || (val1.toLowerCase() == "normal" && val2 == "400")
- || (val2.toLowerCase() == "normal" && val1 == "400");
- }
-
- var property = commands[command].relevantCssProperty;
- var test1 = document.createElement("span");
- test1.style[property] = val1;
- var test2 = document.createElement("span");
- test2.style[property] = val2;
-
- // Computing style doesn't seem to always work if the elements aren't in
- // the body?
- document.body.appendChild(test1);
- document.body.appendChild(test2);
-
- // We can't test xxx-large with CSS. Also, some browsers (WebKit?) don't
- // actually make <span style="font-size: xx-small"> have the same size as
- // <font size="1">, and so on. So we have to test both . . .
- var test1b = null, test2b = null;
- if (command == "fontsize") {
- if (typeof cssSizeToLegacy(val1) != "undefined") {
- test1b = document.createElement("font");
- test1b.size = cssSizeToLegacy(val1);
- document.body.appendChild(test1b);
- }
- if (typeof cssSizeToLegacy(val2) != "undefined") {
- test2b = document.createElement("font");
- test2b.size = cssSizeToLegacy(val2);
- document.body.appendChild(test2b);
- }
- }
-
- var computed1b = test1b
- ? getComputedStyle(test1b)[property]
- : null;
- var computed2b = test2b
- ? getComputedStyle(test2b)[property]
- : null;
- var computed1 = command == "fontsize" && val1 == "xxx-large"
- ? computed1b
- : getComputedStyle(test1)[property];
- var computed2 = command == "fontsize" && val2 == "xxx-large"
- ? computed2b
- : getComputedStyle(test2)[property];
-
- document.body.removeChild(test1);
- document.body.removeChild(test2);
-
- if (test1b) {
- document.body.removeChild(test1b);
- }
- if (test2b) {
- document.body.removeChild(test2b);
- }
-
- return computed1 == computed2
- || computed1 === computed2b
- || computed1b === computed2;
+// Return the CSS size given a legacy size.
+function legacySizeToCss(legacyVal) {
+ return {
+ 1: "xx-small",
+ 2: "small",
+ 3: "medium",
+ 4: "large",
+ 5: "x-large",
+ 6: "xx-large",
+ 7: "xxx-large",
+ }[legacyVal];
}
// Opera 11 puts HTML elements in the null namespace, it seems.
@@ -462,12 +393,52 @@
return nodeList;
}
+// Returns either null, or something of the form rgb(x, y, z), or something of
+// the form rgb(x, y, z, w) with w != 0.
+function normalizeColor(color) {
+ if (color.toLowerCase() == "currentcolor") {
+ return null;
+ }
+
+ var outerSpan = document.createElement("span");
+ document.body.appendChild(outerSpan);
+ outerSpan.style.color = "black";
+
+ var innerSpan = document.createElement("span");
+ outerSpan.appendChild(innerSpan);
+ innerSpan.style.color = color;
+ color = getComputedStyle(innerSpan).color;
+
+ if (color == "rgb(0, 0, 0)") {
+ // Maybe it's really black, maybe it's invalid.
+ outerSpan.color = "white";
+ color = getComputedStyle(innerSpan).color;
+ if (color != "rgb(0, 0, 0)") {
+ return null;
+ }
+ }
+
+ document.body.removeChild(outerSpan);
+
+ // I rely on the fact that browsers generally provide consistent syntax for
+ // getComputedStyle(), although it's not standardized. There are only two
+ // exceptions I found:
+ if (/^rgba\([0-9]+, [0-9]+, [0-9]+, 1\)$/.test(color)) {
+ // IE10PP2 seems to do this sometimes.
+ return color.replace("rgba", "rgb").replace(", 1)", ")");
+ }
+ if (color == "transparent") {
+ // IE10PP2, Firefox 7.0a2, and Opera 11.50 all return "transparent" if
+ // the specified value is "transparent".
+ return "rgba(0, 0, 0, 0)";
+ }
+ return color;
+}
+
// Returns either null, or something of the form #xxxxxx, or the color itself
// if it's a valid keyword.
function parseSimpleColor(color) {
color = color.toLowerCase();
- // Yay for Gecko allowing you to select a column of a table without
- // selecting anything from other columns.
if (["aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral",
@@ -499,36 +470,7 @@
return color;
}
- var outerSpan = document.createElement("span");
- document.body.appendChild(outerSpan);
- outerSpan.style.color = "black";
-
- var innerSpan = document.createElement("span");
- outerSpan.appendChild(innerSpan);
- innerSpan.style.color = color;
- color = getComputedStyle(innerSpan).color;
-
- if (color == "rgb(0, 0, 0)") {
- // Maybe it's really black, maybe it's invalid.
- outerSpan.color = "white";
- color = getComputedStyle(innerSpan).color;
- if (color != "rgb(0, 0, 0)") {
- return null;
- }
- }
-
- document.body.removeChild(outerSpan);
-
- if (/^rgba\([0-9]+, [0-9]+, [0-9]+, 1\)$/.test(color)) {
- // IE10PP2 seems to do this sometimes.
- color = color.replace("rgba", "rgb").replace(", 1)", ")");
- }
- // I rely on the fact that browsers generally provide consistent syntax for
- // getComputedStyle(), although it's not standardized. In particular, they
- // seem to clamp the components to integers between 0 and 255, and use
- // consistent spacing, and always return rgb() syntax. (Firefox 7.0a2
- // sometimes returns "transparent", but we need to return null then
- // anyway.)
+ color = normalizeColor(color);
var matches = /^rgb\(([0-9]+), ([0-9]+), ([0-9]+)\)$/.exec(color);
if (matches) {
return "#"
@@ -1838,6 +1780,66 @@
return false;
}
+// "Two quantities are equivalent values for a command if either both are null,
+// or both are strings and they're equal and the command does not define any
+// equivalent values, or both are strings and the command defines equivalent
+// values and they match the definition."
+function areEquivalentValues(command, val1, val2) {
+ if (val1 === null && val2 === null) {
+ return true;
+ }
+
+ if (typeof val1 == "string"
+ && typeof val2 == "string"
+ && val1 == val2
+ && !("equivalentValues" in commands[command])) {
+ return true;
+ }
+
+ if (typeof val1 == "string"
+ && typeof val2 == "string"
+ && "equivalentValues" in commands[command]
+ && commands[command].equivalentValues(val1, val2)) {
+ return true;
+ }
+
+ return false;
+}
+
+// "Two quantities are loosely equivalent values for a command if either they
+// are equivalent values for the command, or if the command is the fontSize
+// command; one of the quantities is one of "xx-small", "small", "medium",
+// "large", "x-large", "xx-large", or "xxx-large"; and the other quantity is
+// the resolved value of "font-size" on a font element whose size attribute has
+// the corresponding value set ("1" through "7" respectively)."
+function areLooselyEquivalentValues(command, val1, val2) {
+ if (areEquivalentValues(command, val1, val2)) {
+ return true;
+ }
+
+ if (command != "fontsize"
+ || typeof val1 != "string"
+ || typeof val2 != "string") {
+ return false;
+ }
+
+ // Static variables in JavaScript?
+ var callee = areLooselyEquivalentValues;
+ if (callee.sizeMap === undefined) {
+ callee.sizeMap = {};
+ var font = document.createElement("font");
+ document.body.appendChild(font);
+ ["xx-small", "small", "medium", "large", "x-large", "xx-large",
+ "xxx-large"].forEach(function(keyword) {
+ font.size = cssSizeToLegacy(keyword);
+ callee.sizeMap[keyword] = getComputedStyle(font).fontSize;
+ });
+ document.body.removeChild(font);
+ }
+
+ return val1 === callee.sizeMap[val2]
+ || val2 === callee.sizeMap[val1];
+}
//@}
///// Assorted inline formatting command algorithms /////
@@ -2152,21 +2154,23 @@
// "While candidate is a modifiable element, and candidate has exactly one
// child, and that child is also a modifiable element, and candidate is not
// a simple modifiable element or candidate's specified command value for
- // command is not new value, set candidate to its child."
+ // command is not equivalent to new value, set candidate to its child."
while (isModifiableElement(candidate)
&& candidate.childNodes.length == 1
+ && isModifiableElement(candidate.firstChild)
&& (!isSimpleModifiableElement(candidate)
- || !valuesEqual(command, getSpecifiedCommandValue(candidate, command), newValue))) {
+ || !areEquivalentValues(command, getSpecifiedCommandValue(candidate, command), newValue))) {
candidate = candidate.firstChild;
}
// "If candidate is node, or is not a simple modifiable element, or its
- // specified command value and effective command value for command are not
- // both new value, abort these steps."
+ // specified command value is not equivalent to new value, or its effective
+ // command value is not loosely equivalent to new value, abort these
+ // steps."
if (candidate == node
|| !isSimpleModifiableElement(candidate)
- || !valuesEqual(command, getSpecifiedCommandValue(candidate, command), newValue)
- || !valuesEqual(command, getEffectiveCommandValue(candidate, command), newValue)) {
+ || !areEquivalentValues(command, getSpecifiedCommandValue(candidate, command), newValue)
+ || !areLooselyEquivalentValues(command, getEffectiveCommandValue(candidate, command), newValue)) {
return;
}
@@ -2256,12 +2260,12 @@
pushDownValues(node, command, null);
// "Otherwise, if ancestor is an Element and its specified command
- // value for command is different from value, or if ancestor is not an
- // Element and value is not null, force the value of command to value
- // on node."
+ // value for command is not equivalent to value, or if ancestor is not
+ // an Element and value is not null, force the value of command to
+ // value on node."
} else if ((ancestor
&& ancestor.nodeType == Node.ELEMENT_NODE
- && !valuesEqual(command, getSpecifiedCommandValue(ancestor, command), value))
+ && !areEquivalentValues(command, getSpecifiedCommandValue(ancestor, command), value))
|| ((!ancestor || ancestor.nodeType != Node.ELEMENT_NODE)
&& value !== null)) {
forceValue(node, command, value);
@@ -2391,9 +2395,9 @@
return;
}
- // "If the effective command value of command is new value on node, abort
- // this algorithm."
- if (valuesEqual(command, getEffectiveCommandValue(node, command), newValue)) {
+ // "If the effective command value of command is loosely equivalent to new
+ // value on node, abort this algorithm."
+ if (areLooselyEquivalentValues(command, getEffectiveCommandValue(node, command), newValue)) {
return;
}
@@ -2404,11 +2408,12 @@
var ancestorList = [];
// "While current ancestor is an editable Element and the effective command
- // value of command is not new value on it, append current ancestor to
- // ancestor list, then set current ancestor to its parent."
+ // value of command is not loosely equivalent to new value on it, append
+ // current ancestor to ancestor list, then set current ancestor to its
+ // parent."
while (isEditable(currentAncestor)
&& currentAncestor.nodeType == Node.ELEMENT_NODE
- && !valuesEqual(command, getEffectiveCommandValue(currentAncestor, command), newValue)) {
+ && !areLooselyEquivalentValues(command, getEffectiveCommandValue(currentAncestor, command), newValue)) {
ancestorList.push(currentAncestor);
currentAncestor = currentAncestor.parentNode;
}
@@ -2428,11 +2433,11 @@
return;
}
- // "If the effective command value of command is not new value on the
- // parent of the last member of ancestor list, and new value is not null,
- // abort this algorithm."
+ // "If the effective command value for the parent of the last member of
+ // ancestor list is not loosely equivalent to new value, and new value is
+ // not null, abort this algorithm."
if (newValue !== null
- && !valuesEqual(command, getEffectiveCommandValue(ancestorList[ancestorList.length - 1].parentNode, command), newValue)) {
+ && !areLooselyEquivalentValues(command, getEffectiveCommandValue(ancestorList[ancestorList.length - 1].parentNode, command), newValue)) {
return;
}
@@ -2467,11 +2472,11 @@
}
// "If child is an Element whose specified command value for
- // command is neither null nor equal to propagated value, continue
- // with the next child."
+ // command is neither null nor equivalent to propagated value,
+ // continue with the next child."
if (child.nodeType == Node.ELEMENT_NODE
&& getSpecifiedCommandValue(child, command) !== null
- && !valuesEqual(command, propagatedValue, getSpecifiedCommandValue(child, command))) {
+ && !areEquivalentValues(command, propagatedValue, getSpecifiedCommandValue(child, command))) {
continue;
}
@@ -2514,21 +2519,22 @@
// "Wrap the one-node list consisting of node, with sibling criteria
// matching a simple modifiable element whose specified command value
- // and effective command value for command are both new value, and with
- // new parent instructions returning null."
+ // is equivalent to new value and whose effective command value is
+ // loosely equivalent to new value, and with new parent instructions
+ // returning null."
wrap([node],
function(node) {
return isSimpleModifiableElement(node)
- && valuesEqual(command, getSpecifiedCommandValue(node, command), newValue)
- && valuesEqual(command, getEffectiveCommandValue(node, command), newValue);
+ && areEquivalentValues(command, getSpecifiedCommandValue(node, command), newValue)
+ && areLooselyEquivalentValues(command, getEffectiveCommandValue(node, command), newValue);
},
function() { return null }
);
}
- // "If the effective command value of command is new value on node, abort
- // this algorithm."
- if (valuesEqual(command, getEffectiveCommandValue(node, command), newValue)) {
+ // "If the effective command value of command is loosely equivalent to new
+ // value on node, abort this algorithm."
+ if (areLooselyEquivalentValues(command, getEffectiveCommandValue(node, command), newValue)) {
return;
}
@@ -2536,14 +2542,14 @@
if (!isAllowedChild(node, "span")) {
// "Let children be all children of node, omitting any that are
// Elements whose specified command value for command is neither null
- // nor equal to new value."
+ // nor equivalent to new value."
var children = [];
for (var i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].nodeType == Node.ELEMENT_NODE) {
var specifiedValue = getSpecifiedCommandValue(node.childNodes[i], command);
if (specifiedValue !== null
- && !valuesEqual(command, newValue, specifiedValue)) {
+ && !areEquivalentValues(command, newValue, specifiedValue)) {
continue;
}
}
@@ -2560,9 +2566,9 @@
return;
}
- // "If the effective command value of command is new value on node, abort
- // this algorithm."
- if (valuesEqual(command, getEffectiveCommandValue(node, command), newValue)) {
+ // "If the effective command value of command is loosely equivalent to new
+ // value on node, abort this algorithm."
+ if (areLooselyEquivalentValues(command, getEffectiveCommandValue(node, command), newValue)) {
return;
}
@@ -2658,15 +2664,7 @@
&& ["xx-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large"].indexOf(newValue) != -1
&& (!cssStylingFlag || newValue == "xxx-large")) {
newParent = node.ownerDocument.createElement("font");
- newParent.size = {
- "xx-small": 1,
- "small": 2,
- "medium": 3,
- "large": 4,
- "x-large": 5,
- "xx-large": 6,
- "xxx-large": 7
- }[newValue];
+ newParent.size = cssSizeToLegacy(newValue);
}
// "If command is "subscript" or "superscript" and new value is "sub", let
@@ -2694,13 +2692,13 @@
// "Insert new parent in node's parent before node."
node.parentNode.insertBefore(newParent, node);
- // "If the effective command value of command for new parent is not new
- // value, and the relevant CSS property for command is not null, set that
- // CSS property of new parent to new value (if the new value would be
- // valid)."
+ // "If the effective command value of command for new parent is not loosely
+ // equivalent to new value, and the relevant CSS property for command is
+ // not null, set that CSS property of new parent to new value (if the new
+ // value would be valid)."
var property = commands[command].relevantCssProperty;
if (property !== null
- && !valuesEqual(command, getEffectiveCommandValue(newParent, command), newValue)) {
+ && !areLooselyEquivalentValues(command, getEffectiveCommandValue(newParent, command), newValue)) {
newParent.style[property] = newValue;
}
@@ -2728,9 +2726,9 @@
movePreservingRanges(node, newParent, newParent.childNodes.length);
// "If node is an Element and the effective command value of command for
- // node is not new value:"
+ // node is not loosely equivalent to new value:"
if (node.nodeType == Node.ELEMENT_NODE
- && !valuesEqual(command, getEffectiveCommandValue(node, command), newValue)) {
+ && !areEquivalentValues(command, getEffectiveCommandValue(node, command), newValue)) {
// "Insert node into the parent of new parent before new parent,
// preserving ranges."
movePreservingRanges(node, newParent.parentNode, getNodeIndex(newParent));
@@ -2740,14 +2738,14 @@
// "Let children be all children of node, omitting any that are
// Elements whose specified command value for command is neither null
- // nor equal to new value."
+ // nor equivalent to new value."
var children = [];
for (var i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].nodeType == Node.ELEMENT_NODE) {
var specifiedValue = getSpecifiedCommandValue(node.childNodes[i], command);
if (specifiedValue !== null
- && !valuesEqual(command, newValue, specifiedValue)) {
+ && !areEquivalentValues(command, newValue, specifiedValue)) {
continue;
}
}
@@ -2796,19 +2794,6 @@
if (newValue === null) {
unsetValueOverride(command);
- // "Otherwise, if command is "fontSize", set the value override to the
- // legacy font size for the result of converting new value to pixels."
- } else if (command == "fontsize") {
- var font = document.createElement("font");
- document.body.appendChild(font);
- if (newValue == "xxx-large") {
- font.size = 7;
- } else {
- font.style.fontSize = newValue;
- }
- setValueOverride(command, getLegacyFontSize(parseInt(getComputedStyle(font).fontSize)));
- document.body.removeChild(font);
-
// "Otherwise, if command has a value specified, set the value override
// to new value."
} else if ("value" in commands[command]) {
@@ -2908,7 +2893,13 @@
// "Set the selection's value to value."
setSelectionValue("backcolor", value);
- }, standardInlineValueCommand: true, relevantCssProperty: "backgroundColor"
+ }, standardInlineValueCommand: true, relevantCssProperty: "backgroundColor",
+ equivalentValues: function(val1, val2) {
+ // "Either both strings are valid CSS colors and have the same red,
+ // green, blue, and alpha components, or neither string is a valid CSS
+ // color."
+ return normalizeColor(val1) === normalizeColor(val2);
+ },
};
//@}
@@ -2924,7 +2915,16 @@
setSelectionValue("bold", "bold");
}
}, inlineCommandActivatedValues: ["bold", "600", "700", "800", "900"],
- relevantCssProperty: "fontWeight"
+ relevantCssProperty: "fontWeight",
+ equivalentValues: function(val1, val2) {
+ // "Either the two strings are equal, or one is "bold" and the other is
+ // "700", or one is "normal" and the other is "400"."
+ return val1 == val2
+ || (val1 == "bold" && val2 == "700")
+ || (val1 == "700" && val2 == "bold")
+ || (val1 == "normal" && val2 == "400")
+ || (val1 == "400" && val2 == "normal");
+ },
};
//@}
@@ -3156,7 +3156,13 @@
// "Set the selection's value to value."
setSelectionValue("forecolor", value);
- }, standardInlineValueCommand: true, relevantCssProperty: "color"
+ }, standardInlineValueCommand: true, relevantCssProperty: "color",
+ equivalentValues: function(val1, val2) {
+ // "Either both strings are valid CSS colors and have the same red,
+ // green, blue, and alpha components, or neither string is a valid CSS
+ // color."
+ return normalizeColor(val1) === normalizeColor(val2);
+ },
};
//@}
@@ -3195,7 +3201,13 @@
}).filter(function(value, i, arr) {
return arr.slice(0, i).indexOf(value) == -1;
}).length >= 2;
- }, standardInlineValueCommand: true, relevantCssProperty: "backgroundColor"
+ }, standardInlineValueCommand: true, relevantCssProperty: "backgroundColor",
+ equivalentValues: function(val1, val2) {
+ // "Either both strings are valid CSS colors and have the same red,
+ // green, blue, and alpha components, or neither string is a valid CSS
+ // color."
+ return normalizeColor(val1) === normalizeColor(val2);
+ },
};
//@}
@@ -3993,10 +4005,10 @@
}
});
- // "For each command in the list "fontName", "fontSize", "foreColor",
- // "hiliteColor", in order: if there is a value override for command, add
- // (command, command's value override) to overrides."
- ["fontname", "fontsize", "forecolor", "hilitecolor"].forEach(function(command) {
+ // "For each command in the list "fontName", "foreColor", "hiliteColor", in
+ // order: if there is a value override for command, add (command, command's
+ // value override) to overrides."
+ ["fontname", "forecolor", "hilitecolor"].forEach(function(command) {
if (getValueOverride(command) !== undefined) {
overrides.push([command, getValueOverride(command)]);
}
@@ -4039,22 +4051,29 @@
}
});
- // "For each command in the list "fontName", "fontSize", "foreColor",
- // "hiliteColor", in order: add (command, command's value) to overrides."
+ // "For each command in the list "fontName", "foreColor", "hiliteColor", in
+ // order: add (command, command's value) to overrides."
["fontname", "fontsize", "forecolor", "hilitecolor"].forEach(function(command) {
overrides.push([command, commands[command].value()]);
});
+ // "Add ("fontSize", node's effective command value for "fontSize") to
+ // overrides."
+ overrides.push("fontsize", getEffectiveCommandValue(node, "fontsize"));
+
// "Return overrides."
return overrides;
}
function restoreStatesAndValues(overrides) {
- // "If there is some editable Text node effectively contained in the active
- // range, then for each (command, override) pair in overrides, in order:"
- if (getAllEffectivelyContainedNodes(getActiveRange()).some(function(node) {
- return isEditable(node) && node.nodeType == Node.TEXT_NODE
- })) {
+ // "Let node be the first editable Text node effectively contained in the
+ // active range, or null if there is none."
+ var node = getAllEffectivelyContainedNodes(getActiveRange())
+ .filter(function(node) { return isEditable(node) && node.nodeType == Node.TEXT_NODE })[0];
+
+ // "If node is not null, then for each (command, override) pair in
+ // overrides, in order:"
+ if (node) {
for (var i = 0; i < overrides.length; i++) {
var command = overrides[i][0];
var override = overrides[i][1];
@@ -4067,13 +4086,34 @@
myExecCommand(command);
}
- // "If override is a string, and queryCommandValue(command) returns
- // something different from override, call execCommand(command,
- // false, override)."
+ // "If override is a string, and command is not "fontSize", and
+ // queryCommandValue(command) returns something not equivalent to
+ // override, call execCommand(command, false, override)."
if (typeof override == "string"
- && !valuesEqual(command, myQueryCommandValue(command), override)) {
+ && command != "fontsize"
+ && !areEquivalentValues(command, myQueryCommandValue(command), override)) {
myExecCommand(command, false, override);
}
+
+ // "If override is a string; and command is "fontSize"; and either
+ // there is a value override for "fontSize" that is not equal to
+ // override, or there is no value override for "fontSize" and
+ // node's effective command value for "fontSize" is not loosely
+ // equivalent to override: call execCommand("fontSize", false,
+ // override)."
+ if (typeof override == "string"
+ && command == "fontsize"
+ && (
+ (
+ getValueOverride("fontsize") !== undefined
+ && getValueOverride("fontsize") !== override
+ ) || (
+ getValueOverride("fontsize") === undefined
+ && !areLooselyEquivalentValues(command, getEffectiveCommandValue(node, "fontsize"), override)
+ )
+ )) {
+ myExecCommand("fontsize", false, override);
+ }
}
// "Otherwise, for each (command, override) pair in overrides, in order:"
--- a/preprocess Thu Jul 28 15:24:15 2011 -0600
+++ b/preprocess Fri Jul 29 14:43:56 2011 -0600
@@ -44,6 +44,7 @@
'em': '<code data-anolis-spec=html title="the em element">em</code>',
'endnode': '<span data-anolis-spec=domrange title=concept-range-end>end</span> <span data-anolis-spec=domrange title=concept-boundary-point-node>node</span>',
'endoffset': '<span data-anolis-spec=domrange title=concept-range-end>end</span> <span data-anolis-spec=domrange title=concept-boundary-point-offset>offset</span>',
+ 'equivalent': '<span title="equivalent values">equivalent</span>',
'extractcontents': '<code data-anolis-spec=domrange title=dom-Range-extractContents>extractContents()</code>',
'firstchild': '<code data-anolis-spec=domcore title=dom-Node-firstChild>firstChild</code>',
'followingsibling': '<span data-anolis-spec=domcore title="concept-tree-following-sibling">following sibling</span>',
@@ -64,6 +65,7 @@
'length': '<span data-anolis-spec=domrange title=concept-node-length>length</span>',
'li': '<code data-anolis-spec=html title="the li element">li</code>',
'localname': '<span data-anolis-spec=domcore title=concept-element-local-name>local name</span>',
+ 'looselyequivalent': '<span title="loosely equivalent values">loosely equivalent</span>',
'namespace': '<span data-anolis-spec=domcore title=concept-element-namespace>namespace</span>',
'nextsibling': '<code data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code>',
'node': '<span data-anolis-spec=domcore title=concept-node>node</span>',
@@ -133,6 +135,7 @@
'appendchild': '<code data-anolis-spec=domcore title=dom-Node-appendChild>appendChild(\\1)</code>',
'createelement': '<code data-anolis-spec=domcore title=dom-Document-createElement>createElement(\\1)</code>',
'deletedata': '<code data-anolis-spec=domcore title=dom-CharacterData-deleteData>deleteData(\\1)</code>',
+ 'execcommand': '<code title=execCommand()>execCommand(\\1)</code>',
'extend': '<code data-anolis-spec=domrange title=dom-Selection-extend>extend(\\1)</code>',
'insertdata': '<code data-anolis-spec=domcore title=dom-CharacterData-insertData>insertData(\\1)</code>',
'insertnode': '<code data-anolis-spec=domrange title=dom-Range-insertNode>insertNode(\\1)</code>',
--- a/source.html Thu Jul 28 15:24:15 2011 -0600
+++ b/source.html Fri Jul 29 14:43:56 2011 -0600
@@ -165,9 +165,7 @@
<ul>
<li>Need to make CSS terminology more precise, about setting/unsetting CSS
properties. The intent is to modify the style attribute, CSSOM-style.
- Likewise, CSS value comparisons need to be done after serializing both
- values, so "bold" == "700" and "red" == "#f00" and so on. Suggestions
- appreciated on how I should spec this.
+ Suggestions appreciated on how I should spec this.
<li>I use [[resval]] instead of computed or used or anything like that, just
because that's what my test implementation uses (via getComputedStyle). This
@@ -1335,6 +1333,29 @@
<p class=note>Conceptually, a simple modifiable element is a modifiable element
which specifies a value for at most one command.
+<p>Two quantities are <dfn>equivalent values</dfn> for a <span>command</span>
+if either both are null, or both are strings and they're equal and the
+<span>command</span> does not define any <span>equivalent values</span>, or
+both are strings and the <span>command</span> defines <span>equivalent
+values</span> and they match the definition.
+
+<p>Two quantities are <dfn>loosely equivalent values</dfn> for a
+<span>command</span> if either they are <span>equivalent values</span> for the
+<span>command</span>, or if the <span>command</span> is <span>the <code
+title>fontSize</code> command</span>; one of the quantities is one of
+"xx-small", "small", "medium", "large", "x-large", "xx-large", or "xxx-large";
+and the other quantity is the [[resval]] of "font-size" on a [[font]] element
+whose [[fontsize]] attribute has the corresponding value set ("1" through "7"
+respectively).
+
+<p class=note>Loose equivalence needs to be used when comparing effective
+command values to other values, while regular equivalence is used in other
+cases. The effective command value for fontSize is converted to pixels, so
+comparing it to a specified value literally would produce false negatives. But
+a <em>specified</em> value in pixels is actually different from a
+<em>specified</em> value like "small" or "x-large", because there is no precise
+mapping from such keywords to pixels.
+
<p>If a <span>command</span> has <dfn>inline command activated values</dfn>
defined but nothing else defines when it is <span>indeterminate</span>, it is
<span>indeterminate</span> if among <span>editable</span> [[text]] nodes
@@ -1577,13 +1598,16 @@
<var>candidate</var> has exactly one [[child]], and that [[child]] is also a
<span>modifiable element</span>, and <var>candidate</var> is not a
<span>simple modifiable element</span> or <var>candidate</var>'s
- <span>specified command value</span> for <var>command</var> is not <var>new
- value</var>, set <var>candidate</var> to its [[child]].
+ <span>specified command value</span> for <var>command</var> is not <span
+ title="equivalent values">equivalent</span> to <var>new value</var>, set
+ <var>candidate</var> to its [[child]].
<li>If <var>candidate</var> is <var>node</var>, or is not a <span>simple
- modifiable element</span>, or its <span>specified command value</span> and
- <span>effective command value</span> for <var>command</var> are not both
- <var>new value</var>, abort these steps.
+ modifiable element</span>, or its <span>specified command value</span> is not
+ <span title="equivalent values">equivalent</span> to <var>new value</var>, or
+ its <span>effective command value</span> is not <span title="loosely
+ equivalent values">loosely equivalent</span> to <var>new value</var>, abort
+ these steps.
<li>While <var>candidate</var> has [[children]], insert the first [[child]]
of <var>candidate</var> into <var>candidate</var>'s [[parent]] immediately
@@ -1670,10 +1694,11 @@
with <var>new value</var> null.
<li>Otherwise, if <var>ancestor</var> is an [[element]] and its
- <span>specified command value</span> for <var>command</var> is different
- from <var>value</var>, or if <var>ancestor</var> is not an [[element]] and
- <var>value</var> is not null, <span>force the value</span> of
- <var>command</var> to <var>value</var> on <var>node</var>.
+ <span>specified command value</span> for <var>command</var> is not <span
+ title="equivalent values">equivalent</span> to <var>value</var>, or if
+ <var>ancestor</var> is not an [[element]] and <var>value</var> is not null,
+ <span>force the value</span> of <var>command</var> to <var>value</var> on
+ <var>node</var>.
</ol>
</ol>
@@ -1799,7 +1824,8 @@
algorithm. <!-- E.g., a text node child of a document fragment. -->
<li>If the <span>effective command value</span> of <var>command</var> is
- <var>new value</var> on <var>node</var>, abort this algorithm.
+ [[looselyequivalent]] to <var>new value</var> on <var>node</var>, abort this
+ algorithm.
<li>Let <var>current ancestor</var> be <var>node</var>'s [[parent]].
@@ -1807,9 +1833,9 @@
<li>While <var>current ancestor</var> is an <span>editable</span> [[element]]
and the <span>effective command value</span> of <var>command</var> is not
- <var>new value</var> on it, append <var>current ancestor</var> to
- <var>ancestor list</var>, then set <var>current ancestor</var> to its
- [[parent]].
+ [[looselyequivalent]] to <var>new value</var> on it, append <var>current
+ ancestor</var> to <var>ancestor list</var>, then set <var>current
+ ancestor</var> to its [[parent]].
<li>If <var>ancestor list</var> is empty, abort this algorithm.
@@ -1853,8 +1879,9 @@
we're styling something that includes the first or last child).
-->
<li>If the <span>effective command value</span> of <var>command</var> is not
- <var>new value</var> on the [[parent]] of the last member of <var>ancestor
- list</var>, and <var>new value</var> is not null, abort this algorithm.
+ [[looselyequivalent]] to <var>new value</var> on the [[parent]] of the last
+ member of <var>ancestor list</var>, and <var>new value</var> is not null,
+ abort this algorithm.
<li>While <var>ancestor list</var> is not empty:
@@ -1882,8 +1909,9 @@
<var>child</var>.
<li>If <var>child</var> is an [[element]] whose <span>specified command
- value</span> for <var>command</var> is neither null nor equal to
- <var>propagated value</var>, continue with the next <var>child</var>.
+ value</span> for <var>command</var> is neither null nor <span
+ title="equivalent values">equivalent</span> to <var>propagated
+ value</var>, continue with the next <var>child</var>.
<!--
TODO: This will be incorrect for relative font sizes. If the font size
on the parent was removed and the font size on the child is in ems or
@@ -1943,24 +1971,25 @@
<li><span>Wrap</span> the one-[[node]] list consisting of <var>node</var>,
with <span>sibling criteria</span> matching a <span>simple modifiable
- element</span> whose <span>specified command value</span> and
- <span>effective command value</span> for <var>command</var> are both
- <var>new value</var>, and with <span>new parent instructions</span>
- returning null.
+ element</span> whose <span>specified command value</span> is [[equivalent]]
+ to <var>new value</var> and whose <span>effective command value</span> is
+ [[looselyequivalent]] to <var>new value</var>, and with <span>new parent
+ instructions</span> returning null.
<!-- The new parent instructions are too complicated to reasonably feed
into the wrap algorithm. -->
</ol>
<li>If the <span>effective command value</span> of <var>command</var> is
- <var>new value</var> on <var>node</var>, abort this algorithm.
+ [[looselyequivalent]] to <var>new value</var> on <var>node</var>, abort this
+ algorithm.
<li>If <var>node</var> is not an <span>allowed child</span> of "span":
<ol>
<li>Let <var>children</var> be all [[children]] of <var>node</var>,
omitting any that are [[element]]s whose <span>specified command
- value</span> for <var>command</var> is neither null nor equal to <var>new
- value</var>.
+ value</span> for <var>command</var> is neither null nor <span
+ title="equivalent values">equivalent</span> to <var>new value</var>.
<li><span>Force the value</span> of each [[node]] in <var>children</var>,
with <var>command</var> and <var>new value</var> as in this invocation of
@@ -1975,7 +2004,8 @@
</ol>
<li>If the <span>effective command value</span> of <var>command</var> is
- <var>new value</var> on <var>node</var>, abort this algorithm.
+ [[looselyequivalent]] to <var>new value</var> on <var>node</var>, abort this
+ algorithm.
<li>Let <var>new parent</var> be null.
@@ -2124,10 +2154,13 @@
-->
<li>If the <span>effective command value</span> of <var>command</var> for
- <var>new parent</var> is not <var>new value</var>, and the <span>relevant CSS
- property</span> for <var>command</var> is not null, set that CSS property of
- <var>new parent</var> to <var>new value</var> (if the new value would be
- valid).
+ <var>new parent</var> is not [[looselyequivalent]] to <var>new value</var>,
+ and the <span>relevant CSS property</span> for <var>command</var> is not
+ null, set that CSS property of <var>new parent</var> to <var>new value</var>
+ (if the new value would be valid).
+
+ <p class=XXX>Need to be explicit. I think "if the new value would be valid"
+ means "if the new value isn't xxx-large for font-size", need to double-check.
<li>If <var>command</var> is "strikethrough", and <var>new value</var> is
"line-through", and the <span>effective command value</span> of
@@ -2143,8 +2176,8 @@
<span>preserving ranges</span>.
<li>If <var>node</var> is an [[element]] and the <span>effective command
- value</span> of <var>command</var> for <var>node</var> is not <var>new
- value</var>:
+ value</span> of <var>command</var> for <var>node</var> is not
+ [[looselyequivalent]] to <var>new value</var>:
<ol>
<li>Insert <var>node</var> into the [[parent]] of <var>new parent</var>
@@ -2154,8 +2187,8 @@
<li>Let <var>children</var> be all [[children]] of <var>node</var>,
omitting any that are [[element]]s whose <span>specified command
- value</span> for <var>command</var> is neither null nor equal to <var>new
- value</var>.
+ value</span> for <var>command</var> is neither null nor <span
+ title="equivalent values">equivalent</span> to <var>new value</var>.
<li><span>Force the value</span> of each [[node]] in <var>children</var>,
with <var>command</var> and <var>new value</var> as in this invocation of
@@ -2260,10 +2293,6 @@
<li>If <var>new value</var> is null, unset the <span>value override</span>
(if any).
- <li>Otherwise, if <var>command</var> is "fontSize", set the <span>value
- override</span> to the <span>legacy font size for</span> the result of
- converting <var>new value</var> to pixels.
-
<li>Otherwise, if <var>command</var> has a <span>value</span> specified,
set the <span>value override</span> to <var>new value</var>.
@@ -2399,6 +2428,10 @@
<p><span>Relevant CSS property</span>: "background-color"
+<p><span>Equivalent values</span>: Either both strings are valid CSS colors and
+have the same red, green, blue, and alpha components, or neither string is a
+valid CSS color.
+
<!-- @} -->
<h3><dfn>The <code title>bold</code> command</dfn></h3>
<!-- @{ -->
@@ -2434,6 +2467,9 @@
<p><span>Relevant CSS property</span>: "font-weight"
+<p><span>Equivalent values</span>: Either the two strings are equal, or one is
+"bold" and the other is "700", or one is "normal" and the other is "400".
+
<!-- @} -->
<h3><dfn>The <code title>createLink</code> command</dfn></h3>
<!-- @{ -->
@@ -2811,6 +2847,10 @@
<p><span>Relevant CSS property</span>: "color"
+<p><span>Equivalent values</span>: Either both strings are valid CSS colors and
+have the same red, green, blue, and alpha components, or neither string is a
+valid CSS color.
+
<!-- @} -->
<h3><dfn>The <code title>hiliteColor</code> command</dfn></h3>
<!-- @{ -->
@@ -2854,6 +2894,10 @@
<p><span>Relevant CSS property</span>: "background-color"
+<p><span>Equivalent values</span>: Either both strings are valid CSS colors and
+have the same red, green, blue, and alpha components, or neither string is a
+valid CSS color.
+
<!-- @} -->
<h3><dfn>The <code title>italic</code> command</dfn></h3>
<!-- @{ -->
@@ -3628,9 +3672,13 @@
the contents".
-->
- <li>For each <var>command</var> in the list "fontName", "fontSize",
- "foreColor", "hiliteColor", in order: add (<var>command</var>,
- <var>command</var>'s <span>value</span>) to <var>overrides</var>.
+ <li>For each <var>command</var> in the list "fontName", "foreColor",
+ "hiliteColor", in order: add (<var>command</var>, <var>command</var>'s
+ <span>value</span>) to <var>overrides</var>.
+
+ <!-- Special case for fontSize, because its values are weird. -->
+ <li>Add ("fontSize", <var>node</var>'s <span>effective command value</span>
+ for "fontSize") to <var>overrides</var>.
<li>Return <var>overrides</var>.
</ol>
@@ -3640,10 +3688,12 @@
<span>record current states and values</span> algorithm:
<ol>
- <li>If there is some <span>editable</span> [[text]] node <span>effectively
- contained</span> in the <span>active range</span>, then for each
- (<var>command</var>, <var>override</var>) pair in <var>overrides</var>, in
- order:
+ <li>Let <var>node</var> be the first <span>editable</span> [[text]] node
+ <span>effectively contained</span> in the <span>active range</span>, or null
+ if there is none.
+
+ <li>If <var>node</var> is not null, then for each (<var>command</var>,
+ <var>override</var>) pair in <var>overrides</var>, in order:
<ol>
<li>If <var>override</var> is a boolean, and <code
@@ -3651,11 +3701,21 @@
returns something different from <var>override</var>, call <code
title=execCommand()>execCommand(<var>command</var>)</code>.
- <li>If <var>override</var> is a string, and <code
+ <li>If <var>override</var> is a string, and <var>command</var> is not
+ "fontSize", and <code
title=queryCommandValue()>queryCommandValue(<var>command</var>)</code>
- returns something different from <var>override</var>, call <code
+ returns something not <span title="equivalent values">equivalent</span> to
+ <var>override</var>, call <code
title=execCommand()>execCommand(<var>command</var>, false,
<var>override</var>)</code>.
+
+ <li>If <var>override</var> is a string; and <var>command</var> is
+ "fontSize"; and either there is a <span>value override</span> for
+ "fontSize" that is not equal to <var>override</var>, or there is no
+ <span>value override</span> for "fontSize" and <var>node</var>'s
+ <span>effective command value</span> for "fontSize" is not
+ [[looselyequivalent]] to <var>override</var>: call
+ [[execcommand|"fontSize", false, <var>override</var>]].
</ol>
<li>Otherwise, for each (<var>command</var>, <var>override</var>) pair in
--- a/tests.js Thu Jul 28 15:24:15 2011 -0600
+++ b/tests.js Fri Jul 29 14:43:56 2011 -0600
@@ -446,6 +446,8 @@
// Styled stuff with collapsed selection
'<p style=color:blue>foo<p>[]bar',
'<p style=color:blue>foo<p style=color:brown>[]bar',
+ '<p style=color:blue>foo<p style=color:rgba(0,0,255,1)>[]bar',
+ '<p style=color:transparent>foo<p style=color:rgba(0,0,0,0)>[]bar',
'<p>foo<p style=color:brown>[]bar',
'<p><font color=blue>foo</font><p>[]bar',
'<p><font color=blue>foo</font><p><font color=brown>[]bar</font>',
@@ -3755,16 +3757,7 @@
value = "#" + value;
}
} else if (command == "fontsize") {
- value = normalizeFontSize(value);
- var font = document.createElement("font");
- document.body.appendChild(font);
- if (value == "xxx-large") {
- font.size = 7;
- } else {
- font.style.fontSize = value;
- }
- value = getLegacyFontSize(parseInt(getComputedStyle(font).fontSize));
- document.body.removeChild(font);
+ afterValue = legacySizeToCss(afterValue);
} else if (command == "formatblock") {
value = value.replace(/^<(.*)>$/, "$1").toLowerCase();
} else if (command == "unlink") {
@@ -3795,7 +3788,7 @@
// And in all other cases, the value afterwards has to be the one we
// set.
afterDiv.lastChild.className =
- valuesEqual(command, afterValue, value)
+ areEquivalentValues(command, afterValue, value)
? "good-result"
: "bad-result";
}