--- a/autoimplementation.html Wed Mar 23 11:59:33 2011 -0600
+++ b/autoimplementation.html Wed Mar 23 16:03:54 2011 -0600
@@ -39,6 +39,7 @@
<h1>bold</h1>
<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
+<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
<p><label>Enter new test here: <input></label>
<button onclick="addTest('bold', document.querySelector('#bold input').value)">Add test</button>
@@ -47,9 +48,10 @@
<div id=fontname>
<h1>fontname</h1>
-<p>Tests set the font-family to "serif".
+<p>Tests set the font-family to "sans-serif". Note that the body's font-family is "serif".
<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
+<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
<p><label>Enter new test here: <input></label>
<button onclick="addTest('bold', document.querySelector('#fontname input').value)">Add test</button>
@@ -61,6 +63,7 @@
<p>Tests set the color to "#FF0000".
<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
+<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
<p><label>Enter new test here: <input></label>
<button onclick="addTest('forecolor', document.querySelector('#forecolor input').value)">Add test</button>
@@ -81,6 +84,7 @@
<h1>italic</h1>
<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
+<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
<p><label>Enter new test here: <input></label>
<button onclick="addTest('italic', document.querySelector('#italic input').value)">Add test</button>
@@ -90,6 +94,7 @@
<h1>underline</h1>
<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
+<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
<p><label>Enter new test here: <input></label>
<button onclick="addTest('underline', document.querySelector('#underline input').value)">Add test</button>
@@ -99,7 +104,7 @@
<script>
var values = {
bold: null,
- fontname: "serif",
+ fontname: "sans-serif",
forecolor: "#FF0000",
hilitecolor: "#FF8888",
italic: null,
@@ -112,17 +117,26 @@
'foo]bar[baz',
'{<p><p> <p>Foo</p>}',
'foo[bar<i>baz]qoz</i>quz',
+
'foo<span style="font-weight: bold">[bar]</span>baz',
'foo<b>[bar]</b>baz',
'foo<b>bar</b>[baz]',
'[foo]<b>bar</b>baz',
+ '<b>foo</b>[bar]<b>baz</b>',
'foo<strong>bar</strong>[baz]',
'[foo]<strong>bar</strong>baz',
+ '<strong>foo</strong>[bar]<strong>baz</strong>',
+ '<b>foo</b>[bar]<strong>baz</strong>',
+ '<strong>foo</strong>[bar]<b>baz</b>',
'foo[<b>bar</b>]baz',
'foo[<b>bar]</b>baz',
'foo<b>[bar</b>]baz',
- 'foo<span style="font-weight: normal"><b>{bar}</b></span>baz',
+
'foo{<b></b>}baz',
+ 'foo{<i></i>}baz',
+ 'foo{<b><i></i></b>}baz',
+ 'foo{<i><b></b></i>}baz',
+
'foo<strong>[bar]</strong>baz',
'foo[<strong>bar</strong>]baz',
'foo[<strong>bar]</strong>baz',
@@ -131,11 +145,15 @@
'foo[<span style="font-weight: bold">bar</span>]baz',
'foo[<span style="font-weight: bold">bar]</span>baz',
'foo<span style="font-weight: bold">[bar</span>]baz',
+
'<b>{<p>foo</p><p>bar</p>}<p>baz</p></b>',
'<b><p>foo[<i>bar</i>}</p><p>baz</p></b>',
+
'foo [bar <b>baz] qoz</b> quz sic',
'foo bar <b>baz [qoz</b> quz] sic',
+
'<b id=purple>bar [baz] qoz</b>',
+
'foo<span style="font-weight: 100">[bar]</span>baz',
'foo<span style="font-weight: 400">[bar]</span>baz',
'foo<span style="font-weight: 700">[bar]</span>baz',
@@ -158,6 +176,7 @@
'<span style="font-weight: 400">foo[barbaz</span>}',
'<span style="font-weight: 700">foo[barbaz</span>}',
'<span style="font-weight: 900">foo[barbaz</span>}',
+
'<h3>Foo[bar]baz</h3>',
'{<h3>Foobar]baz</h3>',
'<h3>Foo[barbaz</h3>}',
@@ -165,13 +184,19 @@
'{<h3>Foobarbaz]</h3>',
'<h3>[Foobarbaz</h3>}',
'{<h3>Foobarbaz</h3>}',
+
'<b>Foo<span style="font-weight: normal">bar<b>[baz]</b>quz</span>qoz</b>',
'<b>Foo<span style="font-weight: normal">[bar]</span>baz</b>',
+
'{<b>Foo</b> <b>bar</b>}',
'{<h3>Foo</h3><b>bar</b>}',
+
'<i><b>Foo</b></i>[bar]<i><b>baz</b></i>',
'<i><b>Foo</b></i>[bar]<b>baz</b>',
'<b>Foo</b>[bar]<i><b>baz</b></i>',
+ '<font color=red face=monospace><b>Foo</b></font>[bar]',
+
+ 'foo<span style="font-weight: normal"><b>{bar}</b></span>baz',
'[Foo<span class=notbold>bar</span>baz]',
],
fontname: [
@@ -214,8 +239,8 @@
'foo<samp>b[ar</samp>baz]',
'foo<tt>b[ar</tt>baz]',
- 'foo<span style="font-family: serif">[bar]</span>baz',
- 'foo<span style="font-family: serif">b[a]r</span>baz',
+ 'foo<span style="font-family: sans-serif">[bar]</span>baz',
+ 'foo<span style="font-family: sans-serif">b[a]r</span>baz',
'foo<span style="font-family: monospace">[bar]</span>baz',
'foo<span style="font-family: monospace">b[a]r</span>baz',
],
@@ -306,6 +331,10 @@
'foo<span style="text-decoration: underline">[bar]</span>baz',
'<u>foo[bar]baz</u>',
'<u>foo[b<span style="color:red">ar]ba</span>z</u>',
+ '<u>foo[b<span style="color:red" id=foo>ar]ba</span>z</u>',
+ '<u>foo[b<span style="font-size:3em">ar]ba</span>z</u>',
+ '<u>foo[b<i>ar]ba</i>z</u>',
+ '<p style="text-decoration: underline">foo[bar]baz</p>',
],
};
@@ -316,21 +345,33 @@
}
function addTest(command, test) {
- var tr = doSetup(command);
+ var doubleTesting = ["bold", "italic", "underline", "forecolor",
+ "fontname", "fontsize"].indexOf(command) != -1;
+
+ var tr = doSetup(command, 0);
doInputCell(tr, test);
- doSpecCell(tr, test, command);
- doBrowserCell(tr, test, command);
+ doSpecCell(tr, test, command, false);
+ doBrowserCell(tr, test, command, false);
doSameCell(tr);
+ if (doubleTesting) {
+ var tr = doSetup(command, 1);
+
+ doInputCell(tr, test);
+ doSpecCell(tr, test, command, true);
+ doBrowserCell(tr, test, command, true);
+ doSameCell(tr);
+ }
+
doTearDown(command);
}
-function doSetup(command) {
+function doSetup(command, idx) {
var div = document.getElementById(command);
div.contentEditable = "true";
div.spellcheck = false;
- var table = div.querySelector("table");
+ var table = div.querySelectorAll("table")[idx];
var tr = document.createElement("tr");
// Insert at the top, because Chrome debugger doesn't let you scroll down
@@ -352,7 +393,7 @@
tr.appendChild(inputCell);
}
-function doSpecCell(tr, test, command) {
+function doSpecCell(tr, test, command, styleWithCss) {
var value = values[command];
var specCell = document.createElement("td");
@@ -368,16 +409,32 @@
if (range.collapsed) {
range.setEnd(points[0], points[1]);
}
+ myExecCommand("styleWithCSS", false, styleWithCss);
myExecCommand(command, false, value, range);
specCell.lastChild.textContent = specCell.firstChild.innerHTML;
} catch (e) {
- specCell.textContent = "Exception: " + e;
+ specCell.lastChild.style.color = "red";
+ specCell.lastChild.style.fontWeight = "bold";
+ specCell.lastChild.textContent = "Note, exception: " + e;
+ }
+
+ var key = "execcommand-" + command
+ + "-" + Number(myQueryCommandState("styleWithCSS"))
+ + "-" + test;
+
+ var oldValue = localStorage[key];
+ localStorage[key] = specCell.lastChild.textContent;
+
+ if (oldValue !== null && oldValue !== undefined && oldValue != specCell.lastChild.textContent) {
+ specCell.appendChild(document.createElement("div"));
+ specCell.lastChild.style.color = "red";
+ specCell.lastChild.style.fontWeight = "bold";
+ specCell.lastChild.textContent = "Note, last run produced different markup: " + oldValue;
}
}
-function doBrowserCell(tr, test, command) {
+function doBrowserCell(tr, test, command, styleWithCss) {
var value = values[command];
- var styleWithCss = command != "bold" && command != "italic" && command != "underline";
var browserCell = document.createElement("td");
browserCell.innerHTML = "<div></div><div></div>";
@@ -387,10 +444,8 @@
var points = parseBrackets(browserCell);
setSelection(points[0], points[1], points[2], points[3]);
try {
- document.execCommand("styleWithCss", false, styleWithCss);
- } catch (e) {
- // IE, we don't care
- }
+ document.execCommand("styleWithCSS", false, styleWithCss);
+ } catch (e) {}
document.execCommand(command, false, value);
browserCell.lastChild.textContent = browserCell.firstChild.innerHTML;
} catch (e) {
@@ -401,9 +456,9 @@
function doSameCell(tr) {
var sameCell = document.createElement("td");
// Ad hoc normalization to avoid basically spurious mismatches
- var normalizedSpecCell = tr.childNodes[1].lastChild.textContent
+ var normalizedSpecCell = tr.childNodes[1].childNodes[1].textContent
.replace(/;? ?"/g, '"');
- var normalizedBrowserCell = tr.childNodes[2].lastChild.textContent
+ var normalizedBrowserCell = tr.childNodes[2].childNodes[1].textContent
.replace(/;? ?"/g, '"')
.replace(/<(\/?)strong/g, '<$1b')
.replace(/<(\/?)em/g, '<$1i')
--- a/editcommands.html Wed Mar 23 11:59:33 2011 -0600
+++ b/editcommands.html Wed Mar 23 16:03:54 2011 -0600
@@ -207,7 +207,9 @@
<li>Return the last <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> in <var title="">selection</var> whose <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>
is <var title="">start</var>.
- <!-- This is what Firefox seems to do, no reason to change it . . . -->
+
+ <p class=XXX>Double-check that this is what Firefox actually does. It seems
+ pretty baroque.
<p class=note>In user agents that support only one <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> per
<a href=http://html5.org/specs/dom-range.html#selection><code class=external data-anolis-spec=domrange>Selection</code></a>, the active range is simply the only one in the selection.
@@ -215,7 +217,16 @@
<p>An <dfn id=unwrappable-element>unwrappable element</dfn> is an <a href=#html-element>HTML element</a> which may
not be used where only <a class=external data-anolis-spec=html href=http://www.whatwg.org/html/#phrasing-content>phrasing content</a> is expected (not counting unknown or
-obsolete elements, which cannot be used at all).
+obsolete elements, which cannot be used at all); or any <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> whose
+display property computes to something other than "inline", "inline-block", or
+"inline-table".
+
+<p class=XXX>Currently when we hit an unwrappable element, we ignore it and
+style its children. Alternatively, if we would otherwise create a span with a
+style element on it, maybe we could put the style element directly on the
+unwrappable element. This would produce shorter markup in many cases, but
+would also cause problems for things like background-color that do something
+different on block elements.
<p>The <dfn id=effective-style>effective style</dfn> of a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> <var title="">node</var> for a given
<var title="">property</var> is returned by the following algorithm, which will return
@@ -290,6 +301,19 @@
<li>Return null.
</ol>
+<p>A <dfn id=styling-element>styling element</dfn> is a <a href=http://www.whatwg.org/html/#the-b-element><code class=external data-anolis-spec=html title="the b element">b</code></a>, <a href=http://www.whatwg.org/html/#the-em-element><code class=external data-anolis-spec=html title="the em element">em</code></a>, <a href=http://www.whatwg.org/html/#the-i-element><code class=external data-anolis-spec=html title="the i element">i</code></a>, <a href=http://www.whatwg.org/html/#the-span-element><code class=external data-anolis-spec=html title="the span element">span</code></a>,
+<a href=http://www.whatwg.org/html/#the-strong-element><code class=external data-anolis-spec=html title="the strong element">strong</code></a>, or <a href=http://www.whatwg.org/html/#the-u-element><code class=external data-anolis-spec=html title="the u element">u</code></a> element with no attributes except possibly <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>, or
+a <a href=http://www.whatwg.org/html/#font><code class=external data-anolis-spec=html title=font>font</code></a> element with no attributes except possibly <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>, <a href=http://www.whatwg.org/html/#dom-font-color><code class=external data-anolis-spec=html title=dom-font-color>color</code></a>,
+<a href=http://www.whatwg.org/html/#dom-font-face><code class=external data-anolis-spec=html title=dom-font-face>face</code></a>, and/or <a href=http://www.whatwg.org/html/#dom-font-size><code class=external data-anolis-spec=html title=dom-font-size>size</code></a>.
+
+<p class=note>Conceptually, a <a href=#styling-element>styling element</a> is a phrasing
+element whose only purpose is to style text. Thus changing around styling
+elements (such as moving them, breaking them up, deleting them, or switching
+them with other styling elements) is fine as long as the style is preserved.
+In fact, some styling elements are supposed to have semantics other than
+styling, but the algorithms here treat them as styling elements anyway, for
+compatibility with legacy user-agents that treat them that way.
+
<p>A <dfn id=simple-styling-element>simple styling element</dfn> is an <a href=#html-element>HTML element</a> for
which at least one of the following holds:
@@ -301,30 +325,36 @@
element with exactly one attribute, which is <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>, which sets no CSS
properties (including invalid or unrecognized properties).
- <li>It is a <a href=http://www.whatwg.org/html/#font><code class=external data-anolis-spec=html title=font>font</code></a> element with one attribute, which is either
+ <li>It is a <a href=http://www.whatwg.org/html/#font><code class=external data-anolis-spec=html title=font>font</code></a> element with exactly one attribute, which is either
<a href=http://www.whatwg.org/html/#dom-font-color><code class=external data-anolis-spec=html title=dom-font-color>color</code></a>, <a href=http://www.whatwg.org/html/#dom-font-face><code class=external data-anolis-spec=html title=dom-font-face>face</code></a>, or <a href=http://www.whatwg.org/html/#dom-font-size><code class=external data-anolis-spec=html title=dom-font-size>size</code></a>.
- <li>It is a <a href=http://www.whatwg.org/html/#the-b-element><code class=external data-anolis-spec=html title="the b element">b</code></a> or <a href=http://www.whatwg.org/html/#the-strong-element><code class=external data-anolis-spec=html title="the strong element">strong</code></a> element with one attribute, which is
- <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>, and the only CSS property set by the <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a> attribute
- (including invalid or unrecognized properties) is "font-weight".
+ <li>It is a <a href=http://www.whatwg.org/html/#the-b-element><code class=external data-anolis-spec=html title="the b element">b</code></a> or <a href=http://www.whatwg.org/html/#the-strong-element><code class=external data-anolis-spec=html title="the strong element">strong</code></a> element with exactly one attribute, which is
+ <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>, and the <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a> attribute sets exactly one CSS property
+ (including invalid or unrecognized properties), which is "font-weight".
- <li>It is an <a href=http://www.whatwg.org/html/#the-i-element><code class=external data-anolis-spec=html title="the i element">i</code></a> or <a href=http://www.whatwg.org/html/#the-em-element><code class=external data-anolis-spec=html title="the em element">em</code></a> element with one attribute, which is <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>,
- and the only CSS property set by the <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a> attribute (including invalid
- or unrecognized properties) is "font-style".
+ <li>It is an <a href=http://www.whatwg.org/html/#the-i-element><code class=external data-anolis-spec=html title="the i element">i</code></a> or <a href=http://www.whatwg.org/html/#the-em-element><code class=external data-anolis-spec=html title="the em element">em</code></a> element with exactly one attribute, which is
+ <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>, and the <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a> attribute sets exactly one CSS property
+ (including invalid or unrecognized properties), which is "font-style".
- <li>It is a <a href=http://www.whatwg.org/html/#the-u-element><code class=external data-anolis-spec=html title="the u element">u</code></a> element with one attribute, which is <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>, and the
- only CSS property set by the <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a> attribute (including invalid or
- unrecognized properties) is "text-decoration", which is set to "underline" or
- "none".
+ <li>It is a <a href=http://www.whatwg.org/html/#the-u-element><code class=external data-anolis-spec=html title="the u element">u</code></a> element with exactly one attribute, which is <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>, and
+ the <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a> attribute sets exactly one CSS property (including invalid or
+ unrecognized properties), which is "text-decoration", which is set to
+ "underline" or "none".
<li>It is a <a href=http://www.whatwg.org/html/#font><code class=external data-anolis-spec=html title=font>font</code></a> or <a href=http://www.whatwg.org/html/#the-span-element><code class=external data-anolis-spec=html title="the span element">span</code></a> element with exactly one attribute, which is
<a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>, and the <a href=http://www.whatwg.org/html/#the-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a> attribute sets exactly one CSS property
(including invalid or unrecognized properties).
</ol>
-<p class=note>Conceptually, a <a href=#simple-styling-element>simple styling element</a> is an element
-which has a <a href=#specified-style>specified style</a> for exactly one CSS property, but does
-nothing else.
+<p class=note>Conceptually, a <a href=#simple-styling-element>simple styling element</a> is a
+<a href=#styling-element>styling element</a> which <a href=#specified-style title="specified
+style">specifies</a> at most one CSS property.
+
+<p>The <dfn id=css-styling-flag>CSS styling flag</dfn> is a boolean flag, which must initially be
+false.
+
+<p class=XXX>Is the styling flag associated with the document, with the editing
+host, what? Needs reverse-engineering.
<p>When the user agent is instructed to run a particular method, it must follow
the steps defined for that method in the appropriate specification, not act as
@@ -476,7 +506,7 @@
set.
</ol>
- <li>If <var title="">element</var>'s <var title="">specified style</var> for
+ <li>If <var title="">element</var>'s <a href=#specified-style>specified style</a> for
<var title="">property</var> is null, return the empty list.
<!-- If we get past this step, we're something like <b class=foo> where we
want to keep the extra attributes, so we stick them on a span. -->
@@ -502,6 +532,32 @@
<var title="">node</var>, given a CSS property name <var title="">property</var> and a new value
<var title="">new value</var>, it must run the following steps:
+<!-- This algorithm goes up to just below the nearest ancestor with the right
+style, then re-applies the bad styles repeatedly going down, omitting the
+things we want to have the new style. This is basically what WebKit does,
+although WebKit sometimes starts higher up and therefore makes more intrusive
+changes, often creating more markup.
+
+Gecko instead seems to start breaking up elements from the bottom, so that the
+range consists of a few consecutive siblings, and it can then break up the
+problematic element into a maximum of two pieces. The spec's approach seems to
+create fewer elements and simpler markup (or at least markup that's no more
+complex) in every case I throw at it.
+
+Gecko's approach does have the major advantage that it gets underlines right in
+many cases for free. E.g.,
+
+ <u>foo<font color=red>[bar]baz</font></u>
+ -> <u>foo</u><font color=red>bar<u>baz</u></font> (spec)
+ -> <u>foo</u><font color=red>bar</font><u><font color=red>baz</font></u> (Gecko)
+
+The spec's markup here is much shorter and contains fewer elements, but is
+wrong: the underline under "baz" has changed color from black to red. It might
+be worth trying to copy Gecko's results in such cases, but that won't solve all
+underline problems, so perhaps it's not worth it.
+
+Opera also seems to break up the markup surrounding the range, but even more
+aggressively: even if it doesn't need to pull down styles. -->
<ol>
<li>If <var title="">node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is not an <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>, abort this
algorithm. <!-- E.g., a text node child of a document fragment. -->
@@ -588,84 +644,96 @@
After forcing the style, descendants might still have different style.
<ol>
- <!-- Even if the style matches, we stick it in a preceding sibling if
- possible. This ensures "a<cite>b</cite>c" -> "<i>a<cite>b</cite>c</i>"
- instead of "<i>a</i><cite>b</cite><i>c</i>". -->
+ <li>If <var title="">node</var>'s <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is null, abort this algorithm.
+
<li>If <var title="">node</var> is an <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>, <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a>, <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment><code class=external data-anolis-spec=domcore>Comment</code></a>, or
<a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#processinginstruction><code class=external data-anolis-spec=domcore>ProcessingInstruction</code></a> node, and is not an <a href=#unwrappable-element>unwrappable
element</a>:
<ol>
- <!-- Handle cases like bolding "bar" in "<i><b>Foo</b></i>bar".
+ <!-- Even if the style matches, we stick it in a preceding sibling if
+ possible. This ensures "a<cite>b</cite>c" -> "<i>a<cite>b</cite>c</i>"
+ instead of "<i>a</i><cite>b</cite><i>c</i>". While we're at it, we also
+ handle more elaborate cases like <b>foo</b>[bar]<b>baz</b> and even
+ <i><b>foo</b></i>[bar]<i><b>baz</b></i> (the latter becomes
+ <b><i>foo</i>bar<i>baz</i></b>).
+
Theoretically this algorithm could pointlessly reorganize the DOM in the
event of unreasonable style rules, but it's not a big enough deal for us to
- care, probably. -->
- <!-- This is probably more complicated than we want, given how likely this
- is to come up, so I've commented it out for now.
- <li>Let <var title>candidate</var> be <var title>node</var>'s <code data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code>.
+ care, since the resulting style will still be right. -->
+ <li>Let <var title="">candidate</var> be <var title="">node</var>'s <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling><code class=external data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code></a>.
- <li>While <var title>candidate</var> is a <span>simple styling element</span>,
- and <var title>candidate</var> has exactly one <span data-anolis-spec=domcore title=concept-tree-child>child</span>, and that <span data-anolis-spec=domcore title=concept-tree-child>child</span> is
- also a <span>simple styling element</span>, and <var title>candidate</var>'s
- <span>specified style</span> for <var title>property</var> is not <var title>new
- value</var>, set <var title>candidate</var> to its <span data-anolis-spec=domcore title=concept-tree-child>child</span>.
+ <li>While <var title="">candidate</var> is a <a href=#styling-element>styling element</a>, and
+ <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=#styling-element>styling element</a>, and <var title="">candidate</var> is not a
+ <a href=#simple-styling-element>simple styling element</a> or <var title="">candidate</var>'s
+ <a href=#specified-style>specified style</a> for <var title="">property</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>.
- <li>If <var title>candidate</var> is a <span>simple styling element</span> whose
- <span>specified style</span> and computed style for <var title>property</var> are
- both <var title>new value</var>, and <var title>candidate</var> is not the
- <code data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code> of <var title>node</var>:
+ <li>If <var title="">candidate</var> is a <a href=#simple-styling-element>simple styling element</a> whose
+ <a href=#specified-style>specified style</a> and <a href=#effective-style>effective style</a> for
+ <var title="">property</var> are both <var title="">new value</var>, and <var title="">candidate</var>
+ is not the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling><code class=external data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code></a> of <var title="">node</var>:
<ol>
- <li>While <var title>candidate</var> has <span data-anolis-spec=domcore title=concept-tree-child>children</span>, append the first
- <span data-anolis-spec=domcore title=concept-tree-child>child</span> of <var title>candidate</var> as the last <span data-anolis-spec=domcore title=concept-tree-child>child</span> of
- <var title>candidate</var>'s <span data-anolis-spec=domcore title=concept-tree-parent>parent</span>.
-
- <li>Insert <var title>candidate</var> into <var title>node</var>'s <span data-anolis-spec=domcore title=concept-tree-parent>parent</span> before
- <var title>node</var>.
-
- <li>Append the <code data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code> of <var title>candidate</var> as the last
- <span data-anolis-spec=domcore title=concept-tree-child>child</span> of <var title>candidate</var>.
- </ol>
- -->
+ <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>, append 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> as the last <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>'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>.
- <li>If <var title="">node</var>'s <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling><code class=external data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code></a> is a <a href=#simple-styling-element>simple styling
- element</a> whose <a href=#specified-style>specified style</a> and <a href=#effective-style>effective
- style</a> for <var title="">property</var> are both <var title="">new value</var>, append
- <var title="">node</var> as the last <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 its <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling><code class=external data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code></a> and abort
- this algorithm.
-
- <!--
- <li>Let <var title>candidate</var> be <var title>node</var>'s <code data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code>.
+ <li>Insert <var title="">candidate</var> into <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> before
+ <var title="">node</var>.
- <li>While <var title>candidate</var> is a <span>simple styling element</span>,
- and <var title>candidate</var> has exactly one <span data-anolis-spec=domcore title=concept-tree-child>child</span>, and that <span data-anolis-spec=domcore title=concept-tree-child>child</span> is
- also a <span>simple styling element</span>, and <var title>candidate</var>'s
- <span>specified style</span> for <var title>property</var> is not <var title>new
- value</var>, set <var title>candidate</var> to its <span data-anolis-spec=domcore title=concept-tree-child>child</span>.
+ <li>Append the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling><code class=external data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code></a> of <var title="">candidate</var> as the last
+ <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>.
+ </ol>
- <li>If <var title>candidate</var> is a <span>simple styling element</span> whose
- <span>specified style</span> and computed style for <var title>property</var> are
- both <var title>new value</var>, and <var title>candidate</var> is not the
- <code data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code> of <var title>node</var>:
+ <li>Let <var title="">candidate</var> be <var title="">node</var>'s <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling><code class=external data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code></a>.
+
+ <li>While <var title="">candidate</var> is a <a href=#styling-element>styling element</a>, and
+ <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=#styling-element>styling element</a>, and <var title="">candidate</var> is not a
+ <a href=#simple-styling-element>simple styling element</a> or <var title="">candidate</var>'s
+ <a href=#specified-style>specified style</a> for <var title="">property</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>.
+
+ <li>If <var title="">candidate</var> is a <a href=#simple-styling-element>simple styling element</a> whose
+ <a href=#specified-style>specified style</a> and <a href=#effective-style>effective style</a> for
+ <var title="">property</var> are both <var title="">new value</var>, and <var title="">candidate</var>
+ is not the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling><code class=external data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code></a> of <var title="">node</var>:
<ol>
- <li>While <var title>candidate</var> has <span data-anolis-spec=domcore title=concept-tree-child>children</span>, append the first
- <span data-anolis-spec=domcore title=concept-tree-child>child</span> of <var title>candidate</var> as the last <span data-anolis-spec=domcore title=concept-tree-child>child</span> of
- <var title>candidate</var>'s <span data-anolis-spec=domcore title=concept-tree-parent>parent</span>.
-
- <li>Insert <var title>candidate</var> into <var title>node</var>'s <span data-anolis-spec=domcore title=concept-tree-parent>parent</span> after
- <var title>node</var>.
+ <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>, append 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> as the last <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>'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>.
- <li>Append the <code data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code> of <var title>candidate</var> as the last
- <span data-anolis-spec=domcore title=concept-tree-child>child</span> of <var title>candidate</var>.
- </ol>
- -->
+ <li>Insert <var title="">candidate</var> into <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> after
+ <var title="">node</var>.
- <li>If <var title="">node</var>'s <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling><code class=external data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code></a> is a <a href=#simple-styling-element>simple styling
- element</a> whose <a href=#specified-style>specified style</a> and <a href=#effective-style>effective
- style</a> for <var title="">property</var> are both <var title="">new value</var>, insert
- <var title="">node</var> as 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 its <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling><code class=external data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code></a> and abort
- this algorithm.
+ <li>Append the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling><code class=external data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code></a> of <var title="">candidate</var> as the last
+ <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>.
+ </ol>
+
+ <li>Let <var title="">previous sibling</var> and <var title="">next sibling</var> be
+ <var title="">node</var>'s <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-previoussibling><code class=external data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code></a> and <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling><code class=external data-anolis-spec=domcore title=dom-Node-nextSibling>nextSibling</code></a>.
+
+ <li>If <var title="">previous sibling</var> is a <a href=#simple-styling-element>simple styling element</a>
+ whose <a href=#specified-style>specified style</a> and <a href=#effective-style>effective style</a> for
+ <var title="">property</var> are both <var title="">new value</var>, append <var title="">node</var>
+ as the last <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="">previous sibling</var>.
+
+ <li>If <var title="">next sibling</var> is a <a href=#simple-styling-element>simple styling element</a>
+ whose <a href=#specified-style>specified style</a> and <a href=#effective-style>effective style</a> for
+ <var title="">property</var> are both <var title="">new value</var>:
+
+ <ol>
+ <li>If <var title="">node</var> is not a <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="">previous sibling</var>,
+ insert <var title="">node</var> as 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="">next sibling</var>.
+
+ <li>Otherwise, while <var title="">next sibling</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>, append 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="">next sibling</var> as the last <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="">previous sibling</var>. Then remove <var title="">next sibling</var> from
+ 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>.
+ </ol>
</ol>
<li>If the <a href=#effective-style>effective style</a> of <var title="">property</var> is <var title="">new
@@ -693,18 +761,45 @@
<li>If the <a href=#effective-style>effective style</a> of <var title="">property</var> is <var title="">new
value</var> on <var title="">node</var>, abort this algorithm.
- <li>If <var title="">property</var> is "font-weight" and <var title="">new value</var> is
- "bold", let <var title="">tag</var> be "b".
-
- <li>If <var title="">property</var> is "font-style" and <var title="">new value</var> is
- "italic", let <var title="">tag</var> be "i".
+ <li>Let <var title="">new parent</var> be null.
- <li>If <var title="">property</var> is "text-decoration" and <var title="">new value</var> is
- "underline", let <var title="">tag</var> be "u".
+ <li>If the <a href=#css-styling-flag>CSS styling flag</a> is false:
- <li>If <var title="">tag</var> is not set, let <var title="">tag</var> be "span".
+ <ol>
+ <li>If <var title="">property</var> is "font-weight" and <var title="">new value</var> is
+ "bold", let <var title="">new parent</var> be the result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement("b")</code></a> on the
+ <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">node</var>.
- <li>Let <var title="">new parent</var> be the result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement(<var title="">tag</var>)</code></a> on the
+ <li>If <var title="">property</var> is "font-style" and <var title="">new value</var> is
+ "italic", let <var title="">new parent</var> be the result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement("i")</code></a> on the
+ <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">node</var>.
+
+ <li>If <var title="">property</var> is "text-decoration" and <var title="">new value</var> is
+ "underline", let <var title="">new parent</var> be the result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement("u")</code></a> on the
+ <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">node</var>.
+
+ <li>If <var title="">property</var> is "color", let <var title="">new parent</var> be the
+ result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement("font")</code></a> on the
+ <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">node</var>, then set the <a href=http://www.whatwg.org/html/#dom-font-color><code class=external data-anolis-spec=html title=dom-font-color>color</code></a> attribute
+ of <var title="">new parent</var> to <var title="">new value</var>.
+
+ <p class=XXX>This can be wrong if, e.g., the color has an alpha channel.
+ We also need to specify exactly how it's serialized, since CSSOM doesn't
+ cover this. It might be best to always output simple colors.
+
+ <li>If <var title="">property</var> is "font-family", let <var title="">new parent</var> be
+ the result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement("font")</code></a> on the
+ <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">node</var>, then set the <a href=http://www.whatwg.org/html/#dom-font-face><code class=external data-anolis-spec=html title=dom-font-face>face</code></a> attribute
+ of <var title="">new parent</var> to <var title="">new value</var>.
+
+ <li>If <var title="">property</var> is "font-size", let <var title="">new parent</var> be the
+ result of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement("font")</code></a> on the
+ <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">node</var>, then set the <a href=http://www.whatwg.org/html/#dom-font-size><code class=external data-anolis-spec=html title=dom-font-size>size</code></a> attribute
+ of <var title="">new parent</var> to <var title="">new value</var>.
+ </ol>
+
+ <li>If <var title="">new parent</var> is null, let <var title="">new parent</var> be the result
+ of calling <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement><code class=external data-anolis-spec=domcore title=dom-Document-createElement>createElement("span")</code></a> on the
<a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument><code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code></a> of <var title="">node</var>.
<li>Insert <var title="">new parent</var> in <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> before
@@ -720,13 +815,25 @@
of <var title="">property</var> for <var title="">node</var> is not <var title="">new value</var>:
<ol>
- <li>Set the CSS property <var title="">property</var> of <var title="">node</var> to <var title="">new
- value</var>.
-
<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>
before <var title="">new parent</var>.
<li>Remove <var title="">new parent</var> from 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="">new parent</var> is a <a href=http://www.whatwg.org/html/#the-span-element><code class=external data-anolis-spec=html title="the span element">span</code></a>, set the CSS property
+ <var title="">property</var> of <var title="">node</var> to <var title="">new value</var>.
+
+ <li>Otherwise:
+
+ <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 <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>s whose <a href=#specified-style>specified style</a> for
+ <var title="">property</var> is neither null nor equal to <var title="">new value</var>.
+
+ <li><a href=#force-the-style>Force the style</a> of each <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> in <var title="">children</var>,
+ with <var title="">property</var> and <var title="">new value</var> as in this invocation
+ of the algorithm.
+ </ol>
</ol>
</ol>
@@ -835,7 +942,7 @@
<li>Let <var title="">children</var> be the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>children</a> of <var title="">node</var>.
- <li><a href=#style>Style</a> each member of <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>.
+ <li><a href=#style>Style</a> each member of <var title="">children</var>.
<p class=note>Styling a node involves clearing its styles, which can remove
it from the tree. Implementers should be careful to compute the list of
@@ -1155,6 +1262,20 @@
<dd><p><strong>Value</strong>: Always the empty string.
+<dt><code title=""><dfn id=command-stylewithcss title=command-stylewithcss>styleWithCSS</dfn></code>
+
+<dd><p><strong>Action</strong>: Convert <var title="">value</var> to a boolean according
+to the algorithm in WebIDL, and set the <a href=#css-styling-flag>CSS styling flag</a> to the
+result.
+
+<p class=XXX>Properly cross-reference.
+
+<dd><p><strong>State</strong>: True if the <a href=#css-styling-flag>CSS styling flag</a> is
+true, otherwise false.
+
+<dd><p><strong>Value</strong>:
+
+
<dt><code title=""><dfn id=command-underline title=command-underline>underline</dfn></code>
<dd><p><strong>Action</strong>: <a href=#decompose>Decompose</a> the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>. If the
@@ -1204,7 +1325,6 @@
style</a> either null or "underline" for text-decoration. Otherwise false.
<dd><p><strong>Value</strong>: Always the empty string.
-</dl>
<dt><code title=""><dfn id=command-unlink title=command-unlink>unlink</dfn></code>
@@ -1254,6 +1374,22 @@
<dd><p><strong>Value</strong>: Always the empty string.
+<dt><code title=""><dfn id=command-usecss title=command-usecss>useCSS</dfn></code>
+
+<dd><p><strong>Action</strong>: Convert <var title="">value</var> to a boolean according
+to the algorithm in WebIDL, and set the <a href=#css-styling-flag>CSS styling flag</a> to the
+negation of the result. Since the effect of this command is the opposite of
+what one would expect, user agents are encouraged to point authors to <a href=#command-stylewithcss><code title=command-stylewithcss>styleWithCSS</code></a> when <a href=#command-usecss><code title=command-usecss>useCSS</code></a> is used, such as by logging a warning to an
+error console.
+
+<p class=XXX>Properly cross-reference.
+
+<dd><p><strong>State</strong>:
+
+<dd><p><strong>Value</strong>:
+</dl>
+
+
<h2 class=no-num id=references>References</h2><!--REFS-->
<p>All references are normative unless marked "Non-normative".</p>
<div id=anolis-references><dl></dl></div>
--- a/implementation.js Wed Mar 23 11:59:33 2011 -0600
+++ b/implementation.js Wed Mar 23 16:03:54 2011 -0600
@@ -2,6 +2,8 @@
var htmlNamespace = "http://www.w3.org/1999/xhtml";
+var cssStylingFlag = false;
+
// Utility functions
function nextNode(node) {
if (node.hasChildNodes()) {
@@ -262,10 +264,22 @@
// "An unwrappable element is an HTML element which may not be used where only
// phrasing content is expected (not counting unknown or obsolete elements,
-// which cannot be used at all)."
+// which cannot be used at all); or any Element whose display property computes
+// to something other than "inline", "inline-block", or "inline-table"."
//
// I don't bother implementing this exactly, just well enough for testing.
function isUnwrappableElement(node) {
+ if (!node || node.nodeType != Node.ELEMENT_NODE) {
+ return false;
+ }
+
+ var display = getComputedStyle(node).display;
+ if (display != "inline"
+ && display != "inline-block"
+ && display != "inline-table") {
+ return true;
+ }
+
if (!isHtmlElement(node)) {
return false;
}
@@ -395,6 +409,52 @@
return null;
}
+// "A styling element is a b, em, i, span, strong, or u element with no
+// attributes except possibly style, or a font element with no attributes
+// except possibly style, color, face, and/or size."
+function isStylingElement(node) {
+ if (!isHtmlElement(node)) {
+ return false;
+ }
+
+ if (["B", "EM", "I", "SPAN", "STRONG", "U"].indexOf(node.tagName) != -1) {
+ if (node.attributes.length == 0) {
+ return true;
+ }
+
+ if (node.attributes.length == 1
+ && node.hasAttribute("style")) {
+ return true;
+ }
+ }
+
+ if (node.tagName == "FONT") {
+ var numAttrs = node.attributes.length;
+
+ if (node.hasAttribute("style")) {
+ numAttrs--;
+ }
+
+ if (node.hasAttribute("color")) {
+ numAttrs--;
+ }
+
+ if (node.hasAttribute("face")) {
+ numAttrs--;
+ }
+
+ if (node.hasAttribute("size")) {
+ numAttrs--;
+ }
+
+ if (numAttrs == 0) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
function isSimpleStylingElement(node) {
// "A simple styling element is an HTML element for which at least one of
// the following holds:"
@@ -402,9 +462,13 @@
return false;
}
+ // Only these elements can possibly be a simple styling element.
+ if (["B", "EM", "FONT", "I", "SPAN", "STRONG", "U"].indexOf(node.tagName) == -1) {
+ return false;
+ }
+
// "It is a b, em, font, i, span, strong, or u element with no attributes."
- if (node.attributes.length == 0
- && ["B", "EM", "FONT", "I", "SPAN", "STRONG", "U"].indexOf(node.tagName) != -1) {
+ if (node.attributes.length == 0) {
return true;
}
@@ -423,19 +487,19 @@
return true;
}
- // "It is a font element with one attribute, which is either color, face,
- // or size."
+ // "It is a font element with exactly one attribute, which is either color,
+ // face, or size."
if (node.tagName == "FONT"
&& (node.hasAttribute("color")
- || node.hasAttribute("face")
- || node.hasAttribute("size")
+ || node.hasAttribute("face")
+ || node.hasAttribute("size")
)) {
return true;
}
- // "It is a b or strong element with one attribute, which is style, and the
- // only CSS property set by the style attribute (including invalid or
- // unrecognized properties) is "font-weight"."
+ // "It is a b or strong element with exactly one attribute, which is style,
+ // and the style attribute sets exactly one CSS property (including invalid
+ // or unrecognized properties), which is "font-weight"."
if ((node.tagName == "B" || node.tagName == "STRONG")
&& node.hasAttribute("style")
&& node.style.length == 1
@@ -443,9 +507,9 @@
return true;
}
- // "It is an i or em element with one attribute, which is style, and the
- // only CSS property set by the style attribute (including invalid or
- // unrecognized properties) is "font-style"."
+ // "It is an i or em element with exactly one attribute, which is style,
+ // and the style attribute sets exactly one CSS property (including invalid
+ // or unrecognized properties), which is "font-style"."
if ((node.tagName == "I" || node.tagName == "EM")
&& node.hasAttribute("style")
&& node.style.length == 1
@@ -453,10 +517,10 @@
return true;
}
- // "It is a u element with one attribute, which is style, and the only CSS
- // property set by the style attribute (including invalid or unrecognized
- // properties) is "text-decoration", which is set to "underline" or
- // "none"."
+ // "It is a u element with exactly one attribute, which is style, and the
+ // style attribute sets exactly one CSS property (including invalid or
+ // unrecognized properties), which is "text-decoration", which is set to
+ // "underline" or "none"."
if (node.tagName == "U"
&& node.hasAttribute("style")
&& node.style.length == 1
@@ -769,6 +833,11 @@
}
function forceStyle(node, property, newValue) {
+ // "If node's parent is null, abort this algorithm."
+ if (!node.parentNode) {
+ return;
+ }
+
// "If node is an Element, Text, Comment, or ProcessingInstruction node,
// and is not an unwrappable element:"
if ((node.nodeType == Node.ELEMENT_NODE
@@ -776,28 +845,110 @@
|| node.nodeType == Node.COMMENT_NODE
|| node.nodeType == Node.PROCESSING_INSTRUCTION_NODE)
&& !isUnwrappableElement(node)) {
- // "If node's previousSibling is a simple styling element whose
- // specified style and effective style for property are both new value,
- // append node as the last child of its previousSibling and abort this
- // algorithm."
- if (isSimpleStylingElement(node.previousSibling)
- && cssValuesEqual(property, getSpecifiedStyle(node.previousSibling, property), newValue)
- && cssValuesEqual(property, getEffectiveStyle(node.previousSibling, property), newValue)) {
- node.previousSibling.appendChild(node);
- return;
+ // "Let candidate be node's previousSibling."
+ var candidate = node.previousSibling;
+
+ // "While candidate is a styling element, and candidate has exactly one
+ // child, and that child is also a styling element, and candidate is
+ // not a simple styling element or candidate's specified style for
+ // property is not new value, set candidate to its child."
+ while (isStylingElement(candidate)
+ && candidate.childNodes.length == 1
+ && isStylingElement(candidate.firstChild)
+ && (!isSimpleStylingElement(candidate)
+ || !cssValuesEqual(property, getSpecifiedStyle(candidate, property), newValue))) {
+ candidate = candidate.firstChild;
}
- // "If node's nextSibling is a simple styling element whose specified
- // style and effective style for property are both new value, insert
- // node as the first child of its nextSibling and abort this
- // algorithm."
- if (isSimpleStylingElement(node.nextSibling)
- && cssValuesEqual(property, getSpecifiedStyle(node.nextSibling, property), newValue)
- && cssValuesEqual(property, getEffectiveStyle(node.nextSibling, property), newValue)) {
- node.nextSibling.insertBefore(node, node.nextSibling.childNodes.length
- ? node.nextSibling.childNodes[0]
- : null);
- return;
+ // "If candidate is a simple styling element whose specified style and
+ // effective style for property are both new value, and candidate is
+ // not the previousSibling of node:"
+ if (isSimpleStylingElement(candidate)
+ && cssValuesEqual(property, getSpecifiedStyle(candidate, property), newValue)
+ && cssValuesEqual(property, getEffectiveStyle(candidate, property), newValue)
+ && candidate != node.previousSibling) {
+ // "While candidate has children, append the first child of
+ // candidate as the last child of candidate's parent."
+ while (candidate.childNodes.length > 0) {
+ candidate.parentNode.appendChild(candidate.firstChild);
+ }
+
+ // "Insert candidate into node's parent before node."
+ node.parentNode.insertBefore(candidate, node);
+
+ // "Append the previousSibling of candidate as the last child of
+ // candidate."
+ candidate.appendChild(candidate.previousSibling);
+ }
+
+ // "Let candidate be node's nextSibling."
+ var candidate = node.nextSibling;
+
+ // "While candidate is a styling element, and candidate has exactly one
+ // child, and that child is also a styling element, and candidate is
+ // not a simple styling element or candidate's specified style for
+ // property is not new value, set candidate to its child."
+ while (isStylingElement(candidate)
+ && candidate.childNodes.length == 1
+ && isStylingElement(candidate.firstChild)
+ && (!isSimpleStylingElement(candidate)
+ || !cssValuesEqual(property, getSpecifiedStyle(candidate, property), newValue))) {
+ candidate = candidate.firstChild;
+ }
+
+ // "If candidate is a simple styling element whose specified style and
+ // effective style for property are both new value, and candidate is
+ // not the nextSibling of node:"
+ if (isSimpleStylingElement(candidate)
+ && cssValuesEqual(property, getSpecifiedStyle(candidate, property), newValue)
+ && cssValuesEqual(property, getEffectiveStyle(candidate, property), newValue)
+ && candidate != node.nextSibling) {
+ // "While candidate has children, append the first child of
+ // candidate as the last child of candidate's parent."
+ while (candidate.childNodes.length > 0) {
+ candidate.parentNode.appendChild(candidate.firstChild);
+ }
+
+ // "Insert candidate into node's parent after node."
+ node.parentNode.insertBefore(candidate, node.nextSibling);
+
+ // "Append the nextSibling of candidate as the last child of
+ // candidate."
+ candidate.appendChild(candidate.nextSibling);
+ }
+
+ // "Let previous sibling and next sibling be node's previousSibling and
+ // nextSibling."
+ var previousSibling = node.previousSibling;
+ var nextSibling = node.nextSibling;
+
+ // "If previous sibling is a simple styling element whose specified
+ // style and effective style for property are both new value, append
+ // node as the last child of previous sibling."
+ if (isSimpleStylingElement(previousSibling)
+ && cssValuesEqual(property, getSpecifiedStyle(previousSibling, property), newValue)
+ && cssValuesEqual(property, getEffectiveStyle(previousSibling, property), newValue)) {
+ previousSibling.appendChild(node);
+ }
+
+ // "If next sibling is a simple styling element whose specified style
+ // and effective style for property are both new value:"
+ if (isSimpleStylingElement(nextSibling)
+ && cssValuesEqual(property, getSpecifiedStyle(nextSibling, property), newValue)
+ && cssValuesEqual(property, getEffectiveStyle(nextSibling, property), newValue)) {
+ // "If node is not a child of previous sibling, insert node as the
+ // first child of next sibling."
+ if (node.parentNode != previousSibling) {
+ nextSibling.insertBefore(node, nextSibling.firstChild);
+ // "Otherwise, while next sibling has children, append the first
+ // child of next sibling as the last child of previous sibling.
+ // Then remove next sibling from its parent."
+ } else {
+ while (nextSibling.childNodes.length) {
+ previousSibling.appendChild(nextSibling.firstChild);
+ }
+ nextSibling.parentNode.removeChild(nextSibling);
+ }
}
}
@@ -847,25 +998,62 @@
return;
}
- // "If property is "font-weight" and new value is "bold", let tag be "b"."
- var tag;
- if (property == "fontWeight" && (newValue == "bold" || newValue == "700")) {
- tag = "b";
- // "If property is "font-style" and new value is "italic", let tag be "i"."
- } else if (property == "fontStyle" && newValue == "italic") {
- tag = "i";
- // "If property is "text-decoration" and new value is "underline", let tag
- // be "u"."
- } else if (property == "textDecoration" && newValue == "underline") {
- tag = "u";
- // "If tag is not set, let tag be "span"."
- } else {
- tag = "span";
+ // "Let new parent be null."
+ var newParent = null;
+
+ // "If the CSS styling flag is false:"
+ if (!cssStylingFlag) {
+ // "If property is "font-weight" and new value is "bold", let new
+ // parent be the result of calling createElement("b") on the
+ // ownerDocument of node."
+ if (property == "fontWeight" && (newValue == "bold" || newValue == "700")) {
+ newParent = node.ownerDocument.createElement("b");
+ }
+
+ // "If property is "font-style" and new value is "italic", let new
+ // parent be the result of calling createElement("i") on the
+ // ownerDocument of node."
+ if (property == "fontStyle" && newValue == "italic") {
+ newParent = node.ownerDocument.createElement("i");
+ }
+
+ // "If property is "text-decoration" and new value is "underline", let
+ // new parent be the result of calling createElement("u") on the
+ // ownerDocument of node."
+ if (property == "textDecoration" && newValue == "underline") {
+ newParent = node.ownerDocument.createElement("u");
+ }
+
+ // "If property is "color", let new parent be the result of calling
+ // createElement("font") on the ownerDocument of node, then set the
+ // color attribute of new parent to new value."
+ if (property == "color") {
+ newParent = node.ownerDocument.createElement("font");
+ newParent.color = newValue;
+ }
+
+ // "If property is "font-family", let new parent be the result of
+ // calling createElement("font") on the ownerDocument of node, then set
+ // the face attribute of new parent to new value."
+ if (property == "fontFamily") {
+ newParent = node.ownerDocument.createElement("font");
+ newParent.face = newValue;
+ }
+
+ // "If property is "font-size", let new parent be the result of calling
+ // createElement("font") on the ownerDocument of node, then set the
+ // size attribute of new parent to new value."
+ if (property == "fontSize") {
+ newParent = node.ownerDocument.createElement("font");
+ newParent.size = newValue;
+ }
}
- // "Let new parent be the result of calling createElement(tag) on the
- // ownerDocument of node."
- var newParent = node.ownerDocument.createElement(tag);
+ // "If new parent is null, let new parent be the result of calling
+ // createElement("span") on the ownerDocument of node."
+ if (!newParent) {
+ newParent = node.ownerDocument.createElement("span");
+ }
// "Insert new parent in node's parent before node."
node.parentNode.insertBefore(newParent, node);
@@ -883,14 +1071,41 @@
// not new value:"
if (node.nodeType == Node.ELEMENT_NODE
&& !cssValuesEqual(property, getEffectiveStyle(node, property), newValue)) {
- // "Set the CSS property property of node to new value."
- node.style[property] = newValue;
-
// "Insert node into the parent of new parent before new parent."
newParent.parentNode.insertBefore(node, newParent);
// "Remove new parent from its parent."
newParent.parentNode.removeChild(newParent);
+
+ // "If new parent is a span, set the CSS property property of node to
+ // new value."
+ if (newParent.tagName == "SPAN") {
+ node.style[property] = newValue;
+
+ // "Otherwise:"
+ } else {
+ // "Let children be all children of node, omitting any that are
+ // Elements whose specified style for property is neither null nor
+ // equal to new value."
+ var children = [];
+ for (var i = 0; i < node.childNodes.length; i++) {
+ if (node.childNodes[i].nodeType == Node.ELEMENT_NODE) {
+ var specifiedStyle = getSpecifiedStyle(node.childNodes[i], property);
+
+ if (specifiedStyle !== null
+ && !cssValuesEqual(property, newValue, specifiedStyle)) {
+ continue;
+ }
+ }
+ children.push(node.childNodes[i]);
+ }
+
+ // "Force the style of each Node in children, with property and new
+ // value as in this invocation of the algorithm."
+ for (var i = 0; i < children.length; i++) {
+ forceStyle(children[i], property, newValue);
+ }
+ }
}
}
@@ -964,12 +1179,14 @@
function myExecCommand(commandId, showUI, value, range) {
commandId = commandId.toLowerCase();
- if (typeof range == "undefined") {
- range = getActiveRange(document);
- }
+ if (commandId != "stylewithcss" && commandId != "usecss") {
+ if (typeof range == "undefined") {
+ range = getActiveRange(document);
+ }
- if (!range) {
- return;
+ if (!range) {
+ return;
+ }
}
switch (commandId) {
@@ -1108,6 +1325,12 @@
}
break;
+ case "stylewithcss":
+ // "Convert value to a boolean according to the algorithm in WebIDL,
+ // and set the CSS styling flag to the result."
+ cssStylingFlag = Boolean(value);
+ break;
+
case "underline":
// "Decompose the Range. If the state of the Range for this command is
// then true, style each returned Node with property "text-decoration"
@@ -1120,6 +1343,12 @@
}
break;
+ case "usecss":
+ // "Convert value to a boolean according to the algorithm in WebIDL,
+ // and set the CSS styling flag to the negation of the result."
+ cssStylingFlag = !value;
+ break;
+
default:
break;
}
@@ -1137,6 +1366,10 @@
}
function getState(commandId, range) {
+ if (commandId == "stylewithcss") {
+ return cssStylingFlag;
+ }
+
if (commandId != "bold"
&& commandId != "italic"
&& commandId != "underline") {
--- a/source.html Wed Mar 23 11:59:33 2011 -0600
+++ b/source.html Wed Mar 23 16:03:54 2011 -0600
@@ -197,7 +197,9 @@
<li>Return the last [[range]] in <var>selection</var> whose [[rangestart]]
is <var>start</var>.
- <!-- This is what Firefox seems to do, no reason to change it . . . -->
+
+ <p class=XXX>Double-check that this is what Firefox actually does. It seems
+ pretty baroque.
<p class=note>In user agents that support only one [[range]] per
[[selection]], the active range is simply the only one in the selection.
@@ -205,7 +207,16 @@
<p>An <dfn>unwrappable element</dfn> is an <span>HTML element</span> which may
not be used where only [[phrasingcontent]] is expected (not counting unknown or
-obsolete elements, which cannot be used at all).
+obsolete elements, which cannot be used at all); or any [[element]] whose
+display property computes to something other than "inline", "inline-block", or
+"inline-table".
+
+<p class=XXX>Currently when we hit an unwrappable element, we ignore it and
+style its children. Alternatively, if we would otherwise create a span with a
+style element on it, maybe we could put the style element directly on the
+unwrappable element. This would produce shorter markup in many cases, but
+would also cause problems for things like background-color that do something
+different on block elements.
<p>The <dfn>effective style</dfn> of a [[node]] <var>node</var> for a given
<var>property</var> is returned by the following algorithm, which will return
@@ -281,6 +292,19 @@
<li>Return null.
</ol>
+<p>A <dfn>styling element</dfn> is a [[b]], [[em]], [[i]], [[span]],
+[[strong]], or [[u]] element with no attributes except possibly [[style]], or
+a [[font]] element with no attributes except possibly [[style]], [[fontcolor]],
+[[fontface]], and/or [[fontsize]].
+
+<p class=note>Conceptually, a <span>styling element</span> is a phrasing
+element whose only purpose is to style text. Thus changing around styling
+elements (such as moving them, breaking them up, deleting them, or switching
+them with other styling elements) is fine as long as the style is preserved.
+In fact, some styling elements are supposed to have semantics other than
+styling, but the algorithms here treat them as styling elements anyway, for
+compatibility with legacy user-agents that treat them that way.
+
<p>A <dfn>simple styling element</dfn> is an <span>HTML element</span> for
which at least one of the following holds:
@@ -292,30 +316,36 @@
element with exactly one attribute, which is [[style]], which sets no CSS
properties (including invalid or unrecognized properties).
- <li>It is a [[font]] element with one attribute, which is either
+ <li>It is a [[font]] element with exactly one attribute, which is either
[[fontcolor]], [[fontface]], or [[fontsize]].
- <li>It is a [[b]] or [[strong]] element with one attribute, which is
- [[style]], and the only CSS property set by the [[style]] attribute
- (including invalid or unrecognized properties) is "font-weight".
+ <li>It is a [[b]] or [[strong]] element with exactly one attribute, which is
+ [[style]], and the [[style]] attribute sets exactly one CSS property
+ (including invalid or unrecognized properties), which is "font-weight".
- <li>It is an [[i]] or [[em]] element with one attribute, which is [[style]],
- and the only CSS property set by the [[style]] attribute (including invalid
- or unrecognized properties) is "font-style".
+ <li>It is an [[i]] or [[em]] element with exactly one attribute, which is
+ [[style]], and the [[style]] attribute sets exactly one CSS property
+ (including invalid or unrecognized properties), which is "font-style".
- <li>It is a [[u]] element with one attribute, which is [[style]], and the
- only CSS property set by the [[style]] attribute (including invalid or
- unrecognized properties) is "text-decoration", which is set to "underline" or
- "none".
+ <li>It is a [[u]] element with exactly one attribute, which is [[style]], and
+ the [[style]] attribute sets exactly one CSS property (including invalid or
+ unrecognized properties), which is "text-decoration", which is set to
+ "underline" or "none".
<li>It is a [[font]] or [[span]] element with exactly one attribute, which is
[[style]], and the [[style]] attribute sets exactly one CSS property
(including invalid or unrecognized properties).
</ol>
-<p class=note>Conceptually, a <span>simple styling element</span> is an element
-which has a <span>specified style</span> for exactly one CSS property, but does
-nothing else.
+<p class=note>Conceptually, a <span>simple styling element</span> is a
+<span>styling element</span> which <span title="specified
+style">specifies</span> at most one CSS property.
+
+<p>The <dfn>CSS styling flag</dfn> is a boolean flag, which must initially be
+false.
+
+<p class=XXX>Is the styling flag associated with the document, with the editing
+host, what? Needs reverse-engineering.
<p>When the user agent is instructed to run a particular method, it must follow
the steps defined for that method in the appropriate specification, not act as
@@ -472,7 +502,7 @@
set.
</ol>
- <li>If <var>element</var>'s <var>specified style</var> for
+ <li>If <var>element</var>'s <span>specified style</span> for
<var>property</var> is null, return the empty list.
<!-- If we get past this step, we're something like <b class=foo> where we
want to keep the extra attributes, so we stick them on a span. -->
@@ -498,6 +528,32 @@
<var>node</var>, given a CSS property name <var>property</var> and a new value
<var>new value</var>, it must run the following steps:
+<!-- This algorithm goes up to just below the nearest ancestor with the right
+style, then re-applies the bad styles repeatedly going down, omitting the
+things we want to have the new style. This is basically what WebKit does,
+although WebKit sometimes starts higher up and therefore makes more intrusive
+changes, often creating more markup.
+
+Gecko instead seems to start breaking up elements from the bottom, so that the
+range consists of a few consecutive siblings, and it can then break up the
+problematic element into a maximum of two pieces. The spec's approach seems to
+create fewer elements and simpler markup (or at least markup that's no more
+complex) in every case I throw at it.
+
+Gecko's approach does have the major advantage that it gets underlines right in
+many cases for free. E.g.,
+
+ <u>foo<font color=red>[bar]baz</font></u>
+ -> <u>foo</u><font color=red>bar<u>baz</u></font> (spec)
+ -> <u>foo</u><font color=red>bar</font><u><font color=red>baz</font></u> (Gecko)
+
+The spec's markup here is much shorter and contains fewer elements, but is
+wrong: the underline under "baz" has changed color from black to red. It might
+be worth trying to copy Gecko's results in such cases, but that won't solve all
+underline problems, so perhaps it's not worth it.
+
+Opera also seems to break up the markup surrounding the range, but even more
+aggressively: even if it doesn't need to pull down styles. -->
<ol>
<li>If <var>node</var>'s [[parent]] is not an [[element]], abort this
algorithm. <!-- E.g., a text node child of a document fragment. -->
@@ -584,32 +640,36 @@
After forcing the style, descendants might still have different style.
<ol>
- <!-- Even if the style matches, we stick it in a preceding sibling if
- possible. This ensures "a<cite>b</cite>c" -> "<i>a<cite>b</cite>c</i>"
- instead of "<i>a</i><cite>b</cite><i>c</i>". -->
+ <li>If <var>node</var>'s [[parent]] is null, abort this algorithm.
+
<li>If <var>node</var> is an [[element]], [[text]], [[comment]], or
[[processinginstruction]] node, and is not an <span>unwrappable
element</span>:
<ol>
- <!-- Handle cases like bolding "bar" in "<i><b>Foo</b></i>bar".
+ <!-- Even if the style matches, we stick it in a preceding sibling if
+ possible. This ensures "a<cite>b</cite>c" -> "<i>a<cite>b</cite>c</i>"
+ instead of "<i>a</i><cite>b</cite><i>c</i>". While we're at it, we also
+ handle more elaborate cases like <b>foo</b>[bar]<b>baz</b> and even
+ <i><b>foo</b></i>[bar]<i><b>baz</b></i> (the latter becomes
+ <b><i>foo</i>bar<i>baz</i></b>).
+
Theoretically this algorithm could pointlessly reorganize the DOM in the
event of unreasonable style rules, but it's not a big enough deal for us to
- care, probably. -->
- <!-- This is probably more complicated than we want, given how likely this
- is to come up, so I've commented it out for now.
+ care, since the resulting style will still be right. -->
<li>Let <var>candidate</var> be <var>node</var>'s [[previoussibling]].
- <li>While <var>candidate</var> is a <span>simple styling element</span>,
- and <var>candidate</var> has exactly one [[child]], and that [[child]] is
- also a <span>simple styling element</span>, and <var>candidate</var>'s
+ <li>While <var>candidate</var> is a <span>styling element</span>, and
+ <var>candidate</var> has exactly one [[child]], and that [[child]] is also
+ a <span>styling element</span>, and <var>candidate</var> is not a
+ <span>simple styling element</span> or <var>candidate</var>'s
<span>specified style</span> for <var>property</var> is not <var>new
value</var>, set <var>candidate</var> to its [[child]].
<li>If <var>candidate</var> is a <span>simple styling element</span> whose
- <span>specified style</span> and computed style for <var>property</var> are
- both <var>new value</var>, and <var>candidate</var> is not the
- [[previoussibling]] of <var>node</var>:
+ <span>specified style</span> and <span>effective style</span> for
+ <var>property</var> are both <var>new value</var>, and <var>candidate</var>
+ is not the [[previoussibling]] of <var>node</var>:
<ol>
<li>While <var>candidate</var> has [[children]], append the first
@@ -622,27 +682,20 @@
<li>Append the [[previoussibling]] of <var>candidate</var> as the last
[[child]] of <var>candidate</var>.
</ol>
- -->
- <li>If <var>node</var>'s [[previoussibling]] is a <span>simple styling
- element</span> whose <span>specified style</span> and <span>effective
- style</span> for <var>property</var> are both <var>new value</var>, append
- <var>node</var> as the last [[child]] of its [[previoussibling]] and abort
- this algorithm.
-
- <!--
<li>Let <var>candidate</var> be <var>node</var>'s [[nextsibling]].
- <li>While <var>candidate</var> is a <span>simple styling element</span>,
- and <var>candidate</var> has exactly one [[child]], and that [[child]] is
- also a <span>simple styling element</span>, and <var>candidate</var>'s
+ <li>While <var>candidate</var> is a <span>styling element</span>, and
+ <var>candidate</var> has exactly one [[child]], and that [[child]] is also
+ a <span>styling element</span>, and <var>candidate</var> is not a
+ <span>simple styling element</span> or <var>candidate</var>'s
<span>specified style</span> for <var>property</var> is not <var>new
value</var>, set <var>candidate</var> to its [[child]].
<li>If <var>candidate</var> is a <span>simple styling element</span> whose
- <span>specified style</span> and computed style for <var>property</var> are
- both <var>new value</var>, and <var>candidate</var> is not the
- [[nextsibling]] of <var>node</var>:
+ <span>specified style</span> and <span>effective style</span> for
+ <var>property</var> are both <var>new value</var>, and <var>candidate</var>
+ is not the [[nextsibling]] of <var>node</var>:
<ol>
<li>While <var>candidate</var> has [[children]], append the first
@@ -655,13 +708,28 @@
<li>Append the [[nextsibling]] of <var>candidate</var> as the last
[[child]] of <var>candidate</var>.
</ol>
- -->
- <li>If <var>node</var>'s [[nextsibling]] is a <span>simple styling
- element</span> whose <span>specified style</span> and <span>effective
- style</span> for <var>property</var> are both <var>new value</var>, insert
- <var>node</var> as the first [[child]] of its [[nextsibling]] and abort
- this algorithm.
+ <li>Let <var>previous sibling</var> and <var>next sibling</var> be
+ <var>node</var>'s [[previoussibling]] and [[nextsibling]].
+
+ <li>If <var>previous sibling</var> is a <span>simple styling element</span>
+ whose <span>specified style</span> and <span>effective style</span> for
+ <var>property</var> are both <var>new value</var>, append <var>node</var>
+ as the last [[child]] of <var>previous sibling</var>.
+
+ <li>If <var>next sibling</var> is a <span>simple styling element</span>
+ whose <span>specified style</span> and <span>effective style</span> for
+ <var>property</var> are both <var>new value</var>:
+
+ <ol>
+ <li>If <var>node</var> is not a [[child]] of <var>previous sibling</var>,
+ insert <var>node</var> as the first [[child]] of <var>next sibling</var>.
+
+ <li>Otherwise, while <var>next sibling</var> has [[children]], append the
+ first [[child]] of <var>next sibling</var> as the last [[child]] of
+ <var>previous sibling</var>. Then remove <var>next sibling</var> from
+ its [[parent]].
+ </ol>
</ol>
<li>If the <span>effective style</span> of <var>property</var> is <var>new
@@ -689,20 +757,55 @@
<li>If the <span>effective style</span> of <var>property</var> is <var>new
value</var> on <var>node</var>, abort this algorithm.
- <li>If <var>property</var> is "font-weight" and <var>new value</var> is
- "bold", let <var>tag</var> be "b".
-
- <li>If <var>property</var> is "font-style" and <var>new value</var> is
- "italic", let <var>tag</var> be "i".
+ <li>Let <var>new parent</var> be null.
- <li>If <var>property</var> is "text-decoration" and <var>new value</var> is
- "underline", let <var>tag</var> be "u".
+ <li>If the <span>CSS styling flag</span> is false:
- <li>If <var>tag</var> is not set, let <var>tag</var> be "span".
+ <ol>
+ <li>If <var>property</var> is "font-weight" and <var>new value</var> is
+ "bold", let <var>new parent</var> be the result of calling <code
+ data-anolis-spec=domcore
+ title=dom-Document-createElement>createElement("b")</code> on the
+ [[ownerdocument]] of <var>node</var>.
- <li>Let <var>new parent</var> be the result of calling <code
- data-anolis-spec=domcore
- title=dom-Document-createElement>createElement(<var>tag</var>)</code> on the
+ <li>If <var>property</var> is "font-style" and <var>new value</var> is
+ "italic", let <var>new parent</var> be the result of calling <code
+ data-anolis-spec=domcore
+ title=dom-Document-createElement>createElement("i")</code> on the
+ [[ownerdocument]] of <var>node</var>.
+
+ <li>If <var>property</var> is "text-decoration" and <var>new value</var> is
+ "underline", let <var>new parent</var> be the result of calling <code
+ data-anolis-spec=domcore
+ title=dom-Document-createElement>createElement("u")</code> on the
+ [[ownerdocument]] of <var>node</var>.
+
+ <li>If <var>property</var> is "color", let <var>new parent</var> be the
+ result of calling <code data-anolis-spec=domcore
+ title=dom-Document-createElement>createElement("font")</code> on the
+ [[ownerdocument]] of <var>node</var>, then set the [[fontcolor]] attribute
+ of <var>new parent</var> to <var>new value</var>.
+
+ <p class=XXX>This can be wrong if, e.g., the color has an alpha channel.
+ We also need to specify exactly how it's serialized, since CSSOM doesn't
+ cover this. It might be best to always output simple colors.
+
+ <li>If <var>property</var> is "font-family", let <var>new parent</var> be
+ the result of calling <code data-anolis-spec=domcore
+ title=dom-Document-createElement>createElement("font")</code> on the
+ [[ownerdocument]] of <var>node</var>, then set the [[fontface]] attribute
+ of <var>new parent</var> to <var>new value</var>.
+
+ <li>If <var>property</var> is "font-size", let <var>new parent</var> be the
+ result of calling <code data-anolis-spec=domcore
+ title=dom-Document-createElement>createElement("font")</code> on the
+ [[ownerdocument]] of <var>node</var>, then set the [[fontsize]] attribute
+ of <var>new parent</var> to <var>new value</var>.
+ </ol>
+
+ <li>If <var>new parent</var> is null, let <var>new parent</var> be the result
+ of calling <code data-anolis-spec=domcore
+ title=dom-Document-createElement>createElement("span")</code> on the
[[ownerdocument]] of <var>node</var>.
<li>Insert <var>new parent</var> in <var>node</var>'s [[parent]] before
@@ -718,13 +821,25 @@
of <var>property</var> for <var>node</var> is not <var>new value</var>:
<ol>
- <li>Set the CSS property <var>property</var> of <var>node</var> to <var>new
- value</var>.
-
<li>Insert <var>node</var> into the [[parent]] of <var>new parent</var>
before <var>new parent</var>.
<li>Remove <var>new parent</var> from its [[parent]].
+
+ <li>If <var>new parent</var> is a [[span]], set the CSS property
+ <var>property</var> of <var>node</var> to <var>new value</var>.
+
+ <li>Otherwise:
+
+ <ol>
+ <li>Let <var>children</var> be all [[children]] of <var>node</var>,
+ omitting any that are [[element]]s whose <span>specified style</span> for
+ <var>property</var> is neither null nor equal to <var>new value</var>.
+
+ <li><span>Force the style</span> of each [[node]] in <var>children</var>,
+ with <var>property</var> and <var>new value</var> as in this invocation
+ of the algorithm.
+ </ol>
</ol>
</ol>
@@ -835,7 +950,7 @@
<li>Let <var>children</var> be the [[children]] of <var>node</var>.
- <li><span>Style</span> each member of [[children]].
+ <li><span>Style</span> each member of <var>children</var>.
<p class=note>Styling a node involves clearing its styles, which can remove
it from the tree. Implementers should be careful to compute the list of
@@ -1167,6 +1282,20 @@
<dd><p><strong>Value</strong>: Always the empty string.
+<dt><code title><dfn title=command-stylewithcss>styleWithCSS</dfn></code>
+
+<dd><p><strong>Action</strong>: Convert <var>value</var> to a boolean according
+to the algorithm in WebIDL, and set the <span>CSS styling flag</span> to the
+result.
+
+<p class=XXX>Properly cross-reference.
+
+<dd><p><strong>State</strong>: True if the <span>CSS styling flag</span> is
+true, otherwise false.
+
+<dd><p><strong>Value</strong>:
+
+
<dt><code title><dfn title=command-underline>underline</dfn></code>
<dd><p><strong>Action</strong>: <span>Decompose</span> the [[range]]. If the
@@ -1216,7 +1345,6 @@
style</span> either null or "underline" for text-decoration. Otherwise false.
<dd><p><strong>Value</strong>: Always the empty string.
-</dl>
<dt><code title><dfn title=command-unlink>unlink</dfn></code>
@@ -1266,6 +1394,24 @@
<dd><p><strong>Value</strong>: Always the empty string.
+<dt><code title><dfn title=command-usecss>useCSS</dfn></code>
+
+<dd><p><strong>Action</strong>: Convert <var>value</var> to a boolean according
+to the algorithm in WebIDL, and set the <span>CSS styling flag</span> to the
+negation of the result. Since the effect of this command is the opposite of
+what one would expect, user agents are encouraged to point authors to <code
+title=command-stylewithcss>styleWithCSS</code> when <code
+title=command-usecss>useCSS</code> is used, such as by logging a warning to an
+error console.
+
+<p class=XXX>Properly cross-reference.
+
+<dd><p><strong>State</strong>:
+
+<dd><p><strong>Value</strong>:
+</dl>
+
+
<h2 class=no-num id=references>References</h2><!--REFS-->
<p>All references are normative unless marked "Non-normative".</p>
<div id=anolis-references></div>