--- a/autoimplementation.html Tue Mar 15 22:39:50 2011 -0600
+++ b/autoimplementation.html Thu Mar 17 16:14:25 2011 -0600
@@ -1,7 +1,31 @@
<!doctype html>
-<table border=1>
- <tr><th>Input <th>Spec <th>Browser
-</table>
+<title>Auto-running execCommand() bold tests</title>
+<style>
+.yes { color: green }
+.no { color: red }
+b, strong { font-weight: bold }
+.bold { font-weight: bold }
+.notbold { font-weight: normal }
+td > div:first-child {
+ padding-bottom: 0.2em;
+ border-bottom: 1px solid black;
+}
+td > div:last-child {
+ padding-top: 0.2em;
+}
+</style>
+<p>Legend: {[ are the selection anchor, }] are the selection focus, {}
+represent an element boundary point, [] represent a text node boundary point.
+Syntax and some of the tests taken from <a
+href=http://www.browserscope.org/richtext2/test>Browserscope</a>.
+
+<p><label>Enter new test here: <input></label>
+<button onclick="addTest(document.querySelector('input').value)">Add test</button>
+
+<div>
+<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
+</div>
+
<script src=implementation.js></script>
<script>
// Note: this data format can only yield selections whose start and end are
@@ -26,37 +50,139 @@
'<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'
+ 'foo bar <b>baz [qoz</b> quz] sic',
+ '<b id=foo>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',
+ 'foo<span style="font-weight: 900">[bar]</span>baz',
+ 'foo<span style="font-weight: normal">[bar]</span>baz',
+ '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',
+ 'foo<span style="font-weight: 900">[bar</span>]baz',
+ 'foo<span style="font-weight: normal">[bar</span>]baz',
+ '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',
+ 'foo[<span style="font-weight: 900">bar]</span>baz',
+ 'foo[<span style="font-weight: normal">bar]</span>baz',
+ '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',
+ 'foo[<span style="font-weight: 900">bar</span>]baz',
+ 'foo[<span style="font-weight: normal">bar</span>]baz',
+ '<span style="font-weight: 100">foo[bar]baz</span>',
+ '<span style="font-weight: 400">foo[bar]baz</span>',
+ '<span style="font-weight: 700">foo[bar]baz</span>',
+ '<span style="font-weight: 900">foo[bar]baz</span>',
+ '<span style="font-weight: normal">foo[bar]baz</span>',
+ '{<span style="font-weight: 100">foobar]baz</span>',
+ '{<span style="font-weight: 400">foobar]baz</span>',
+ '{<span style="font-weight: 700">foobar]baz</span>',
+ '{<span style="font-weight: 900">foobar]baz</span>',
+ '{<span style="font-weight: normal">foobar]baz</span>',
+ '<span style="font-weight: 100">foo[barbaz</span>}',
+ '<span style="font-weight: 400">foo[barbaz</span>}',
+ '<span style="font-weight: 700">foo[barbaz</span>}',
+ '<span style="font-weight: 900">foo[barbaz</span>}',
+ '<span style="font-weight: normal">foo[barbaz</span>}',
+ '<h3>Foo[bar]baz</h3>',
+ '{<h3>Foobar]baz</h3>',
+ '<h3>Foo[barbaz</h3>}',
+ '<h3>[Foobarbaz]</h3>',
+ '{<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>',
+ '{<p><p> <p>Foo</p>}',
+ '[Foo<span class=notbold>bar</span>baz]',
];
-var table = document.querySelector("table");
-table.contentEditable = "true";
for (var i = 0; i < tests.length; i++) {
+ addTest(tests[i]);
+}
+
+function addTest(test) {
+ document.querySelector("div").contentEditable = "true";
+ var table = document.querySelector("table");
+
var tr = document.createElement("tr");
- table.appendChild(tr);
+ // Insert at the top, because Chrome debugger doesn't let you scroll down
+ // while you're stopped at a breakpoint . . .
+ //if (table.childNodes.length == 1) {
+ table.appendChild(tr);
+ //} else {
+ // table.insertBefore(tr, table.childNodes[1]);
+ //}
var inputCell = document.createElement("td");
- inputCell.textContent = tests[i];
+ inputCell.innerHTML = test;
+ inputCell.innerHTML = "<div>" + inputCell.innerHTML + "</div><div>" + inputCell.innerHTML.replace(/\&/g, "&").replace(/</g, "<") + "</div>";
tr.appendChild(inputCell);
var specCell = document.createElement("td");
- specCell.innerHTML = tests[i];
+ specCell.innerHTML = test;
tr.appendChild(specCell);
- selectBrackets(specCell);
- myExecCommand("bold");
- specCell.textContent = specCell.innerHTML;
+ try {
+ selectBrackets(specCell);
+ myExecCommand("bold");
+ specCell.innerHTML = "<div>" + specCell.innerHTML + "</div><div>" + specCell.innerHTML.replace(/\&/g, "&").replace(/</g, "<") + "</div>";
+ } catch (e) {
+ specCell.textContent = "Exception: " + e;
+ }
var browserCell = document.createElement("td");
- browserCell.innerHTML = tests[i];
+ browserCell.innerHTML = test;
tr.appendChild(browserCell);
- selectBrackets(browserCell);
- document.execCommand("bold", null, false);
- browserCell.textContent = browserCell.innerHTML;
+ try {
+ selectBrackets(browserCell);
+ try {
+ document.execCommand("styleWithCSS", null, false);
+ } catch (e) {
+ // IE, we don't care
+ }
+ document.execCommand("bold", null, false);
+ browserCell.innerHTML = "<div>" + browserCell.innerHTML + "</div><div>" + browserCell.innerHTML.replace(/\&/g, "&").replace(/</g, "<") + "</div>";
+ } catch (e) {
+ browserCell.textContent = "Exception: " + e;
+ }
+
+ var sameCell = document.createElement("td");
+ // Ad hoc normalization to avoid basically spurious mismatches
+ var normalizedSpecCell = specCell.lastChild.textContent
+ .replace(/;? ?"/g, '"');
+ var normalizedBrowserCell = browserCell.lastChild.textContent
+ .replace(/;? ?"/g, '"')
+ .replace(/ class="Apple-style-span"/g, "");
+ if (normalizedSpecCell == normalizedBrowserCell) {
+ sameCell.className = "yes";
+ sameCell.innerHTML = "✓";
+ } else {
+ sameCell.className = "no";
+ sameCell.innerHTML = "✗";
+ }
+ tr.appendChild(sameCell);
+
+ getSelection().removeAllRanges();
+ document.querySelector("div").contentEditable = "inherit";
}
-getSelection().removeAllRanges();
-table.contentEditable = false;
function selectBrackets(node) {
+ if (node.textContent.replace(/[^{[]/g, "").length != 1) {
+ throw "Need one [ or {, found " + node.textContent.replace(/[^{[]/g, "").length;
+ }
+
+ if (node.textContent.replace(/[^}\]]/g, "").length != 1) {
+ throw "Need one ] or }, found " + node.textContent.replace(/[^}\]]/g, "").length;
+ }
+
var startNode, startOffset, endNode, endOffset;
var cur = node;
@@ -123,7 +249,18 @@
}
}
- if ("extend" in getSelection()) {
+ if (navigator.userAgent.indexOf("Opera") != -1) {
+ // Yes, browser sniffing is evil, but I can't be bothered to debug
+ // Opera.
+ var range = document.createRange();
+ range.setStart(startNode, startOffset);
+ range.setEnd(endNode, endOffset);
+ if (range.collapsed) {
+ range.setEnd(startNode, startOffset);
+ }
+ getSelection().removeAllRanges();
+ getSelection().addRange(range);
+ } else if ("extend" in getSelection()) {
// WebKit behaves unreasonably for collapse(), so do that manually.
var range = document.createRange();
range.setStart(startNode, startOffset);
@@ -132,16 +269,22 @@
getSelection().extend(endNode, endOffset);
} else {
// IE9. Selections have no direction, so we just make the selection
- // always forwards;
- var range = document.createRange();
+ // always forwards.
+ var range;
+ if (getSelection().rangeCount) {
+ range = getSelection().getRangeAt(0);
+ } else {
+ range = document.createRange();
+ }
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
if (range.collapsed) {
// Phooey, we got them backwards.
range.setEnd(startNode, startOffset);
}
- getSelection().removeAllRanges();
- getSelection().addRange(range);
+ if (!getSelection().rangeCount) {
+ getSelection().addRange(range);
+ }
}
}
</script>
--- a/editcommands.html Tue Mar 15 22:39:50 2011 -0600
+++ b/editcommands.html Thu Mar 17 16:14:25 2011 -0600
@@ -22,11 +22,12 @@
white-space: pre-wrap;
}
div.note > p:first-child::before { content: 'Note: '; }
+ div + * > li { margin: 1em 0 }
</style>
<body class=draft>
<div class=head id=head>
<h1>HTML Editing Commands</h1>
-<h2 class="no-num no-toc" id=work-in-progress-—-last-update-15-march-2011>Work in Progress — Last Update 15 March 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-—-last-update-17-march-2011>Work in Progress — Last Update 17 March 2011</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <ayg+spec@aryeh.name>
@@ -56,15 +57,12 @@
<li><a href=#introduction><span class=secno>1 </span>Introduction</a></li>
<li><a href=#issues><span class=secno>2 </span>Issues</a></li>
<li><a href=#definitions><span class=secno>3 </span>Definitions</a></li>
- <li><a href=#decomposing-a-range-into-nodes><span class=secno>4 </span>Decomposing a Range into Nodes</a></li>
+ <li><a href=#decomposing-a-range-into-nodes><span class=secno>4 </span>Decomposing a range into nodes</a></li>
<li><a href="#clearing-an-element's-styles"><span class=secno>5 </span>Clearing an element's styles</a></li>
- <li><a href="#recursively-clearing-an-element's-styles"><span class=secno>6 </span>Recursively clearing an element's styles</a></li>
- <li><a href=#styling-a-node><span class=secno>7 </span>Styling a Node</a></li>
- <li><a href=#recursively-styling-a-node><span class=secno>8 </span>Recursively styling a Node</a></li>
- <li><a href=#styling-a-range><span class=secno>9 </span>Styling a Range</a></li>
- <li><a href=#unstyling-a-node><span class=secno>10 </span>Unstyling a Node</a></li>
- <li><a href=#unstyling-a-range><span class=secno>11 </span>Unstyling a Range</a></li>
- <li><a href=#commands><span class=secno>12 </span>Commands</a></li>
+ <li><a href=#pushing-down-styles><span class=secno>6 </span>Pushing down styles</a></li>
+ <li><a href=#forcing-the-style-of-a-node><span class=secno>7 </span>Forcing the style of a node</a></li>
+ <li><a href=#styling-a-node><span class=secno>8 </span>Styling a node</a></li>
+ <li><a href=#commands><span class=secno>9 </span>Commands</a></li>
<li><a class=no-num href=#references>References</a></li>
<li><a class=no-num href=#acknowledgements>Acknowledgements</a></ol>
<!--end-toc-->
@@ -82,6 +80,57 @@
major preexisting rendering engines are known not to match it, the reasoning is
included in HTML comments so as not to distract the reader.
+<p>The principles I've used for writing this specification so far are:
+
+<ul>
+ <li>If all browsers that implement a particular feature agree on some detail
+ of how it works, match them unless there's very good reason not to. When
+ it's not clear what behavior is best, try to follow the implementations with
+ the most market share. But if one browser's behavior is clearly better than
+ the others', go with the better behavior.
+
+ <li>If a command is issued to format some text in a particular way, we will
+ format the text that way no matter what. If the user clicks the "bold"
+ button, they don't care that the text didn't become bold because of an
+ external CSS rule or for any other reason, they only care that it didn't
+ work. The only exception (beyond where it's simply impossible, like
+ propagated text-decorations we can't remove) is that we don't try to override
+ !important rules from external stylesheets, although we also don't go out of
+ our way to respect them.
+
+ <li>When we're given a presentational command like "bold", don't modify
+ anything other than presentational markup related to that command. If an
+ element has non-presentational attributes like id or class, don't split it up
+ or remove it or anything. At most convert it to a span, if it's some type of
+ presentational element (where "presentational" here really means "browsers
+ produce it in response to execCommand() so we need to treat it as
+ presentational", so it includes things like <a href=http://www.whatwg.org/html/#the-strong-element><code class=external data-anolis-spec=html title="the strong element">strong</code></a> and <a href=http://www.whatwg.org/html/#the-em-element><code class=external data-anolis-spec=html title="the em element">em</code></a>).
+
+ <li>Don't interfere with more markup than necessary. If the user modifies
+ only a small run of text, don't go around simplifying ancestors or siblings
+ or whatever unless it's necessary to produce simpler markup in the place that
+ was actually modified.
+
+ <li>But if we are already changing around something's style, convert existing
+ styles to the preferred format. For instance, we use <a href=http://www.whatwg.org/html/#the-b-element><code class=external data-anolis-spec=html title="the b element">b</code></a> for bold, and
+ convert <a href=http://www.whatwg.org/html/#the-strong-element><code class=external data-anolis-spec=html title="the strong element">strong</code></a> and <<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-style-attribute><code class=external data-anolis-spec=html title="the style attribute">style</code></a>="font-weight: bold"> if we
+ happen to be modifying that node anyway.
+
+ <li>Don't make the document less conforming than it originally was. If we
+ happen to make it more conforming, good, although we don't have to go out of
+ our way to do that. (In the future, I'll add a mode that supports using
+ obsolete presentational elements instead of CSS for the sake of e-mail
+ clients and such, and this rule will be bent in that mode.)
+
+ <li>Keep the markup as concise as possible. (I've received feedback that
+ this is very important to authors.) Ideally, the markup should look as
+ simple and neat as what a human would have produced by hand-editing. We do
+ complicated manipulation to pull styles down from ancestors rather than
+ having to use inline CSS, and make sure to tidy up any styles on elements
+ that we happen to be modifying anyway. Previous principles take precedence
+ over this one, however.
+</ul>
+
<h2 id=issues><span class=secno>2 </span>Issues</h2>
@@ -127,27 +176,15 @@
<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-namespace title=concept-attr-namespace>namespace</a> is
the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#html-namespace>HTML namespace</a>.
-<p>The <dfn id=beginning-element>beginning element</dfn> of a <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> is returned by the following
-algorithm:
-
-<ol>
- <li>If the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a> of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> is 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 the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>
- <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a> of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> is not equal to the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of its
- <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>, let <var title="">first node</var> be the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>'s
- <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>.
+<p>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> is <dfn id=effectively-contained>effectively contained</dfn> in a <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> if either it
+is <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>; or it is the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a>
+<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>, it is 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> node, and its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> is different from the
+<a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a>; or it is the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a>
+<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>, it is 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> node, and the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a>
+<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a> is not 0.
- <li>Otherwise, let <var title="">first node</var> be the first <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
- <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a> that is <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>, if there is any.
-
- <li>If <var title="">first node</var> is defined and 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>, return
- <var title="">first node</var>.
-
- <li>Otherwise, if <var title="">first node</var> is defined and its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is an
- <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>, return <var title="">first 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>.
-
- <li>Return null.
-</ol>
+<p class=note>A node is <a href=#effectively-contained>effectively contained</a> in a range if and
+only if it would be <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> after the range is <a href=#decompose title=decompose>decomposed</a>.
<p>The <dfn id=active-range>active range</dfn> of a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#document><code class=external data-anolis-spec=domcore>Document</code></a> is the value returned by the
following algorithm:
@@ -171,90 +208,28 @@
<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.
</ol>
-<p>Given a CSS property name <var title="">property name</var>, an (optional) value
-<var title="">property value</var> for that property, and a possibly empty list of
-strings <var title="">tag list</var>, 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> is a <dfn id=potentially-relevant-styling-element>potentially relevant styling
-element</dfn> if it is an <a href=#html-element>HTML element</a> and one of the following
-holds:
-
-<ul>
- <li>Its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> is in <var title="">tag list</var> and it has no attributes.
-
- <li>Its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> is in <var title="">tag list</var> or is "span" or is "font",
- and it has exactly one attribute, and that attribute is an <a href=#html-attribute>HTML
- attribute</a> with <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-local-name title=concept-attr-local-name>local name</a> "style", and that attribute sets
- exactly one CSS property, and that property is <var title="">property name</var>, and
- either <var title="">property value</var> is undefined or the value the attribute sets
- the property to is <var title="">property value</var>.
-
- <li>Its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> is "font", and it has exactly one attribute, and that
- attribute is 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>
- attribute, and either <var title="">property value</var> is undefined or the effect of
- the attribute is to hint that the CSS color attribute be set to <var title="">property
- value</var>, and <var title="">property name</var> is "color".
-
- <li>Its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> is "font", and it has exactly one attribute, and that
- attribute is 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>
- attribute, and either <var title="">property value</var> is undefined or the effect of
- the attribute is to hint that the CSS font-family attribute be set to
- <var title="">property value</var>, and <var title="">property name</var> is "font-family".
+<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).
- <li>Its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> is "font", and it has exactly one attribute, and that
- attribute is a <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, and either <var title="">property value</var> is undefined or the effect of
- the attribute is to hint that the CSS font-size attribute be set to
- <var title="">property value</var>, and <var title="">property name</var> is "font-size".
-
- <!-- Should we bother handling <font color=red style=color:red>? Let's not.
- -->
-</ul>
-
-<p>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> is a <dfn id=relevant-styling-element>relevant styling element</dfn> if it is a
-<a href=#potentially-relevant-styling-element>potentially relevant styling element</a>, and its CSS property
-<var title="">property name</var> computes to <var title="">property value</var> (which cannot be
-undefined).
-
-<div class=note>
-<p>If <var title="">property name</var> is "font-weight", <var title="">property value</var> is
-"bold", and <var title="">tag list</var> contains "b", an example of a <a href=#potentially-relevant-styling-element>potentially
-relevant styling element</a> that is not actually <a href=#relevant-styling-element title="relevant
-styling element">relevant</a> is
-
-</p><xmp><p style="font-weight: 100"><b>Foo</b></p></xmp>
-
-<p>Since <a href=http://www.whatwg.org/html/#the-b-element><code class=external data-anolis-spec=html title="the b element">b</code></a>'s default
-font-weight is "bolder", the computed font-weight will most likely end up being
-"normal" or lighter.
-</div>
-
-<p>A <dfn id=phrasing-element>phrasing element</dfn> is either an <a href=#html-element>HTML element</a> that is
-categorized as <a class=external data-anolis-spec=html href=http://www.whatwg.org/html/#phrasing-content>phrasing content</a>, or a <a class=external data-anolis-spec=html href=http://www.whatwg.org/html/#non-conforming-element title="non-conforming element">non-conforming</a> <a href=#html-element>HTML element</a>
-(which thus has no categories), or 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> that is not an <a href=#html-element>HTML
-element</a>.
-
-<p class=XXX>We should allow unrecognized HTML elements too.
-
-<p>The <dfn id=specified-style>specified style</dfn> of 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> for a given <var title="">property
-name</var> is returned by the following algorithm, which will return either a
-CSS value or null:
+<p>The <dfn id=specified-style>specified style</dfn> of 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> for a given
+<var title="">property</var> is returned by the following algorithm, which will return
+either a CSS value or null:
<ol>
<li>If the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> has a <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 set, and that attribute has
- the effect of setting <var title="">property name</var>, return the value that it sets
- <var title="">property name</var> to.
+ the effect of setting <var title="">property</var>, return the value that it sets
+ <var title="">property</var> to.
<li>If the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> is a <a href=http://www.whatwg.org/html/#font><code class=external data-anolis-spec=html>font</code></a> element
that has an attribute whose effect is to create a <a class=external data-anolis-spec=html href=http://www.whatwg.org/html/#presentational-hints title="presentational hints">presentational hint</a> for
- <var title="">property name</var>, return the value that the hint sets <var title="">property
- name</var> to.
+ <var title="">property</var>, return the value that the hint sets <var title="">property</var>
+ to.
- <li>If the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> is in the following list, and <var title="">property name</var>
- is equal to the CSS property name listed for it, return the string listed for
+ <li>If the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> is in the following list, and <var title="">property</var> is
+ equal to the CSS property name listed for it, return the string listed for
it.
- <p class=XXX>Add any other elements that can be output by the style/unstyle
- algorithms, or existing browser implementations of execCommand().
-
<dl class=switch>
<dt><a href=http://www.whatwg.org/html/#the-b-element><code class=external data-anolis-spec=html title="the b element">b</code></a>
<dt><a href=http://www.whatwg.org/html/#the-strong-element><code class=external data-anolis-spec=html title="the strong element">strong</code></a>
@@ -271,6 +246,38 @@
<li>Return null.
</ol>
+<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:
+
+<ol>
+ <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>, <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/#font><code class=external data-anolis-spec=html title=font>font</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.
+
+ <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>, <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/#font><code class=external data-anolis-spec=html title=font>font</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 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
+ <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 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 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/#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>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
though the method had actually been called from JavaScript. In particular,
@@ -284,8 +291,8 @@
sequentially in the list's order.
-<h2 id=decomposing-a-range-into-nodes><span class=secno>4 </span>Decomposing a Range into Nodes</h2>
-<p>When a user agent is to <dfn id=decompose-a-range>decompose a <code class=external data-anolis-spec=domrange>Range</code></dfn> <var title="">range</var>,
+<h2 id=decomposing-a-range-into-nodes><span class=secno>4 </span>Decomposing a range into nodes</h2>
+<p>When a user agent is to <dfn id=decompose>decompose</dfn> a <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> <var title="">range</var>,
it must run the following steps.
<ol>
@@ -340,9 +347,25 @@
<var title="">start offset</var>) and its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> to (<var title="">end node</var>,
<var title="">end offset</var>).
- <li>Return a list consisting of every <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in
- <var title="">range</var> in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>, omitting any whose <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 also
- <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">range</var>.
+ <!-- Now we want to make sure our range contains as many nodes as possible,
+ such as by changing <tag>[foo]</tag> to {<tag>foo</tag>}. -->
+ <li>Let <var title="">cloned range</var> be the result of calling <a href=http://html5.org/specs/dom-range.html#dom-range-clonerange><code class=external data-anolis-spec=domrange title=dom-Range-cloneRange>cloneRange()</code></a> on
+ <var title="">range</var>.
+
+ <li>While the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a> of <var title="">cloned range</var> is 0,
+ and 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="">cloned range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a> is
+ not null, set the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> of <var title="">cloned range</var> to (<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
+ <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>, <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> of <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-start title=concept-range-start>start</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>).
+
+ <li>While the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-offset title=concept-boundary-point-offset>offset</a> of <var title="">cloned range</var> equals the
+ <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a> of its <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>, and 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="">clone range</var>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a> is not null, set the
+ <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> of <var title="">cloned range</var> to (<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 <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a>
+ <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>, 1 + <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-indexof title=concept-indexof>index</a> of <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range-end title=concept-range-end>end</a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-boundary-point-node title=concept-boundary-point-node>node</a>).
+
+ <li>Return a list consisting of every <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">cloned
+ range</var> in <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#tree-order>tree order</a>, omitting any whose <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 also
+ <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">cloned range</var>.
</ol>
@@ -350,27 +373,22 @@
<p>When a user agent is to <dfn id=clear-styles>clear styles</dfn> on an element, it must run
the following steps:
-<div class=note>
-<p>Clearing styles (<a href=#recursively-clear-styles title="recursively clear styles">recursively</a>
-or not) can remove it from its parent and put other nodes in its place. When
-implementations do something like clear style on all children of an element,
-they should take care not to assume that the set of children won't change as
-they're unstyled. If the element is removed, the algorithm will return the
-list of nodes inserted in its place.
+<p class=note>Clearing styles can remove it from its parent and put other nodes
+in its place. When implementations do something like clear style on all
+children of an element, they should take care not to assume that the set of
+children won't change as they're unstyled. If the element is removed, the
+algorithm will return the list of nodes inserted in its place.
-<p>Clearing styles only removes inline styles from the element. It doesn't
-ensure that the element isn't inheriting styles from an ancestor (or a style
-rule). For that, one must <a href=#unstyle-a-node>unstyle a node</a>.
-</div>
+<p class=XXX>This should probably convert, e.g., <font color=red id=foo>
+into <span id=foo> instead of <font id=foo>.
<ol>
<li>Let <var title="">element</var> be the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> to be unstyled.
- <li>Let <var title="">property name</var> and <var title="">tag list</var> be as
- in the invoking algorithm.
+ <li>Let <var title="">property</var> be as in the invoking algorithm.
- <li>If <var title="">element</var> is a <a href=#potentially-relevant-styling-element>potentially relevant styling
- element</a>:
+ <li>If <var title="">element</var> is a <a href=#simple-styling-element>simple styling element</a> and its
+ <a href=#specified-style>specified style</a> for <var title="">property</var> is not null:
<ol>
<li>Let <var title="">children</var> be an empty list of <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a>s.
@@ -386,31 +404,31 @@
<var title="">element</var>.
</ol>
- <li>Remove <var title="">element</var>.
+ <li>Remove <var title="">element</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>Return <var title="">children</var>.
</ol>
- <li>Unset the CSS property <var title="">property name</var> of <var title="">element</var>.
+ <li>Unset the CSS property <var title="">property</var> of <var title="">element</var>.
<li>If <var title="">element</var> is a <a href=http://www.whatwg.org/html/#font><code class=external data-anolis-spec=html>font</code></a>
element:
<ol>
- <li>If <var title="">property name</var> is "color", unset <var title="">element</var>'s
+ <li>If <var title="">property</var> is "color", unset <var title="">element</var>'s
<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, if
set.
- <li>If <var title="">property name</var> is "font-family", unset
+ <li>If <var title="">property</var> is "font-family", unset
<var title="">element</var>'s <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, if set.
- <li>If <var title="">property name</var> is "font-size", unset <var title="">element</var>'s
+ <li>If <var title="">property</var> is "font-size", unset <var title="">element</var>'s
<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, if
set.
</ol>
- <li>If <var title="">element</var> is not an <a href=#html-element>HTML element</a> or its
- <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-element-local-name title=concept-element-local-name>local name</a> is not in <var title="">tag list</var>, return the empty list.
+ <li>If <var title="">element</var>'s <var title="">specified style</var> 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. -->
@@ -424,190 +442,49 @@
<li>While <var title="">element</var> has children, append its first child
as the last child of <var title="">new element</var>.
- <li>Remove <var title="">element</var>.
+ <li>Remove <var title="">element</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>Return the one-<a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> list consisting of <var title="">new element</var>.
</ol>
-<h2 id="recursively-clearing-an-element's-styles"><span class=secno>6 </span>Recursively clearing an element's styles</h2>
-<p>When a user agent is to <dfn id=recursively-clear-styles>recursively clear styles</dfn> on an element,
-it must run the following steps:
-
-<ol>
- <li>Let <var title="">element</var> be the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> to be unstyled.
-
- <li>Let <var title="">property name</var> and <var title="">tag list</var> be as
- in the invoking algorithm.
-
- <li>Let <var title="">element children</var> be the <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> children of
- <var title="">element</var>.
-
- <li><a href=#recursively-clear-styles>Recursively clear styles</a> on each <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> in <var title="">element
- children</var>.
-
- <li><a href=#clear-styles>Clear styles</a> on <var title="">element</var>, and return the resulting
- list.
-</ol>
-
-
-<h2 id=styling-a-node><span class=secno>7 </span>Styling a Node</h2>
-<p>When a user agent is to <dfn id=style-a-node>style a <code class=external data-anolis-spec=domcore>Node</code></dfn> <var title="">node</var>, it must
-run the following steps. There are three inputs: a CSS property name
-<var title="">property name</var>, a new value <var title="">property value</var>, and a possibly
-empty list of strings <var title="">tag list</var>.
-
-<p class=note>This algorithm applies the given style to the node itself, but
-doesn't interfere with conflicting styles on its descendants. <a href=#recursively-style-a-node title="recursively style a node">Recursive styling</a> removes conflicting
-styles from descendants first.
+<h2 id=pushing-down-styles><span class=secno>6 </span>Pushing down styles</h2>
+<p>When a user agent is to <dfn id=push-down-styles>push down styles</dfn> to 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>, given a CSS property name <var title="">property</var> and a new value
+<var title="">new value</var>, it must run the following steps:
<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 null, or if <var title="">node</var> 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>, <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, abort
- this algorithm. <!-- XXX: What to do here? -->
-
- <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>:
-
- <ol>
- <li><a href=#clear-styles>Clear styles</a> on <var title="">node</var>, and let <var title="">new
- nodes</var> be the result.
-
- <li>For each <var title="">new node</var> in <var title="">new nodes</var>, <a href=#style-a-node title="style a node">style <var title="">new node</var></a>, with the same inputs
- as this invocation of the algorithm.
-
- <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.
- </ol>
-
- <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> but not a <a href=#phrasing-element>phrasing
- element</a>:
+ <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. -->
- <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 name</var> is neither null nor equal to <var title="">property
- value</var>.
-
- <li><a href=#style-a-node title="style a node">Style</a> 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>.
-
- <li>Abort this algorithm.
- </ol>
+ <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> and <var title="">property</var> computes to
+ <var title="">new value</var> on <var title="">node</var>, abort this algorithm.
- <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=#relevant-styling-element>relevant styling
- element</a>, 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>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=#relevant-styling-element>relevant styling
- element</a>, 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>If <var title="">node</var> is 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>, abort
- this algorithm. <!-- There's no point in making a new element in this case.
- -->
-
- <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> and the computed style of
- <var title="">property name</var> for it is <var title="">property value</var>, abort this
+ <li>If <var title="">node</var> 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> and <var title="">property</var> computes
+ to <var title="">new value</var> on <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>, abort this
algorithm.
- <li>If <var title="">node</var> is 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> node and the computed style of
- <var title="">property name</var> for its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> is <var title="">property value</var>,
- abort this algorithm.
-
- <li>Let <var title="">tag</var> be the first string in <var title="">tag list</var>, if that is
- not empty, or "span" if it is empty.
-
- <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
- <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
- <var title="">node</var>.
-
- <li>If the computed value of <var title="">property name</var> for <var title="">new
- parent</var> is not <var title="">property value</var>, set the CSS property
- <var title="">property name</var> of <var title="">new parent</var> to <var title="">property
- value</var>.
-
- <li>Append <var title="">node</var> to <var title="">new parent</var> as its 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>.
-</ol>
-
-
-<h2 id=recursively-styling-a-node><span class=secno>8 </span>Recursively styling a Node</h2>
-<p>When a user agent is to <dfn id=recursively-style-a-node>recursively style a <code class=external data-anolis-spec=domcore>Node</code></dfn>
-<var title="">node</var>, it must run the following steps. There are three inputs: a
-CSS property name <var title="">property name</var>, a new value <var title="">property
-value</var>, and a possibly empty list of strings <var title="">tag list</var>.
-
-<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 null, or if <var title="">node</var> 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>, <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, abort
- this algorithm. <!-- XXX: What to do here? -->
-
- <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>:
-
- <ol>
- <li><a href=#recursively-clear-styles>Recursively clear styles</a> on <var title="">node</var>, and let
- <var title="">new nodes</var> be the result.
-
- <li>For each <var title="">new node</var> in <var title="">new nodes</var>, <a href=#recursively-style-a-node title="recursively style a node">recursively style <var title="">new
- node</var></a>, with the same inputs as this invocation of the
- algorithm.
-
- <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.
- </ol>
-
- <li><a href=#style-a-node title="style a node">Style</a> <var title="">node</var>.
-</ol>
-
-
-<h2 id=styling-a-range><span class=secno>9 </span>Styling a Range</h2>
-<p>When a user agent is to <dfn id=style-a-range>style a <code class=external data-anolis-spec=domrange>Range</code></dfn>, it must <a href=#decompose-a-range title="decompose a range">decompose</a> the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>, then <a href=#recursively-style-a-node title="recursively style a node">recursively style</a> 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 the
-returned list.
-
-
-<h2 id=unstyling-a-node><span class=secno>10 </span>Unstyling a Node</h2>
-<p>When a user agent is to <dfn id=unstyle-a-node>unstyle a <code class=external data-anolis-spec=domcore>Node</code></dfn> <var title="">node</var>, it
-must run the following steps. There are three inputs: a CSS property name
-<var title="">property name</var>, a new value <var title="">new value</var>, and a possibly
-empty list of strings <var title="">tag list</var>.
-
-<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 null, or if <var title="">node</var> 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> or <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node, abort this algorithm. <!-- XXX: What to do
- here? We want to ignore comments and PIs, but we might want to support
- detached elements, documents, document fragments, . . . -->
-
- <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>:
-
- <ol>
- <li><a href=#recursively-clear-styles>Recursively clear styles</a> on <var title="">node</var>, and let
- <var title="">new nodes</var> be the result.
-
- <li>For each <var title="">new node</var> in <var title="">new nodes</var>, <a href=#unstyle-a-node title="unstyle a node">unstyle <var title="">new node</var></a>, with the same
- inputs as this invocation of the algorithm.
-
- <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.
- </ol>
-
- <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>, let <var title="">current value</var> equal
- the computed value of <var title="">property name</var> on <var title="">node</var>.
- Otherwise, let <var title="">current value</var> equal the computed value of
- <var title="">property name</var> on <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>.
-
- <li>If <var title="">current value</var> equals <var title="">new value</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>.
<li>Let <var title="">ancestor list</var> be a list of <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a>s, initially empty.
- <li>Let <var title="">current ancestor</var> equal <var title="">node</var>.
+ <li>While <var title="">current ancestor</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> and
+ <var title="">property</var> does not compute 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>While <var title="">current ancestor</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 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>, 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>, then append it to
- <var title="">ancestor list</var>.
-
- <li>While <var title="">ancestor list</var> is not empty, and the last member of
- <var title="">ancestor list</var> has <a href=#specified-style>specified style</a> for <var title="">property
- name</var> equal to <var title="">new value</var> or null, remove the last member from
- <var title="">ancestor list</var>.
+ <!-- We can only remove specified styles, so if the style isn't specified,
+ give up. -->
+ <li>If <var title="">ancestor list</var> is not empty, and the <a href=#specified-style>specified
+ style</a> of <var title="">property</var> on the last member of <var title="">ancestor
+ list</var> is null, abort this algorithm.
+
+ <!-- If we go all the way up to the root and still don't have the desired
+ style, pushing down styles is pointless. It will create extra markup for no
+ purpose. -->
+ <li>If <var title="">ancestor list</var> is not empty, and 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> 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.
<li>While <var title="">ancestor list</var> is not empty:
@@ -618,7 +495,7 @@
<li>Remove the last member from <var title="">ancestor list</var>.
<li>Let <var title="">propagated value</var> be the <a href=#specified-style>specified style</a> of
- <var title="">current ancestor</var> for <var title="">property name</var>.
+ <var title="">current ancestor</var> for <var title="">property</var>.
<li>If <var title="">propagated value</var> is null, continue this loop from the
beginning.
@@ -635,53 +512,222 @@
<var title="">child</var>.
<li>If <var title="">child</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> whose <a href=#specified-style>specified
- style</a> for <var title="">property name</var> is neither null nor equal to
+ style</a> for <var title="">property</var> is neither null nor equal to
<var title="">propagated value</var>, continue with the next <var title="">child</var>.
<li>If <var title="">child</var> is the last member of <var title="">ancestor list</var>,
- set <var title="">child</var>'s CSS property <var title="">property name</var> to
+ set <var title="">child</var>'s CSS property <var title="">property</var> to
<var title="">propagated value</var> and continue with the next <var title="">child</var>.
<p class=note>This style will be removed on the next loop iteration and
distributed to its children.
- <li><a href=#style-a-node title="style a node">Style</a> <var title="">child</var>, with
- <var title="">property name</var> and <var title="">tag list</var> as in this algorithm,
- and <var title="">property value</var> equal to <var title="">propagated value</var>.
+ <li><a href=#force-the-style>Force the style</a> of <var title="">child</var>, with
+ <var title="">property</var> as in this algorithm and <var title="">new value</var> equal
+ to <var title="">propagated value</var>.
</ol>
</ol>
-
- <!-- We might have a rule inherited from someplace where we can't remove it,
- or maybe even a rule in a stylesheet (although that case is pathological and
- we generally ignore it) -->
- <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> and <var title="">property name</var> does
- not compute to <var title="">new value</var> on it, set <var title="">property name</var> to
- <var title="">new value</var> on it.
-
- <li>If <var title="">node</var> is 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> node and <var title="">property name</var> does
- not compute to <var title="">new value</var> on its <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a>:
-
- <ol>
- <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("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>Set <var title="">property name</var> to <var title="">new value</var> on <var title="">new
- parent</var>.
-
- <li>Insert <var title="">new parent</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>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="">new parent</var>.
- </ol>
</ol>
-<h2 id=unstyling-a-range><span class=secno>11 </span>Unstyling a Range</h2>
-<p>When a user agent is to <dfn id=unstyle-a-range>unstyle a <code class=external data-anolis-spec=domrange>Range</code></dfn> <var title="">range</var>, it
-must <a href=#decompose-a-range title="decompose a range">decompose</a> the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>, then <a href=#unstyle-a-node title="unstyle a node">unstyle</a> 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 the returned list.
+<h2 id=forcing-the-style-of-a-node><span class=secno>7 </span>Forcing the style of a node</h2>
+<p>When a user agent is to <dfn id=force-the-style>force the 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>, given a CSS property name <var title="">property</var> and a new value
+<var title="">new value</var>, it must run the following steps.
+
+<p class=note>This algorithm checks if the node has the desired style, and if
+not, it wraps the node (or, if that's not possible, its descendants) in a
+<a href=#simple-styling-element>simple styling element</a>. This is only used as a last resort after
+<a href=#clear-styles title="clear styles">clearing styles</a> and <a href=#push-down-styles title="push down
+styles">pushing down styles</a> don't work to achieve the desired style.
+After forcing the style, descendants might still have different style.
+
+<ol>
+ <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> and <var title="">property</var> computes 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=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>, <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
+ 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>, and <var title="">property</var> computes to <var title="">new value</var> on
+ <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>, abort this algorithm.
+
+ <li>If <var title="">node</var> is an <a href=#unwrappable-element>unwrappable element</a>:
+
+ <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.
+
+ <li>Abort this algorithm.
+ </ol>
+
+ <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 computed style 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>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 computed style 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.
+
+ <!-- At this point we have to make a new element as a wrapper. This isn't
+ worth the effort for comments or PIs, so abort in that case. -->
+ <li>If <var title="">node</var> is 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>, 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> and <var title="">property</var> computes 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=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a>, <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
+ 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>, and <var title="">property</var> computes to <var title="">new value</var> on
+ <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>, 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>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 <var title="">tag</var> is not set, let <var title="">tag</var> be "span".
+
+ <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
+ <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
+ <var title="">node</var>.
+
+ <li>If the computed value of <var title="">property</var> for <var title="">new parent</var> is
+ not <var title="">new value</var>, set the CSS property <var title="">property</var> of
+ <var title="">new parent</var> to <var title="">new value</var>.
+
+ <li>Append <var title="">node</var> to <var title="">new parent</var> as its 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>.
+
+ <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> and the computed value of
+ <var title="">property</var> for <var title="">node</var> is not <var title="">new value</var>, set the
+ CSS property <var title="">property</var> of <var title="">node</var> to <var title="">new value</var>.
+</ol>
-<h2 id=commands><span class=secno>12 </span>Commands</h2>
+<h2 id=styling-a-node><span class=secno>8 </span>Styling a node</h2>
+<p>When a user agent is to <dfn id=style>style</dfn> 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>, it must
+run the following steps. There are two inputs: a CSS property name
+<var title="">property</var> and a new value <var title="">new value</var>.
+
+<div class=note>
+<p>The effect of this algorithm is to ensure that the node and all its
+descendants have the style requested, no matter what, producing the simplest
+markup possible to achieve that effect. It's inspired by the approach WebKit
+takes. The only places where the algorithm should fail are when there's an
+!important CSS rule that conflicts with the requested style (which we don't try
+to override because we assume it's !important for a reason), or when it's
+literally impossible to succeed (such as when a text-decoration is propagated
+from an ancestor we can't reach). Any other failures are bugs.
+
+<p>First, if the node is an element with an inline style rule for this
+property, we unset it ("clearing styles"). This step also removes <a href=#simple-styling-element title="simple styling element">simple styling elements</a> entirely, and
+replaces elements like <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/#font><code class=external data-anolis-spec=html title=font>font</code></a> with <a href=http://www.whatwg.org/html/#the-span-element><code class=external data-anolis-spec=html title="the span element">span</code></a>s if they aren't simple
+styling elements. This will be sufficient if the desired style is inherited
+from an ancestor, or if it's the default (like font-style: normal) and no
+conflicting style is inherited from an ancestor. Even if clearing styles
+doesn't actually fix the style of the node we're dealing with, we do it anyway
+to simplify the generated markup.
+
+<p>If clearing styles didn't work, and it looks like an ancestor has inline
+style that we're inheriting, we push the style down from that ancestor. Thus
+if we're unbolding the letter "r" in
+
+</p><xmp><b>foo <i>bar</i> baz</b>,</xmp>
+
+<p>we get
+
+</p><xmp><b>foo </b><i><b>ba</b>r</i><b> baz</b>.</xmp>
+
+<p>If we didn't push down styles, the final step (forcing styles) would instead
+give us
+
+</p><xmp><b>foo <i>ba<span style="font-weight: normal">r</span></i> baz</b>,</xmp>
+
+<p>which is much longer and uglier. We take care not to disturb the style or
+semantics of anything but the node we're dealing with.
+
+<p>We'll only push down styles if some ancestor actually has the style we want,
+so we can inherit it. Otherwise, it will just create useless markup.
+
+<p>Finally, if neither of the above strategies worked, we have to add new
+markup to get the desired style ("forcing styles"). First we try just sticking
+it into its previous or next sibling, if that's a <a href=#simple-styling-element>simple styling
+element</a> (so it won't add any styles or semantics we don't want).
+Otherwise, we create a new simple styling element and wrap it in that. It's
+common that a previous sibling is the simple styling element we want, because
+often we'll style several consecutive siblings in succession. In that case,
+the element created for the first can be reused for the later ones.
+
+<p>This last step works a bit differently if the node is an <a href=#unwrappable-element>unwrappable
+element</a>. In that case, wrapping it in a simple styling element would
+make the document less conforming than it already was. Instead, we recursively
+force style on its children. The recursion will terminate when we hit a node
+that's wrappable, or when there are no further descendants.
+
+<p>After all this, the node is guaranteed to have the style we want, barring
+bugs in the algorithm or the two exceptions noted earlier (!important style
+rules, and impossible cases). We then re-run the algorithm on each child
+recursively. Typically this means just clearing the style of each descendant,
+because it should then inherit the style we just set on its ancestor. In the
+unusual case that a descendant's style is wrong even after we clear style on
+it, such as because of a non-inline style rule (like trying to unbold a
+heading), we'll repeat the above steps to ensure that the style really gets set
+as desired.
+</div>
+
+<ol>
+ <li>If <var title="">node</var> is a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#document><code class=external data-anolis-spec=domcore>Document</code></a>, <a href=#style>style</a> its <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 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> (if it has one) and abort this algorithm.
+
+ <li>If <var title="">node</var> is a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#documentfragment><code class=external data-anolis-spec=domcore>DocumentFragment</code></a>, let <var title="">children</var> be
+ a list of 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>children</a>. <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>,
+ then abort this algorithm.
+
+ <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, or if <var title="">node</var> is a <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#documenttype><code class=external data-anolis-spec=domcore>DocumentType</code></a>, abort this algorithm.
+
+ <p class=XXX>We could style detached elements, but maybe it's not worth the
+ effort. Is execCommand() even supposed to work on things that don't descend
+ from a document? Needs investigation.
+
+ <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>:
+
+ <ol>
+ <li><a href=#clear-styles>Clear styles</a> on <var title="">node</var>, and let <var title="">new
+ nodes</var> be the result.
+
+ <li>For each <var title="">new node</var> in <var title="">new nodes</var>,
+ <a href=#style>style</a> <var title="">new node</var>, with the same inputs as this
+ invocation of the algorithm.
+
+ <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.
+ </ol>
+
+ <li><a href=#push-down-styles>Push down styles</a> on <var title="">node</var>.
+
+ <li><a href=#force-the-style>Force the style</a> of <var title="">node</var>.
+
+ <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>.
+
+ <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
+ children in full before they begin styling.
+</ol>
+
+
+<h2 id=commands><span class=secno>9 </span>Commands</h2>
<p>The <dfn id=execcommand() title=execCommand()><code>execCommand(<var title="">commandId</var>,
<var title="">showUI</var>, <var title="">value</var>)</code></dfn> method on the
<a href=http://www.whatwg.org/html/#htmldocument><code class=external data-anolis-spec=html>HTMLDocument</code></a> interface allows scripts to
@@ -732,9 +778,10 @@
<dt><code title=""><dfn id=command-backcolor title=command-backColor>backColor</dfn></code>
<dd><p><strong>Action</strong>: If <var title="">value</var> is not a valid CSS color,
-the user agent must do nothing and abort these steps. Otherwise, it must <a href=#style-a-range title="style a range">style the <code class=external data-anolis-spec=domrange>Range</code></a> with <var title="">property name</var>
-equal to "background-color", <var title="">property value</var> equal to
-<var title="">value</var>, and <var title="">tag list</var> equal to the empty list.
+the user agent must do nothing and abort these steps. Otherwise, it must
+<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>, then <a href=#style>style</a> each returned
+<a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> with <var title="">property</var> equal to "background-color" and <var title="">new
+value</var> equal to <var title="">value</var>.
<!-- Firefox documentation says it normally sets the background color of the
document, but I can't get it to work at all in brief testing in 4b11. (It says
it behaves differently in styleWithCss mode.) Opera 11 appears to set the
@@ -761,8 +808,7 @@
<dd><p><strong>Value</strong>: The value is given by the following algorithm:
<ol>
- <li>Let <var title="">element</var> be the <a href=#beginning-element>beginning element</a> of the
- <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>.
+ <li class=XXX>...
<li>While the computed style of "background-color" on <var title="">element</var>
is any fully transparent value, set <var title="">element</var> to its parent.
@@ -782,16 +828,17 @@
<dt><code title=""><dfn id=command-bold title=command-bold>bold</dfn></code>
-<dd><p><strong>Action</strong>: If the state of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> for this command
-is false, the user agent must <a href=#style-a-range title="style a range">style the
-<code class=external data-anolis-spec=domrange>Range</code></a> with <var title="">property name</var> "font-weight", <var title="">property
-value</var> "bold", and <var title="">tag list</var> ["b", "strong"]. Otherwise, it
-must <a href=#unstyle-a-range title="unstyle a range">unstyle it</a> with <var title="">property
-name</var> "font-weight", <var title="">property value</var> "normal", and <var title="">tag
-list</var> ["b", "strong"].
+<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
+state of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> for this command is then true, <a href=#style>style</a> each
+returned <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> with <var title="">property</var> "font-weight" and <var title="">new
+value</var> "bold". Otherwise, <a href=#style>style</a> them with <var title="">new
+value</var> "normal".
-<dd><p><strong>State</strong>: True if the <a href=#beginning-element>beginning element</a> of the
-<a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> has font-weight with computed value less than 700, otherwise false.
+<dd><p><strong>State</strong>: True if every <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> that is
+<a href=#effectively-contained>effectively contained</a> in the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> has computed font-weight at
+least 700, and 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 every <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node that is <a href=#effectively-contained>effectively
+contained</a> in the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> has computed font-weight at least 700.
+Otherwise false.
<dd><p><strong>Value</strong>: Always the empty string.
<!-- We have lots of options here (and presumably for all the others where
@@ -817,8 +864,7 @@
specify "#" for the value, or the author can rewrite it, so it's not like
this makes the API less useful. -->
- <li>Let <var title="">node list</var> be the result of <a href=#decompose-a-range title="decompose a
- range">decomposing</a> the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>.
+ <li>Let <var title="">node list</var> be the result of <a href=#decompose title=decompose>decomposing</a> the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>.
<li>For each <var title="">node</var> in <var title="">node list</var>, in order:
@@ -893,10 +939,9 @@
<dt><code title=""><dfn id=command-fontname title=command-fontname>fontName</dfn></code>
-<dd><p><strong>Action</strong>: The user agent must <a href=#style-a-range title="style a
-range">style the <code class=external data-anolis-spec=domrange>Range</code></a> with <var title="">property name</var> equal to
-"font-family", <var title="">property value</var> equal to <var title="">value</var>, and
-<var title="">tag list</var> equal to the empty list.
+<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>, then
+<a href=#style>style</a> each returned <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> with <var title="">property</var> equal to
+"font-family" and <var title="">new value</var> equal to <var title="">value</var>.
<!-- UAs differ a bit in the details here:
IE 9 RC: Empty string sets <font face="">
@@ -921,7 +966,7 @@
<dd><p><strong>State</strong>: Always false.
<dd><p><strong>Value</strong>: The computed value of the CSS property
-"font-family" for the <a href=#beginning-element>beginning element</a> of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>.
+"font-family" for . . .
<!-- Complicated.
IE 9 RC: Always the empty string. Not very useful.
@@ -958,9 +1003,9 @@
except in Opera, which tries to parse it in some crazy way and winds up with
"#00b025". rgba() colors don't work as uniformly, but I don't see any reason
to prohibit them. Best to just match CSS. -->
-Otherwise, it must <a href=#style-a-range title="style a range">style the <code class=external data-anolis-spec=domrange>Range</code></a> with
-<var title="">property name</var> equal to "color", <var title="">property value</var> equal to
-<var title="">value</var>, and <var title="">tag list</var> equal to the empty list.
+Otherwise, it must <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>, then
+<a href=#style>style</a> each returned <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> with <var title="">property</var> equal to
+"color" and <var title="">new value</var> equal to <var title="">value</var>.
<dd><p><strong>State</strong>: Always false.
<!-- This matches IE 9 RC and Chrome 10. Opera 11 seems to return true if
@@ -970,7 +1015,7 @@
least as much sense. -->
<dd><p><strong>Value</strong>: The computed value of the CSS property "color"
-for the <a href=#beginning-element>beginning element</a> of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a>.
+for . . .
<!-- IE 9 RC returns the number 0 always, which makes no sense at all. This
matches the other browsers. -->
@@ -1019,17 +1064,17 @@
<dt><code title=""><dfn id=command-italic title=command-italic>italic</dfn></code>
-<dd><p><strong>Action</strong>: If the of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> for this command is
-false, the user agent must <a href=#style-a-range title="style a range">style the
-<code class=external data-anolis-spec=domrange>Range</code></a> with <var title="">property name</var> "font-style", <var title="">property
-value</var> "italic", <var title="">tag list</var> ["i", "em"]. Otherwise, it must
-<a href=#unstyle-a-range title="unstyle a range">unstyle it</a> with <var title="">property name</var>
-"font-style", <var title="">property value</var> "normal", and <var title="">tag list</var> ["i",
-"em"].
+<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
+state of the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> for this command is then true, <a href=#style>style</a> each
+returned <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#node><code class=external data-anolis-spec=domcore>Node</code></a> with <var title="">property</var> "font-style" and <var title="">new
+value</var> "italic". Otherwise, <a href=#style>style</a> them with <var title="">new
+value</var> "normal".
-<dd><p><strong>State</strong>: True if the <a href=#beginning-element>beginning element</a> of the
-<a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> has font-style with computed value "italic" or "oblique", otherwise
-false.
+<dd><p><strong>State</strong>: True if every <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element><code class=external data-anolis-spec=domcore>Element</code></a> that is
+<a href=#effectively-contained>effectively contained</a> in the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> has computed font-style
+"italic" or "oblique", and 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 every <a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text><code class=external data-anolis-spec=domcore>Text</code></a> node that is
+<a href=#effectively-contained>effectively contained</a> in the <a href=http://html5.org/specs/dom-range.html#range><code class=external data-anolis-spec=domrange>Range</code></a> has computed font-style
+"italic" or "oblique". Otherwise false.
<dd><p><strong>Value</strong>: Always the empty string.
--- a/implementation.js Tue Mar 15 22:39:50 2011 -0600
+++ b/implementation.js Thu Mar 17 16:14:25 2011 -0600
@@ -2,24 +2,7 @@
var htmlNamespace = "http://www.w3.org/1999/xhtml";
-function getNodeIndex(node) {
- var ret = 0;
- while (node != node.parentNode.childNodes[ret]) {
- ret++;
- }
- return ret;
-}
-
-function getNodeLength(node) {
- if (node.nodeType == Node.TEXT_NODE
- || node.nodeType == Node.COMMENT_NODE
- || node.nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
- return node.data.length;
- }
-
- return node.childNodes.length;
-}
-
+// Utility functions
function nextNode(node) {
if (node.hasChildNodes()) {
return node.firstChild;
@@ -52,35 +35,71 @@
return node.nextSibling;
}
-function convertProperty(propertyName) {
+function convertProperty(property) {
// Special-case for now
var map = {
"fontStyle": "font-style",
"fontWeight": "font-weight",
"textDecoration": "text-decoration",
};
- if (typeof map[propertyName] != "undefined") {
- return map[propertyName];
+ if (typeof map[property] != "undefined") {
+ return map[property];
}
- return propertyName;
+ return property;
}
-function cssValuesEqual(propertyName, val1, val2) {
+function cssValuesEqual(property, val1, val2) {
// This is a bad hack to work around browser incompatibility. It wouldn't
// work in real life, but it's good enough for a test implementation.
+ if (val1 === null || val2 === null) {
+ return val1 === val2;
+ }
+
+ if (property == "fontWeight") {
+ return val1 == val2
+ || (val1.toLowerCase() == "bold" && val2 == "700")
+ || (val2.toLowerCase() == "bold" && val1 == "700")
+ || (val1.toLowerCase() == "normal" && val2 == "400")
+ || (val2.toLowerCase() == "normal" && val1 == "400");
+ }
var test1 = document.createElement("span");
- test1.style[propertyName] = val1;
+ test1.style[property] = val1;
var test2 = document.createElement("span");
- test2.style[propertyName] = val2;
+ test2.style[property] = val2;
- return test1.style[propertyName] == test2.style[propertyName];
+ return test1.style[property] == test2.style[property];
+}
+
+// Opera 11 puts HTML elements in the null namespace, it seems.
+function isHtmlNamespace(ns) {
+ return ns === null
+ || ns === htmlNamespace;
}
+// Functions for stuff in DOM Range
+function getNodeIndex(node) {
+ var ret = 0;
+ while (node != node.parentNode.childNodes[ret]) {
+ ret++;
+ }
+ return ret;
+}
+
+function getNodeLength(node) {
+ if (node.nodeType == Node.TEXT_NODE
+ || node.nodeType == Node.COMMENT_NODE
+ || node.nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
+ return node.data.length;
+ }
+
+ return node.childNodes.length;
+}
+
/**
* The position of two boundary points relative to one another, as defined by
- * the spec.
+ * DOM Range.
*/
function getPosition(nodeA, offsetA, nodeB, offsetB) {
// "If node A is the same as node B, return equal if offset A equals offset
@@ -156,54 +175,43 @@
&& pos2 == "before";
}
+
+// Things defined in the edit command spec (i.e., the interesting stuff)
+
+
+// "A Node is an HTML element if it is an Element whose namespace is the HTML
+// namespace."
function isHtmlElement(node) {
return node
&& node.nodeType == Node.ELEMENT_NODE
- && node.namespaceURI == htmlNamespace;
+ && isHtmlNamespace(node.namespaceURI);
}
-function beginningElement(range) {
- // "If the start node of the Range is a Text, Comment, or
- // ProcessingInstruction node, and the start offset of the Range is not
- // equal to the length of its start node, let first node be the Range's
- // start node."
- var firstNode = null;
- if (range.startOffset != getNodeLength(range.startContainer)
- && (range.startContainer.nodeType == Node.TEXT_NODE
- || range.startContainer.nodeType == Node.COMMENT_NODE
- || range.startContainer.nodeType == Node.PROCESSING_INSTRUCTION_NODE)) {
- firstNode = range.startContainer;
- // "Otherwise, let first node be the first Node in tree order that is
- // contained in the Range, if there is any."
- } else {
- var firstContained = range.startContainer;
- while (firstContained != range.endContainer
- && !isContained(firstContained, range)) {
- firstContained = nextNode(firstContained);
- }
- if (firstContained != range.endContainer) {
- firstNode = firstContained;
- }
+
+/**
+ * "A Node is effectively contained in a Range if either it is contained in the
+ * Range; or it is the Range's start node, it is a Text node, and its length is
+ * different from the Range's start offset; or it is the Range's end node, it
+ * is a Text node, and the Range's end offset is not 0."
+ */
+function isEffectivelyContained(node, range) {
+ if (isContained(node, range)) {
+ return true;
}
-
- // "If first node is defined and is an Element, return first node."
- if (firstNode && firstNode.nodeType == Node.ELEMENT_NODE) {
- return firstNode;
+ if (node == range.startContainer
+ && node.nodeType == Node.TEXT_NODE
+ && getNodeLength(node) != range.startOffset) {
+ return true;
}
-
- // "Otherwise, if first node is defined and its parent is an Element,
- // return first node's parent."
- if (firstNode
- && firstNode.parentNode
- && firstNode.parentNode.nodeType == Node.ELEMENT_NODE) {
- return firstNode.parentNode;
+ if (node == range.endContainer
+ && node.nodeType == Node.TEXT_NODE
+ && range.endOffset != 0) {
+ return true;
}
-
- // "Return null."
- return null;
+ return false;
}
-function activeRange(doc) {
+function getActiveRange(doc) {
// "Let selection be the result of calling getSelection() on the Document."
//
// We call getSelection() on defaultView instead, because Firefox and Opera
@@ -243,161 +251,65 @@
}
}
-/**
- * "Given a CSS property name property name, an (optional) value property value
- * for that property, and a possibly empty list of strings tag list, a Node is
- * a potentially relevant styling element if it is an HTML element and one of
- * the following holds:
- *
- * * Its local name is in tag list and it has no attributes.
- * * Its local name is in tag list or is "span" or is "font", and it has
- * exactly one attribute, and that attribute is an HTML attribute with local
- * name "style", and that attribute sets exactly one CSS property, and that
- * property is property name, and either property value is undefined or the
- * value the attribute sets the property to is property value.
- * * Its local name is "font", and it has exactly one attribute, and that
- * attribute is a color attribute, and either property value is undefined or
- * the effect of the attribute is to hint that the CSS color attribute be
- * set to property value, and property name is "color".
- * * Its local name is "font", and it has exactly one attribute, and that
- * attribute is a face attribute, and either property value is undefined or
- * the effect of the attribute is to hint that the CSS font-family attribute
- * be set to property value, and property name is "font-family".
- * * Its local name is "font", and it has exactly one attribute, and that
- * attribute is a size attribute, and either property value is undefined or
- * the effect of the attribute is to hint that the CSS font-size attribute
- * be set to property value, and property name is "font-size"."
- */
-function isPotentiallyRelevantStylingElement(element, propertyName, propertyValue, tagList) {
- if (!isHtmlElement(element)) {
+// "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)."
+//
+// I don't bother implementing this exactly, just well enough for testing.
+function isUnwrappableElement(node) {
+ if (!isHtmlElement(node)) {
return false;
}
- var localName = element.tagName.toLowerCase();
-
- if (tagList.indexOf(localName) != -1 && element.attributes.length == 0) {
- return true;
- }
-
- if ((tagList.indexOf(localName) != -1 || localName == "span" || localName == "font")
- && element.attributes.length == 1
- // Not checking namespace because it seems buggy, maybe?
- //&& element.attributes[0].namespaceURI == htmlNamespace
- && element.attributes[0].localName == "style"
- && element.style.length == 1
- && element.style.item(0) == convertProperty(propertyName)
- && (propertyValue === null
- || cssValuesEqual(propertyName, element.style[propertyName], propertyValue))) {
- return true;
- }
-
- var fontAttr = null;
- if (propertyName == "color") {
- fontAttr = "color";
- } else if (propertyName == "fontFamily") {
- fontAttr = "face";
- } else if (propertyName == "fontSize") {
- fontAttr = "size";
- }
-
- // TODO: cssValuesEqual() is total nonsense for font-size.
- if (fontAttr
- && localName == "font"
- && element.attributes.length == 1
- //&& element.attributes[0].namespaceURI == htmlNamespace
- && element.attributes[0].localName == fontAttr
- && (propertyValue === null
- || cssValuesEqual(propertyName, element[fontAttr], propertyValue))) {
- return true;
- }
-}
-
-/**
- * "A Node is a relevant styling element if it is a potentially relevant
- * styling element, and its CSS property property name computes to property
- * value."
- */
-function isRelevantStylingElement(node, propertyName, propertyValue, tagList) {
- return isPotentiallyRelevantStylingElement(node, propertyName, propertyValue, tagList)
- && cssValuesEqual(propertyName, getComputedStyle(node)[propertyName], propertyValue);
+ return [
+ "h1", "h2", "h3", "h4", "h5", "h6", "p", "hr", "pre", "blockquote",
+ "ol", "ul", "li", "dl", "dt", "dd", "div", "table", "caption",
+ "colgroup", "col", "tbody", "thead", "tfoot", "tr", "th", "td",
+ ].indexOf(node.tagName.toLowerCase()) != -1;
}
/**
- * "A phrasing element is either an HTML element that is categorized as
- * phrasing content, or a non-conforming HTML element (which thus has no
- * categories), or an Element that is not an HTML element."
+ * "specified style" per edit command spec
*/
-function isPhrasingElement(element) {
- if (!element || element.nodeType != Node.ELEMENT_NODE) {
- return false;
- }
-
- if (!isHtmlElement(element)) {
- return true;
- }
-
- // As of March 2011.
- var nonConforming = ["applet", "acronym", "bgsound", "dir", "frame",
- "frameset", "noframes", "isindex", "listing", "xmp", "nextid", "noembed",
- "plaintext", "rb", "strike", "basefont", "big", "blink", "center", "font",
- "marquee", "multicol", "nobr", "spacer", "tt", "u"];
-
- // I'm skipping checks for elements that are only sometimes phrasing
- // content. I just assume they always are.
- var phrasingElements = ["a", "abbr", "area", "audio", "b", "bdi", "bdo",
- "br", "button", "canvas", "cite", "code", "command", "datalist", "del",
- "dfn", "em", "embed", "i", "iframe", "img", "input", "ins", "kbd",
- "keygen", "label", "link", "map", "mark", "math", "meta", "meter",
- "noscript", "object", "output", "progress", "q", "ruby", "s", "samp",
- "script", "select", "small", "span", "strong", "sub", "sup", "svg",
- "textarea", "time", "var", "video", "wbr"];
-
- return nonConforming.indexOf(element.tagName.toLowerCase()) != -1
- || phrasingElements.indexOf(element.tagName.toLowerCase()) != -1;
-}
-
-/**
- * "specified style" per spec
- */
-function getSpecifiedStyle(element, propertyName) {
+function getSpecifiedStyle(element, property) {
// "If the Element has a style attribute set, and that attribute has the
- // effect of setting property name, return the value that it sets property
- // name to."
- if (element.style[propertyName] != "") {
- return element.style[propertyName];
+ // effect of setting property, return the value that it sets property to."
+ if (element.style[property] != "") {
+ return element.style[property];
}
// "If the Element is a font element that has an attribute whose effect is
- // to create a presentational hint for property name, return the value that
- // the hint sets property name to."
+ // to create a presentational hint for property, return the value that the
+ // hint sets property to."
//
- // I'm cheating on this one for simplicity. Font-size is especially wrong.
- if (element.namespaceURI == htmlNamespace
+ // I'm cheating on this one for simplicity. Font-size is especially wrong,
+ // and will have to be fixed when I implement execCommand() for that.
+ if (isHtmlNamespace(element.namespaceURI)
&& element.tagName == "FONT") {
- if (propertyName == "color" && element.hasAttribute("color")) {
+ if (property == "color" && element.hasAttribute("color")) {
return element.color;
}
- if (propertyName == "fontFamily" && element.hasAttribute("face")) {
+ if (property == "fontFamily" && element.hasAttribute("face")) {
return element.face;
}
- if (propertyName == "fontSize" && element.hasAttribute("size")) {
+ if (property == "fontSize" && element.hasAttribute("size")) {
return element.size;
}
}
- // "If the Element is in the following list, and property name is equal to
- // the CSS property name listed for it, return the string listed for it."
+ // "If the Element is in the following list, and property is equal to the
+ // CSS property name listed for it, return the string listed for it."
//
// A list follows, whose meaning is copied here.
- if (propertyName == "fontWeight"
+ if (property == "fontWeight"
&& (element.tagName == "B" || element.tagName == "STRONG")) {
return "bold";
}
- if (propertyName == "fontStyle"
+ if (property == "fontStyle"
&& (element.tagName == "I" || element.tagName == "EM")) {
return "italic";
}
- if (propertyName == "textDecoration"
+ if (property == "textDecoration"
&& element.tagName == "U") {
return "underline";
}
@@ -406,6 +318,87 @@
return null;
}
+function isSimpleStylingElement(node) {
+ // "A simple styling element is an HTML element for which at least one of
+ // the following holds:"
+ if (!isHtmlElement(node)) {
+ 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) {
+ return true;
+ }
+
+ // If it's got more than one attribute, everything after this fails.
+ if (node.attributes.length > 1) {
+ return false;
+ }
+
+ // "It is a b, em, font, i, span, strong, or u element with exactly one
+ // attribute, which is style, which sets no CSS properties (including
+ // invalid or unrecognized properties)."
+ //
+ // Not gonna try for invalid or unrecognized.
+ if (node.hasAttribute("style")
+ && node.style.length == 0) {
+ return true;
+ }
+
+ // "It is a font element with one attribute, which is either color, face,
+ // or size."
+ if (node.tagName == "FONT"
+ && (node.hasAttribute("color")
+ || 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"."
+ if ((node.tagName == "B" || node.tagName == "STRONG")
+ && node.hasAttribute("style")
+ && node.style.length == 1
+ && node.style.fontWeight != "") {
+ 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"."
+ if ((node.tagName == "I" || node.tagName == "EM")
+ && node.hasAttribute("style")
+ && node.style.length == 1
+ && node.style.fontStyle != "") {
+ 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"."
+ if (node.tagName == "U"
+ && node.hasAttribute("style")
+ && node.style.length == 1
+ && node.style.textDecoration != "") {
+ return true;
+ }
+
+ // "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)."
+ if ((node.tagName == "FONT" || node.tagName == "SPAN")
+ && node.hasAttribute("style")
+ && node.style.length == 1) {
+ return true;
+ }
+
+ return false;
+}
+
function decomposeRange(range) {
// "If range's start and end are the same, return an empty list."
if (range.startContainer == range.endContainer
@@ -481,21 +474,42 @@
range.setStart(startNode, startOffset);
range.setEnd(endNode, endOffset);
- // "Return a list consisting of every Node contained in range in tree
- // order, omitting any whose parent is also contained in range."
+ // "Let cloned range be the result of calling cloneRange() on range."
+ var clonedRange = range.cloneRange();
+
+ // "While the start offset of cloned range is 0, and the parent of cloned
+ // range's start node is not null, set the start of cloned range to (parent
+ // of start node, index of start node)."
+ while (clonedRange.startOffset == 0
+ && clonedRange.startContainer.parentNode) {
+ clonedRange.setStart(clonedRange.startContainer.parentNode, getNodeIndex(clonedRange.startContainer));
+ }
+
+ // "While the end offset of cloned range equals the length of its end node,
+ // and the parent of clone range's end node is not null, set the end of
+ // cloned range to (parent of end node, 1 + index of end node)."
+ while (clonedRange.endOffset == getNodeLength(clonedRange.endContainer)
+ && clonedRange.endContainer.parentNode) {
+ clonedRange.setEnd(clonedRange.endContainer.parentNode, 1 + getNodeIndex(clonedRange.endContainer));
+ }
+
+ // "Return a list consisting of every Node contained in cloned range in
+ // tree order, omitting any whose parent is also contained in cloned
+ // range."
var ret = [];
- for (var node = startNode; node != nextNodeDescendants(endNode); node = nextNode(node)) {
- if (isContained(node, range)
- && !isContained(node.parentNode, range)) {
+ for (var node = clonedRange.startContainer; node != nextNodeDescendants(clonedRange.endContainer); node = nextNode(node)) {
+ if (isContained(node, clonedRange)
+ && !isContained(node.parentNode, clonedRange)) {
ret.push(node);
}
}
return ret;
}
-function clearStyles(element, propertyName, tagList) {
- // "If element is a potentially relevant styling element:"
- if (isPotentiallyRelevantStylingElement(element, propertyName, null, tagList)) {
+function clearStyles(element, property) {
+ // "If element is a simple styling element and its specified style for
+ // property is not null:"
+ if (isSimpleStylingElement(element) && getSpecifiedStyle(element, property) !== null) {
// "Let children be an empty list of Nodes."
var children = [];
@@ -511,44 +525,42 @@
element.parentNode.insertBefore(child, element);
}
- // "Remove element."
+ // "Remove element from its parent."
element.parentNode.removeChild(element);
// "Return children."
return children;
}
- // "Unset the CSS property property name of element."
- element.style[propertyName] = '';
+ // "Unset the CSS property property of element."
+ element.style[property] = '';
if (element.getAttribute("style") == "") {
element.removeAttribute("style");
}
// "If element is a font element:"
- if (element.namespaceURI == htmlNamespace && element.tagName == "FONT") {
- // "If property name is "color", unset element's color attribute, if
- // set."
- if (propertyName == "color") {
+ if (isHtmlNamespace(element.namespaceURI) && element.tagName == "FONT") {
+ // "If property is "color", unset element's color attribute, if set."
+ if (property == "color") {
element.removeAttribute("color");
}
- // "If property name is "font-family", unset element's face attribute,
- // if set."
- if (propertyName == "fontFamily") {
+ // "If property is "font-family", unset element's face attribute, if
+ // set."
+ if (property == "fontFamily") {
element.removeAttribute("face");
}
- // "If property name is "font-size", unset element's size attribute, if
+ // "If property is "font-size", unset element's size attribute, if
// set."
- if (propertyName == "fontSize") {
+ if (property == "fontSize") {
element.removeAttribute("size");
}
}
- // "If element is not an HTML element or its local name is not in tag list,
- // return the empty list."
- if (element.namespaceURI != htmlNamespace
- || tagList.indexOf(element.tagName.toLowerCase()) == -1) {
+ // "If element's specified style for property is null, return the empty
+ // list."
+ if (getSpecifiedStyle(element, property) === null) {
return [];
}
@@ -570,243 +582,63 @@
newElement.appendChild(element.firstChild);
}
- // "Remove element."
+ // "Remove element from its parent."
element.parentNode.removeChild(element);
// "Return the one-Node list consisting of new element."
return [newElement];
}
-function recursivelyClearStyles(element, propertyName, tagList) {
- // "Let element children be the Element children of element."
- var elementChildren = [];
- for (var j = 0; j < element.childNodes.length; j++) {
- if (element.childNodes[j].nodeType == Node.ELEMENT_NODE) {
- elementChildren.push(element.childNodes[j]);
- }
- }
-
- // "Recursively clear styles on each Element in element children."
- for (var j = 0; j < elementChildren.length; j++) {
- recursivelyClearStyles(elementChildren[j], propertyName, tagList);
- }
-
- // "Clear styles on element, and return the resulting list."
- return clearStyles(element, propertyName, tagList);
-}
-
-function styleNode(node, propertyName, propertyValue, tagList) {
- // "If node's parent is null, or if node is not an Element, Text, Comment,
- // or ProcessingInstruction node, abort this algorithm."
+function pushDownStyles(node, property, newValue) {
+ // "If node's parent is not an Element, abort this algorithm."
if (!node.parentNode
- || [Node.ELEMENT_NODE, Node.TEXT_NODE, Node.COMMENT_NODE,
- Node.PROCESSING_INSTRUCTION_NODE].indexOf(node.nodeType) == -1) {
- return;
- }
-
- // "If node is an Element:"
- if (node.nodeType == Node.ELEMENT_NODE) {
- // "Clear styles on node, and let new nodes be the result."
- var newNodes = clearStyles(node, propertyName, tagList);
-
- // "For each new node in new nodes, style new node, with the same
- // inputs as this invocation of the algorithm."
- for (var i = 0; i < newNodes.length; i++) {
- styleNode(newNodes[i], propertyName, propertyValue, tagList);
- }
-
- // "If node's parent is null, abort this algorithm."
- if (!node.parentNode) {
- return;
- }
- }
-
- // "If node is an Element but not a phrasing element:"
- if (node.nodeType == Node.ELEMENT_NODE
- && !isPhrasingElement(node)) {
- // "Let children be all children of node, omitting any that are
- // Elements whose specified style for property name is neither null nor
- // equal to property 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], propertyName);
-
- if (specifiedStyle !== null
- && !cssValuesEqual(propertyName, propertyValue, specifiedStyle)) {
- continue;
- }
- }
- children.push(node.childNodes[i]);
- }
-
- // "Style each Node in children."
- for (var i = 0; i < children.length; i++) {
- styleNode(children[i], propertyName, propertyValue, tagList);
- }
-
- // "Abort this algorithm."
- return;
- }
-
- // "If node's previousSibling is a relevant styling element, append node as
- // the last child of its previousSibling and abort this algorithm."
- if (isRelevantStylingElement(node.previousSibling, propertyName, propertyValue, tagList)) {
- node.previousSibling.appendChild(node);
- return;
- }
-
- // "If node's nextSibling is a relevant styling element, insert node as the
- // first child of its nextSibling and abort this algorithm."
- if (isRelevantStylingElement(node.nextSibling, propertyName, propertyValue, tagList)) {
- node.nextSibling.insertBefore(node, node.nextSibling.childNodes.length
- ? node.nextSibling.childNodes[0]
- : null);
- return;
- }
-
- // "If node is a Comment or ProcessingInstruction, abort this algorithm."
- if (node.nodeType == Node.COMMENT_NODE
- || node.nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
- return;
- }
-
- // "If node is an Element and the computed style of property name for it is
- // property value, abort this algorithm."
- if (node.nodeType == Node.ELEMENT_NODE
- && cssValuesEqual(propertyName, getComputedStyle(node)[propertyName], propertyValue)) {
+ || node.parentNode.nodeType != Node.ELEMENT_NODE) {
return;
}
- // "If node is a Text node and the computed style of property name for its
- // parent is property value, abort this algorithm."
- if (node.nodeType == Node.TEXT_NODE
- && cssValuesEqual(propertyName, getComputedStyle(node.parentNode)[propertyName], propertyValue)) {
- return;
- }
-
- // "Let tag be the first string in tag list, if that is not empty, or
- // "span" if it is empty."
- var tag = tagList.length ? tagList[0] : "span";
-
- // "Let new parent be the result of calling createElement(tag) on the
- // ownerDocument of node."
- var newParent = node.ownerDocument.createElement(tag);
-
- // "Insert new parent in node's parent before node."
- node.parentNode.insertBefore(newParent, node);
-
- // "If the computed value of property name for new parent is not property
- // value, set the CSS property property name of new parent to property
- // value."
- if (!cssValuesEqual(propertyName, getComputedStyle(newParent)[propertyName], propertyValue)) {
- newParent.style[propertyName] = propertyValue;
- }
-
- // "Append node to new parent as its last child."
- newParent.appendChild(node);
-}
-
-function recursivelyStyleNode(node, propertyName, propertyValue, tagList) {
- // "If node's parent is null, or if node is not an Element, Text, Comment,
- // or ProcessingInstruction node, abort this algorithm."
- if (!node.parentNode
- || [Node.ELEMENT_NODE, Node.TEXT_NODE, Node.COMMENT_NODE,
- Node.PROCESSING_INSTRUCTION_NODE].indexOf(node.nodeType) == -1) {
+ // "If node is an Element and property computes to new value on node, abort
+ // this algorithm."
+ if (node.nodeType == Node.ELEMENT_NODE
+ && cssValuesEqual(property, getComputedStyle(node)[property], newValue)) {
return;
}
- // "If node is an Element:"
- if (node.nodeType == Node.ELEMENT_NODE) {
- // "Recursively clear styles on node, and let new nodes be the result."
- var newNodes = recursivelyClearStyles(node, propertyName, tagList);
-
- // "For each new node in new nodes, recursively style new node, with
- // the same inputs as this invocation of the algorithm."
- for (var i = 0; i < newNodes.length; i++) {
- recursivelyStyleNode(newNodes[i], propertyName, propertyValue, tagList);
- }
-
- // "If node's parent is null, abort this algorithm."
- if (!node.parentNode) {
- return;
- }
- }
-
- // "Style node."
- styleNode(node, propertyName, propertyValue, tagList);
-}
-
-// "When a user agent is to style a Range, it must decompose the Range, then
-// recursively style each Node in the returned list."
-function styleRange(range, propertyName, propertyValue, tagList) {
- var nodeList = decomposeRange(range);
- for (var i = 0; i < nodeList.length; i++) {
- recursivelyStyleNode(nodeList[i], propertyName, propertyValue, tagList);
- }
-}
-
-function unstyleNode(node, propertyName, newValue, tagList) {
- // "If node's parent is null, or if node is not an Element or Text node,
- // abort this algorithm."
- if (!node.parentNode
- || (node.nodeType != Node.ELEMENT_NODE && node.nodeType != Node.TEXT_NODE)) {
+ // "If node is not an Element and property computes to new value on node's
+ // parent, abort this algorithm."
+ if (node.nodeType != Node.ELEMENT_NODE
+ && cssValuesEqual(property, getComputedStyle(node.parentNode)[property], newValue)) {
return;
}
- // "If node is an Element:"
- if (node.nodeType == Node.ELEMENT_NODE) {
- // "Recursively clear styles on node, and let new nodes be the result."
- var newNodes = recursivelyClearStyles(node, propertyName, tagList);
-
- // "For each new node in new nodes, unstyle new node, with the same
- // inputs as this invocation of the algorithm."
- for (var i = 0; i < newNodes.length; i++) {
- unstyleNode(newNodes[i], propertyName, newValue, tagList);
- }
-
- // "If node's parent is null, abort this algorithm."
- if (!node.parentNode) {
- return;
- }
- }
-
- // "If node is an Element, let current value equal the computed value of
- // property name on node. Otherwise, let current value equal the computed
- // value of property name on node's parent."
- var currentValue;
- if (node.nodeType == Node.ELEMENT_NODE) {
- currentValue = getComputedStyle(node)[propertyName];
- } else {
- currentValue = getComputedStyle(node.parentNode)[propertyName];
- }
-
- // "If current value equals new value, abort this algorithm."
- if (cssValuesEqual(propertyName, currentValue, newValue)) {
- return;
- }
+ // "Let current ancestor be node's parent."
+ var currentAncestor = node.parentNode;
// "Let ancestor list be a list of Nodes, initially empty."
var ancestorList = [];
- // "Let current ancestor equal node."
- var currentAncestor = node;
-
- // "While current ancestor's parent is an Element, set current ancestor to
- // its parent, then append it to ancestor list."
- while (currentAncestor.parentNode
- && currentAncestor.parentNode.nodeType == Node.ELEMENT_NODE) {
+ // "While current ancestor is an Element and property does not compute to
+ // new value on it, append current ancestor to ancestor list, then set
+ // current ancestor to its parent."
+ while (currentAncestor
+ && currentAncestor.nodeType == Node.ELEMENT_NODE
+ && !cssValuesEqual(property, getComputedStyle(currentAncestor)[property], newValue)) {
+ ancestorList.push(currentAncestor);
currentAncestor = currentAncestor.parentNode;
- ancestorList.push(currentAncestor);
}
- // "While ancestor list is not empty, and the last member of ancestor list
- // has specified style for property name equal to new value or null, remove
- // the last member from ancestor list."
- while (ancestorList.length
- && (getSpecifiedStyle(ancestorList[ancestorList.length - 1], propertyName) === null
- || cssValuesEqual(propertyName, newValue, getSpecifiedStyle(ancestorList[ancestorList.length - 1], propertyName)))) {
- ancestorList.pop();
+ // "If ancestor list is not empty, and the specified style of property on
+ // the last member of ancestor list is null, abort this algorithm."
+ if (ancestorList.length != 0
+ && getSpecifiedStyle(ancestorList[ancestorList.length - 1], property) === null) {
+ return;
+ }
+
+ // "If ancestor list is not empty, and the parent of the last member of
+ // ancestor list is not an Element, abort this algorithm."
+ if (ancestorList.length != 0
+ && (!ancestorList.slice(-1)[0]
+ || ancestorList.slice(-1)[0].nodeType != Node.ELEMENT_NODE)) {
+ return;
}
// "While ancestor list is not empty:"
@@ -816,8 +648,8 @@
var currentAncestor = ancestorList.pop();
// "Let propagated value be the specified style of current ancestor for
- // property name."
- var propagatedValue = getSpecifiedStyle(currentAncestor, propertyName);
+ // property."
+ var propagatedValue = getSpecifiedStyle(currentAncestor, property);
// "If propagated value is null, continue this loop from the
// beginning."
@@ -832,7 +664,7 @@
}
// "Clear styles on current ancestor."
- clearStyles(currentAncestor, propertyName, tagList);
+ clearStyles(currentAncestor, property);
// "For every child in children:"
for (var i = 0; i < children.length; i++) {
@@ -847,64 +679,223 @@
// is neither null nor equal to propagated value, continue with the
// next child."
if (child.nodeType == Node.ELEMENT_NODE
- && getSpecifiedStyle(child, propertyName) !== null
- && !cssValuesEqual(propertyName, propagatedValue, getSpecifiedStyle(child, propertyName))) {
+ && getSpecifiedStyle(child, property) !== null
+ && !cssValuesEqual(property, propagatedValue, getSpecifiedStyle(child, property))) {
continue;
}
// "If child is the last member of ancestor list, set child's CSS
- // property property name to propagated value and continue with the
- // next child."
+ // property property to propagated value and continue with the next
+ // child."
if (child == ancestorList[ancestorList.length - 1]) {
- child.style[propertyName] = propagatedValue;
+ child.style[property] = propagatedValue;
continue;
}
- // "Style child, with property name and tag list as in this
- // algorithm, and property value equal to propagated value."
- styleNode(child, propertyName, propagatedValue, tagList);
+ // "Force the style of child, with property as in this algorithm
+ // and new value equal to propagated value."
+ forceStyle(child, property, propagatedValue);
+ }
+ }
+}
+
+function forceStyle(node, property, newValue) {
+ // "If node is an Element and property computes to new value on node, abort
+ // this algorithm."
+ if (node.nodeType == Node.ELEMENT_NODE
+ && cssValuesEqual(property, getComputedStyle(node)[property], newValue)) {
+ return;
+ }
+
+ // "If node is not an Element, node's parent is an Element, and property
+ // computes to new value on node's parent, abort this algorithm."
+ if (node.nodeType != Node.ELEMENT_NODE
+ && node.parentNode.nodeType == Node.ELEMENT_NODE
+ && cssValuesEqual(property, getComputedStyle(node.parentNode)[property], newValue)) {
+ return;
+ }
+
+ // "If node is an unwrappable element:"
+ if (isUnwrappableElement(node)) {
+ // "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);
+ }
+
+ // "Abort this algorithm."
+ return;
+ }
+
+ // "If node's previousSibling is a simple styling element whose specified
+ // style and computed 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, getComputedStyle(node.previousSibling)[property], newValue)) {
+ node.previousSibling.appendChild(node);
+ return;
+ }
+
+ // "If node's nextSibling is a simple styling element whose specified style
+ // and computed 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, getComputedStyle(node.nextSibling)[property], newValue)) {
+ node.nextSibling.insertBefore(node, node.nextSibling.childNodes.length
+ ? node.nextSibling.childNodes[0]
+ : null);
+ return;
+ }
+
+ // "If node is a Comment or ProcessingInstruction, abort this algorithm."
+ if (node.nodeType == Node.COMMENT_NODE
+ || node.nodeType == Node.PROCESSING_INSTRUCTION_NODE) {
+ return;
+ }
+
+ // "If node is an Element and property computes to new value on node, abort
+ // this algorithm."
+ if (node.nodeType == Node.ELEMENT_NODE
+ && cssValuesEqual(property, getComputedStyle(node)[property], newValue)) {
+ return;
+ }
+
+ // "If node is not an Element, node's parent is an Element, and property
+ // computes to new value on node's parent, abort this algorithm."
+ if (node.nodeType != Node.ELEMENT_NODE
+ && node.parentNode.nodeType == Node.ELEMENT_NODE
+ && cssValuesEqual(property, getComputedStyle(node.parentNode)[property], newValue)) {
+ return;
+ }
+
+ // "If property is "font-weight" and new value is "bold", let tag be "b"."
+ var tag;
+ if (property == "fontWeight" && newValue == "bold") {
+ 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 the result of calling createElement(tag) on the
+ // ownerDocument of node."
+ var newParent = node.ownerDocument.createElement(tag);
+
+ // "Insert new parent in node's parent before node."
+ node.parentNode.insertBefore(newParent, node);
+
+ // "If the computed value of property for new parent is not new value, set
+ // the CSS property property of new parent to new value."
+ if (!cssValuesEqual(property, getComputedStyle(newParent)[property], newValue)) {
+ newParent.style[property] = newValue;
+ }
+
+ // "Append node to new parent as its last child."
+ newParent.appendChild(node);
+
+ // "If node is an Element and the computed value of property for node is
+ // not new value, set the CSS property property of node to new value."
+ if (node.nodeType == Node.ELEMENT_NODE
+ && !cssValuesEqual(property, getComputedStyle(node)[property], newValue)) {
+ node.style[property] = newValue;
+ }
+}
+
+function styleNode(node, property, newValue) {
+ // "If node is a Document, style its Element child (if it has one) and
+ // abort this algorithm."
+ if (node.nodeType == Node.DOCUMENT_NODE) {
+ for (var i = 0; i < node.childNodes.length; i++) {
+ if (node.childNodes[i].nodeType == Node.ELEMENT_NODE) {
+ styleNode(node.childNodes[i], property, newValue);
+ break;
+ }
+ }
+ return;
+ }
+
+ // "If node is a DocumentFragment, let children be a list of its children.
+ // Style each member of children, then abort this algorithm."
+ if (node.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {
+ var children = [];
+ for (var i = 0; i < node.childNodes.length; i++) {
+ children.push(node.childNodes[i]);
+ }
+ for (var i = 0; i < children.length; i++) {
+ styleNode(children[i], property, newValue);
+ }
+ return;
+ }
+
+ // "If node's parent is null, or if node is a DocumentType, abort this
+ // algorithm."
+ if (!node.parentNode || node.nodeType == Node.DOCUMENT_TYPE_NODE) {
+ return;
+ }
+
+ // "If node is an Element:"
+ if (node.nodeType == Node.ELEMENT_NODE) {
+ // "Clear styles on node, and let new nodes be the result."
+ var newNodes = clearStyles(node, property);
+
+ // "For each new node in new nodes, style new node, with the same
+ // inputs as this invocation of the algorithm."
+ for (var i = 0; i < newNodes.length; i++) {
+ styleNode(newNodes[i], property, newValue);
+ }
+
+ // "If node's parent is null, abort this algorithm."
+ if (!node.parentNode) {
+ return;
}
}
- // "If node is an Element and property name does not compute to new value
- // on it, set property name to new value on it."
- if (node.nodeType == Node.ELEMENT_NODE
- && !cssValuesEqual(propertyName, newValue, getComputedStyle(node)[propertyName])) {
- node.style[propertyName] = newValue;
+ // "Push down styles on node."
+ pushDownStyles(node, property, newValue);
+
+ // "Force the style of node."
+ forceStyle(node, property, newValue);
+
+ // "Let children be the children of node."
+ var children = [];
+ for (var i = 0; i < node.childNodes.length; i++) {
+ children.push(node.childNodes[i]);
}
- // "If node is a Text node and property name does not compute to new value
- // on its parent:"
- if (node.nodeType == Node.TEXT_NODE
- && !cssValuesEqual(propertyName, newValue, getComputedStyle(node.parentNode)[propertyName])) {
- // "Let new parent be the result of calling createElement("span") on
- // the ownerDocument of node."
- var newParent = node.ownerDocument.createElement("span");
-
- // "Set property name to new value on new parent."
- newParent.style[propertyName] = newValue;
-
- // "Insert new parent into node's parent before node."
- node.parentNode.insertBefore(newParent, node);
-
- // "Append node as the last child of new parent."
- newParent.appendChild(node);
- }
-}
-
-// "When a user agent is to unstyle a Range range, it must decompose the Range,
-// then unstyle each Node in the returned list."
-function unstyleRange(range, propertyName, propertyValue, tagList) {
- var nodeList = decomposeRange(range);
-
- for (var i = 0; i < nodeList.length; i++) {
- unstyleNode(nodeList[i], propertyName, propertyValue, tagList);
+ // "Style each member of children."
+ for (var i = 0; i < children.length; i++) {
+ styleNode(children[i], property, newValue);
}
}
function myExecCommand(commandId, showUI, value) {
commandId = commandId.toLowerCase();
- var range = activeRange(document);
+ var range = getActiveRange(document);
if (!range) {
return;
@@ -912,13 +903,17 @@
switch (commandId) {
case "bold":
- if (getState("bold", range)) {
- unstyleRange(range, "fontWeight", "normal", ["b", "strong"]);
- } else {
- styleRange(range, "fontWeight", "bold", ["b", "strong"]);
+ // "Decompose the Range. If the state of the Range for this command is
+ // then true, style each returned Node with property "font-weight" and
+ // new value "bold". Otherwise, style them with new value "normal"."
+ var nodeList = decomposeRange(range);
+ var newValue = getState("bold", range) ? "normal" : "bold";
+ for (var i = 0; i < nodeList.length; i++) {
+ styleNode(nodeList[i], "fontWeight", newValue);
}
break;
+ /*
case "createlink":
// "If value is the empty string, do nothing."
if (value === "") {
@@ -957,7 +952,7 @@
// "While ancestor link is not an HTML element, or its local
// name is not "a", or it has no HTML attribute with local name
// "href":"
- while (ancestorLink.namespaceURI != htmlNamespace
+ while (!isHtmlNamespace(ancestorLink.namespaceURI)
|| ancestorLink.nodeType != Node.ELEMENT_NODE
|| ancestorLink.tagName != "A"
|| !ancestorLink.hasAttribute("href")) {
@@ -994,22 +989,16 @@
newParent.appendChild(textNode);
}
}
-
- case "foreColor":
- // Hacky test to see if the color is valid
- var testEl = document.createElement("span");
- testEl.style.color = value;
- if (testEl.style.color === "") {
- return;
- }
- styleRange(range, "color", value, []);
- break;
+ */
case "italic":
- if (getState("italic", range)) {
- unstyleRange(range, "fontStyle", "normal", ["i", "em"]);
- } else {
- styleRange(range, "fontStyle", "italic", ["i", "em"]);
+ // "Decompose the Range. If the state of the Range for this command is
+ // then true, style each returned Node with property "font-style" and
+ // new value "italic". Otherwise, style them with new value "normal"."
+ var nodeList = decomposeRange(range);
+ var newValue = getState("italic", range) ? "normal" : "italic";
+ for (var i = 0; i < nodeList.length; i++) {
+ styleNode(nodeList[i], "fontStyle", newValue);
}
break;
@@ -1020,7 +1009,7 @@
function myQueryCommandState(commandId) {
commandId = commandId.toLowerCase();
- var range = activeRange(document);
+ var range = getActiveRange(document);
if (!range) {
return false;
@@ -1030,29 +1019,69 @@
}
function getState(commandId, range) {
- var style = getComputedStyle(beginningElement(range));
-
- switch (commandId) {
- case "bold":
- return style.fontWeight == "bold"
- || (/^[0-9]+$/.test(style.fontWeight) && style.fontWeight >= 700);
-
- case "italic":
- return style.fontStyle == "italic" || style.fontStyle == "oblique";
-
- default:
+ if (commandId != "bold"
+ && commandId != "italic") {
return false;
}
+
+ var node = range.startContainer;
+ var stop = nextNode(range.endContainer);
+
+ for (node = range.startContainer; node && node != nextNodeDescendants(range.endContainer); node = nextNode(node)) {
+ if (!isEffectivelyContained(node, range)) {
+ continue;
+ }
+
+ var element;
+ if (node.nodeType == Node.TEXT_NODE) {
+ element = node.parentNode;
+ } else {
+ element = node;
+ }
+
+ if (element.nodeType != Node.ELEMENT_NODE) {
+ continue;
+ }
+
+ var style = getComputedStyle(element);
+
+ if (commandId == "bold") {
+ // "True if every Element that is effectively contained in the
+ // Range has computed font-weight at least 700, and the parent of
+ // every Text node that is effectively contained in the Range has
+ // computed font-weight at least 700. Otherwise false."
+ if (style.fontWeight != "bold"
+ && style.fontWeight != "700"
+ && style.fontWeight != "800"
+ && style.fontWeight != "900") {
+ return false;
+ }
+ } else if (commandId == "italic") {
+ // "True if every Element that is effectively contained in the
+ // Range has computed font-style "italic" or "oblique", and the
+ // parent of every Text node that is effectively contained in the
+ // Range has computed font-style "italic" or "oblique". Otherwise
+ // false."
+ if (style.fontStyle != "italic"
+ && style.fontStyle != "oblique") {
+ return false;
+ }
+ }
+ }
+
+ return true;
}
function myQueryCommandValue(commandId) {
commandId = commandId.toLowerCase();
- var range = activeRange(document);
+ var range = getActiveRange(document);
if (!range) {
return "";
}
+ return "";
+ /*
var style = getComputedStyle(beginningElement(range));
switch (commandId) {
@@ -1081,5 +1110,5 @@
default:
return "";
- }
+ }*/
}
--- a/preprocess Tue Mar 15 22:39:50 2011 -0600
+++ b/preprocess Thu Mar 17 16:14:25 2011 -0600
@@ -6,44 +6,56 @@
# in Anolis proper.
replace = {
- "ancestor": "<span data-anolis-spec=domcore title=concept-tree-ancestor>ancestor</span>",
- "attrlocalname": "<span data-anolis-spec=domcore title=concept-attr-local-name>local name</span>",
- "attrvalue": "<span data-anolis-spec=domcore title=concept-attr-value>value</span>",
- "boundarypoint": "<span data-anolis-spec=domrange title=concept-boundary-point>boundary point</span>",
- "bpnode": "<span data-anolis-spec=domrange title=concept-boundary-point-node>node</span>",
- "bpoffset": "<span data-anolis-spec=domrange title=concept-boundary-point-offset>offset</span>",
- "bpposition": "<span data-anolis-spec=domrange title=concept-bp-position>position</span>",
- "child": "<span data-anolis-spec=domcore title=concept-tree-child>child</span>",
- "children": "<span data-anolis-spec=domcore title=concept-tree-child>children</span>",
- "collection": "<span data-anolis-spec=domcore title=concept-collection>collection</span>",
- "contained": "<span data-anolis-spec=domrange>contained</span>",
- "comment": "<code data-anolis-spec=domcore>Comment</code>",
- "contextobject": "<span data-anolis-spec=domrange>context object</span>",
- "descendant": "<span data-anolis-spec=domcore title=concept-tree-descendant>descendant</span>",
- "document": "<code data-anolis-spec=domcore>Document</code>",
- "element": "<code data-anolis-spec=domcore>Element</code>",
- "getselection": "<code data-anolis-spec=domrange title=dom-Document-getSelection>getSelection()</code>",
- "htmlnamespace": "<span data-anolis-spec=domcore>HTML namespace</span>",
- "index": "<span data-anolis-spec=domrange title=concept-indexof>index</span>",
- "localname": "<span data-anolis-spec=domcore title=concept-element-local-name>local name</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": "<code data-anolis-spec=domcore>Node</code>",
- "nodelength": "<span data-anolis-spec=domrange title=concept-node-length>length</span>",
- "ownerdocument": "<code data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code>",
- "parent": "<span data-anolis-spec=domcore title=concept-tree-parent>parent</span>",
- "partiallycontained": "<span data-anolis-spec=domrange>partially contained</span>",
- "phrasingcontent": "<span data-anolis-spec=html>phrasing content</span>",
- "presentationalhint": "<span data-anolis-spec=html title='presentational hints'>presentational hint</span>",
- "previoussibling": "<code data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code>",
- "processinginstruction": "<code data-anolis-spec=domcore>ProcessingInstruction</code>",
- "range": "<code data-anolis-spec=domrange>Range</code>",
- "rangeend": "<span data-anolis-spec=domrange title=concept-range-end>end</span>",
- "rangeroot": "<span data-anolis-spec=domrange title=concept-range-root>root</span>",
- "rangestart": "<span data-anolis-spec=domrange title=concept-range-start>start</span>",
- "selection": "<code data-anolis-spec=domrange>Selection</code>",
- "text": "<code data-anolis-spec=domcore>Text</code>",
- "treeorder": "<span data-anolis-spec=domcore>tree order</span>",
+ 'ancestor': '<span data-anolis-spec=domcore title=concept-tree-ancestor>ancestor</span>',
+ 'attrlocalname': '<span data-anolis-spec=domcore title=concept-attr-local-name>local name</span>',
+ 'attrvalue': '<span data-anolis-spec=domcore title=concept-attr-value>value</span>',
+ 'b': '<code data-anolis-spec=html title="the b element">b</code>',
+ 'boundarypoint': '<span data-anolis-spec=domrange title=concept-boundary-point>boundary point</span>',
+ 'bpnode': '<span data-anolis-spec=domrange title=concept-boundary-point-node>node</span>',
+ 'bpoffset': '<span data-anolis-spec=domrange title=concept-boundary-point-offset>offset</span>',
+ 'bpposition': '<span data-anolis-spec=domrange title=concept-bp-position>position</span>',
+ 'child': '<span data-anolis-spec=domcore title=concept-tree-child>child</span>',
+ 'children': '<span data-anolis-spec=domcore title=concept-tree-child>children</span>',
+ 'collection': '<span data-anolis-spec=domcore title=concept-collection>collection</span>',
+ 'contained': '<span data-anolis-spec=domrange>contained</span>',
+ 'comment': '<code data-anolis-spec=domcore>Comment</code>',
+ 'contextobject': '<span data-anolis-spec=domrange>context object</span>',
+ 'descendant': '<span data-anolis-spec=domcore title=concept-tree-descendant>descendant</span>',
+ 'document': '<code data-anolis-spec=domcore>Document</code>',
+ 'documentfragment': '<code data-anolis-spec=domcore>DocumentFragment</code>',
+ 'element': '<code data-anolis-spec=domcore>Element</code>',
+ 'em': '<code data-anolis-spec=html title="the em element">em</code>',
+ 'font': '<code data-anolis-spec=html title=font>font</code>',
+ 'fontcolor': '<code data-anolis-spec=html title=dom-font-color>color</code>',
+ 'fontface': '<code data-anolis-spec=html title=dom-font-face>face</code>',
+ 'fontsize': '<code data-anolis-spec=html title=dom-font-size>size</code>',
+ 'getselection': '<code data-anolis-spec=domrange title=dom-Document-getSelection>getSelection()</code>',
+ 'htmlnamespace': '<span data-anolis-spec=domcore>HTML namespace</span>',
+ 'i': '<code data-anolis-spec=html title="the i element">i</code>',
+ 'index': '<span data-anolis-spec=domrange title=concept-indexof>index</span>',
+ 'localname': '<span data-anolis-spec=domcore title=concept-element-local-name>local name</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': '<code data-anolis-spec=domcore>Node</code>',
+ 'nodelength': '<span data-anolis-spec=domrange title=concept-node-length>length</span>',
+ 'ownerdocument': '<code data-anolis-spec=domcore title=dom-Node-ownerDocument>ownerDocument</code>',
+ 'parent': '<span data-anolis-spec=domcore title=concept-tree-parent>parent</span>',
+ 'partiallycontained': '<span data-anolis-spec=domrange>partially contained</span>',
+ 'phrasingcontent': '<span data-anolis-spec=html>phrasing content</span>',
+ 'presentationalhint': '<span data-anolis-spec=html title="presentational hints">presentational hint</span>',
+ 'previoussibling': '<code data-anolis-spec=domcore title=dom-Node-previousSibling>previousSibling</code>',
+ 'processinginstruction': '<code data-anolis-spec=domcore>ProcessingInstruction</code>',
+ 'range': '<code data-anolis-spec=domrange>Range</code>',
+ 'rangeend': '<span data-anolis-spec=domrange title=concept-range-end>end</span>',
+ 'rangeroot': '<span data-anolis-spec=domrange title=concept-range-root>root</span>',
+ 'rangestart': '<span data-anolis-spec=domrange title=concept-range-start>start</span>',
+ 'selection': '<code data-anolis-spec=domrange>Selection</code>',
+ 'span': '<code data-anolis-spec=html title="the span element">span</code>',
+ 'strong': '<code data-anolis-spec=html title="the strong element">strong</code>',
+ 'style': '<code data-anolis-spec=html title="the style attribute">style</code>',
+ 'text': '<code data-anolis-spec=domcore>Text</code>',
+ 'treeorder': '<span data-anolis-spec=domcore>tree order</span>',
+ 'u': '<code data-anolis-spec=html title="the u element">u</code>',
}
s = open("source.html", "r").read()
@@ -60,3 +72,4 @@
f = open("intermediate.html", "w")
f.write(s)
f.close()
+# vim: set textwidth=0:
--- a/source.html Tue Mar 15 22:39:50 2011 -0600
+++ b/source.html Thu Mar 17 16:14:25 2011 -0600
@@ -23,6 +23,7 @@
white-space: pre-wrap;
}
div.note > p:first-child::before { content: 'Note: '; }
+ div + * > li { margin: 1em 0 }
</style>
<body class=draft>
<div class=head id=head>
@@ -66,6 +67,57 @@
major preexisting rendering engines are known not to match it, the reasoning is
included in HTML comments so as not to distract the reader.
+<p>The principles I've used for writing this specification so far are:
+
+<ul>
+ <li>If all browsers that implement a particular feature agree on some detail
+ of how it works, match them unless there's very good reason not to. When
+ it's not clear what behavior is best, try to follow the implementations with
+ the most market share. But if one browser's behavior is clearly better than
+ the others', go with the better behavior.
+
+ <li>If a command is issued to format some text in a particular way, we will
+ format the text that way no matter what. If the user clicks the "bold"
+ button, they don't care that the text didn't become bold because of an
+ external CSS rule or for any other reason, they only care that it didn't
+ work. The only exception (beyond where it's simply impossible, like
+ propagated text-decorations we can't remove) is that we don't try to override
+ !important rules from external stylesheets, although we also don't go out of
+ our way to respect them.
+
+ <li>When we're given a presentational command like "bold", don't modify
+ anything other than presentational markup related to that command. If an
+ element has non-presentational attributes like id or class, don't split it up
+ or remove it or anything. At most convert it to a span, if it's some type of
+ presentational element (where "presentational" here really means "browsers
+ produce it in response to execCommand() so we need to treat it as
+ presentational", so it includes things like [[strong]] and [[em]]).
+
+ <li>Don't interfere with more markup than necessary. If the user modifies
+ only a small run of text, don't go around simplifying ancestors or siblings
+ or whatever unless it's necessary to produce simpler markup in the place that
+ was actually modified.
+
+ <li>But if we are already changing around something's style, convert existing
+ styles to the preferred format. For instance, we use [[b]] for bold, and
+ convert [[strong]] and <[[span]] [[style]]="font-weight: bold"> if we
+ happen to be modifying that node anyway.
+
+ <li>Don't make the document less conforming than it originally was. If we
+ happen to make it more conforming, good, although we don't have to go out of
+ our way to do that. (In the future, I'll add a mode that supports using
+ obsolete presentational elements instead of CSS for the sake of e-mail
+ clients and such, and this rule will be bent in that mode.)
+
+ <li>Keep the markup as concise as possible. (I've received feedback that
+ this is very important to authors.) Ideally, the markup should look as
+ simple and neat as what a human would have produced by hand-editing. We do
+ complicated manipulation to pull styles down from ancestors rather than
+ having to use inline CSS, and make sure to tidy up any styles on elements
+ that we happen to be modifying anyway. Previous principles take precedence
+ over this one, however.
+</ul>
+
<h2>Issues</h2>
@@ -113,27 +165,16 @@
<span data-anolis-spec=domcore title=concept-attr-namespace>namespace</span> is
the [[htmlnamespace]].
-<p>The <dfn>beginning element</dfn> of a [[range]] is returned by the following
-algorithm:
-
-<ol>
- <li>If the [[rangestart]] [[bpnode]] of the [[range]] is a [[text]],
- [[comment]], or [[processinginstruction]] node, and the [[rangestart]]
- [[bpoffset]] of the [[range]] is not equal to the [[nodelength]] of its
- [[rangestart]] [[bpnode]], let <var>first node</var> be the [[range]]'s
- [[rangestart]] [[bpnode]].
+<p>A [[node]] is <dfn>effectively contained</dfn> in a [[range]] if either it
+is [[contained]] in the [[range]]; or it is the [[range]]'s [[rangestart]]
+[[bpnode]], it is a [[text]] node, and its [[nodelength]] is different from the
+[[range]]'s [[rangestart]] [[bpoffset]]; or it is the [[range]]'s [[rangeend]]
+[[bpnode]], it is a [[text]] node, and the [[range]]'s [[rangeend]]
+[[bpoffset]] is not 0.
- <li>Otherwise, let <var>first node</var> be the first [[node]] in
- [[treeorder]] that is [[contained]] in the [[range]], if there is any.
-
- <li>If <var>first node</var> is defined and is an [[element]], return
- <var>first node</var>.
-
- <li>Otherwise, if <var>first node</var> is defined and its [[parent]] is an
- [[element]], return <var>first node</var>'s [[parent]].
-
- <li>Return null.
-</ol>
+<p class=note>A node is <span>effectively contained</span> in a range if and
+only if it would be [[contained]] after the range is <span
+title=decompose>decomposed</span>.
<p>The <dfn>active range</dfn> of a [[document]] is the value returned by the
following algorithm:
@@ -157,108 +198,77 @@
[[selection]], the active range is simply the only one in the selection.
</ol>
-<p>Given a CSS property name <var>property name</var>, an (optional) value
-<var>property value</var> for that property, and a possibly empty list of
-strings <var>tag list</var>, a [[node]] is a <dfn>potentially relevant styling
-element</dfn> if it is an <span>HTML element</span> and one of the following
-holds:
-
-<ul>
- <li>Its [[localname]] is in <var>tag list</var> and it has no attributes.
-
- <li>Its [[localname]] is in <var>tag list</var> or is "span" or is "font",
- and it has exactly one attribute, and that attribute is an <span>HTML
- attribute</span> with [[attrlocalname]] "style", and that attribute sets
- exactly one CSS property, and that property is <var>property name</var>, and
- either <var>property value</var> is undefined or the value the attribute sets
- the property to is <var>property value</var>.
-
- <li>Its [[localname]] is "font", and it has exactly one attribute, and that
- attribute is a <code data-anolis-spec=html title=dom-font-color>color</code>
- attribute, and either <var>property value</var> is undefined or the effect of
- the attribute is to hint that the CSS color attribute be set to <var>property
- value</var>, and <var>property name</var> is "color".
-
- <li>Its [[localname]] is "font", and it has exactly one attribute, and that
- attribute is a <code data-anolis-spec=html title=dom-font-face>face</code>
- attribute, and either <var>property value</var> is undefined or the effect of
- the attribute is to hint that the CSS font-family attribute be set to
- <var>property value</var>, and <var>property name</var> is "font-family".
+<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).
- <li>Its [[localname]] is "font", and it has exactly one attribute, and that
- attribute is a <code data-anolis-spec=html title=dom-font-size>size</code>
- attribute, and either <var>property value</var> is undefined or the effect of
- the attribute is to hint that the CSS font-size attribute be set to
- <var>property value</var>, and <var>property name</var> is "font-size".
-
- <!-- Should we bother handling <font color=red style=color:red>? Let's not.
- -->
-</ul>
-
-<p>A [[node]] is a <dfn>relevant styling element</dfn> if it is a
-<span>potentially relevant styling element</span>, and its CSS property
-<var>property name</var> computes to <var>property value</var> (which cannot be
-undefined).
-
-<div class=note>
-<p>If <var>property name</var> is "font-weight", <var>property value</var> is
-"bold", and <var>tag list</var> contains "b", an example of a <span>potentially
-relevant styling element</span> that is not actually <span title="relevant
-styling element">relevant</span> is
-
-<xmp><p style="font-weight: 100"><b>Foo</b></p></xmp>
-
-<p>Since <code data-anolis-spec=html title="the b element">b</code>'s default
-font-weight is "bolder", the computed font-weight will most likely end up being
-"normal" or lighter.
-</div>
-
-<p>A <dfn>phrasing element</dfn> is either an <span>HTML element</span> that is
-categorized as [[phrasingcontent]], or a <span data-anolis-spec=html
-title="non-conforming element">non-conforming</span> <span>HTML element</span>
-(which thus has no categories), or an [[element]] that is not an <span>HTML
-element</span>.
-
-<p class=XXX>We should allow unrecognized HTML elements too.
-
-<p>The <dfn>specified style</dfn> of an [[element]] for a given <var>property
-name</var> is returned by the following algorithm, which will return either a
-CSS value or null:
+<p>The <dfn>specified style</dfn> of an [[element]] for a given
+<var>property</var> is returned by the following algorithm, which will return
+either a CSS value or null:
<ol>
<li>If the [[element]] has a <code data-anolis-spec=html
title="the style attribute">style</code> attribute set, and that attribute has
- the effect of setting <var>property name</var>, return the value that it sets
- <var>property name</var> to.
+ the effect of setting <var>property</var>, return the value that it sets
+ <var>property</var> to.
<li>If the [[element]] is a <code data-anolis-spec=html>font</code> element
that has an attribute whose effect is to create a [[presentationalhint]] for
- <var>property name</var>, return the value that the hint sets <var>property
- name</var> to.
+ <var>property</var>, return the value that the hint sets <var>property</var>
+ to.
- <li>If the [[element]] is in the following list, and <var>property name</var>
- is equal to the CSS property name listed for it, return the string listed for
+ <li>If the [[element]] is in the following list, and <var>property</var> is
+ equal to the CSS property name listed for it, return the string listed for
it.
- <p class=XXX>Add any other elements that can be output by the style/unstyle
- algorithms, or existing browser implementations of execCommand().
-
<dl class=switch>
- <dt><code data-anolis-spec=html title="the b element">b</code>
- <dt><code data-anolis-spec=html title="the strong element">strong</code>
+ <dt>[[b]]
+ <dt>[[strong]]
<dd>font-weight: "bold"
- <dt><code data-anolis-spec=html title="the i element">i</code>
- <dt><code data-anolis-spec=html title="the em element">em</code>
+ <dt>[[i]]
+ <dt>[[em]]
<dd>font-style: "italic"
- <dt><code data-anolis-spec=html title="the u element">u</code>
+ <dt>[[u]]
<dd>text-decoration: "underline"
</dl>
<li>Return null.
</ol>
+<p>A <dfn>simple styling element</dfn> is an <span>HTML element</span> for
+which at least one of the following holds:
+
+<ol>
+ <li>It is a [[b]], [[em]], [[font]], [[i]], [[span]], [[strong]], or [[u]]
+ element with no attributes.
+
+ <li>It is a [[b]], [[em]], [[font]], [[i]], [[span]], [[strong]], or [[u]]
+ 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
+ [[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 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 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 [[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>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
though the method had actually been called from JavaScript. In particular,
@@ -272,8 +282,8 @@
sequentially in the list's order.
-<h2>Decomposing a Range into Nodes</h2>
-<p>When a user agent is to <dfn>decompose a [[range]]</dfn> <var>range</var>,
+<h2>Decomposing a range into nodes</h2>
+<p>When a user agent is to <dfn>decompose</dfn> a [[range]] <var>range</var>,
it must run the following steps.
<ol>
@@ -331,9 +341,26 @@
<var>start offset</var>) and its [[rangeend]] to (<var>end node</var>,
<var>end offset</var>).
- <li>Return a list consisting of every [[node]] [[contained]] in
- <var>range</var> in [[treeorder]], omitting any whose [[parent]] is also
- [[contained]] in <var>range</var>.
+ <!-- Now we want to make sure our range contains as many nodes as possible,
+ such as by changing <tag>[foo]</tag> to {<tag>foo</tag>}. -->
+ <li>Let <var>cloned range</var> be the result of calling <code
+ data-anolis-spec=domrange title=dom-Range-cloneRange>cloneRange()</code> on
+ <var>range</var>.
+
+ <li>While the [[rangestart]] [[bpoffset]] of <var>cloned range</var> is 0,
+ and the [[parent]] of <var>cloned range</var>'s [[rangestart]] [[bpnode]] is
+ not null, set the [[rangestart]] of <var>cloned range</var> to ([[parent]] of
+ [[rangestart]] [[bpnode]], [[index]] of [[rangestart]] [[bpnode]]).
+
+ <li>While the [[rangeend]] [[bpoffset]] of <var>cloned range</var> equals the
+ [[nodelength]] of its [[rangeend]] [[bpnode]], and the [[parent]] of
+ <var>clone range</var>'s [[rangeend]] [[bpnode]] is not null, set the
+ [[rangeend]] of <var>cloned range</var> to ([[parent]] of [[rangeend]]
+ [[bpnode]], 1 + [[index]] of [[rangeend]] [[bpnode]]).
+
+ <li>Return a list consisting of every [[node]] [[contained]] in <var>cloned
+ range</var> in [[treeorder]], omitting any whose [[parent]] is also
+ [[contained]] in <var>cloned range</var>.
</ol>
@@ -341,27 +368,22 @@
<p>When a user agent is to <dfn>clear styles</dfn> on an element, it must run
the following steps:
-<div class=note>
-<p>Clearing styles (<span title="recursively clear styles">recursively</span>
-or not) can remove it from its parent and put other nodes in its place. When
-implementations do something like clear style on all children of an element,
-they should take care not to assume that the set of children won't change as
-they're unstyled. If the element is removed, the algorithm will return the
-list of nodes inserted in its place.
+<p class=note>Clearing styles can remove it from its parent and put other nodes
+in its place. When implementations do something like clear style on all
+children of an element, they should take care not to assume that the set of
+children won't change as they're unstyled. If the element is removed, the
+algorithm will return the list of nodes inserted in its place.
-<p>Clearing styles only removes inline styles from the element. It doesn't
-ensure that the element isn't inheriting styles from an ancestor (or a style
-rule). For that, one must <span>unstyle a node</span>.
-</div>
+<p class=XXX>This should probably convert, e.g., <font color=red id=foo>
+into <span id=foo> instead of <font id=foo>.
<ol>
<li>Let <var>element</var> be the [[element]] to be unstyled.
- <li>Let <var>property name</var> and <var>tag list</var> be as
- in the invoking algorithm.
+ <li>Let <var>property</var> be as in the invoking algorithm.
- <li>If <var>element</var> is a <span>potentially relevant styling
- element</span>:
+ <li>If <var>element</var> is a <span>simple styling element</span> and its
+ <span>specified style</span> for <var>property</var> is not null:
<ol>
<li>Let <var>children</var> be an empty list of [[node]]s.
@@ -377,32 +399,32 @@
<var>element</var>.
</ol>
- <li>Remove <var>element</var>.
+ <li>Remove <var>element</var> from its [[parent]].
<li>Return <var>children</var>.
</ol>
- <li>Unset the CSS property <var>property name</var> of <var>element</var>.
+ <li>Unset the CSS property <var>property</var> of <var>element</var>.
<li>If <var>element</var> is a <code data-anolis-spec=html>font</code>
element:
<ol>
- <li>If <var>property name</var> is "color", unset <var>element</var>'s
+ <li>If <var>property</var> is "color", unset <var>element</var>'s
<code data-anolis-spec=html title=dom-font-color>color</code> attribute, if
set.
- <li>If <var>property name</var> is "font-family", unset
+ <li>If <var>property</var> is "font-family", unset
<var>element</var>'s <code data-anolis-spec=html
title=dom-font-face>face</code> attribute, if set.
- <li>If <var>property name</var> is "font-size", unset <var>element</var>'s
+ <li>If <var>property</var> is "font-size", unset <var>element</var>'s
<code data-anolis-spec=html title=dom-font-size>size</code> attribute, if
set.
</ol>
- <li>If <var>element</var> is not an <span>HTML element</span> or its
- [[localname]] is not in <var>tag list</var>, return the empty list.
+ <li>If <var>element</var>'s <var>specified style</var> 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. -->
@@ -416,198 +438,49 @@
<li>While <var>element</var> has children, append its first child
as the last child of <var>new element</var>.
- <li>Remove <var>element</var>.
+ <li>Remove <var>element</var> from its [[parent]].
<li>Return the one-[[node]] list consisting of <var>new element</var>.
</ol>
-<h2>Recursively clearing an element's styles</h2>
-<p>When a user agent is to <dfn>recursively clear styles</dfn> on an element,
-it must run the following steps:
-
-<ol>
- <li>Let <var>element</var> be the [[element]] to be unstyled.
-
- <li>Let <var>property name</var> and <var>tag list</var> be as
- in the invoking algorithm.
-
- <li>Let <var>element children</var> be the [[element]] children of
- <var>element</var>.
-
- <li><span>Recursively clear styles</span> on each [[element]] in <var>element
- children</var>.
-
- <li><span>Clear styles</span> on <var>element</var>, and return the resulting
- list.
-</ol>
-
-
-<h2>Styling a Node</h2>
-<p>When a user agent is to <dfn>style a [[node]]</dfn> <var>node</var>, it must
-run the following steps. There are three inputs: a CSS property name
-<var>property name</var>, a new value <var>property value</var>, and a possibly
-empty list of strings <var>tag list</var>.
-
-<p class=note>This algorithm applies the given style to the node itself, but
-doesn't interfere with conflicting styles on its descendants. <span
-title="recursively style a node">Recursive styling</span> removes conflicting
-styles from descendants first.
+<h2>Pushing down styles</h2>
+<p>When a user agent is to <dfn>push down styles</dfn> to a [[node]]
+<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:
<ol>
- <li>If <var>node</var>'s [[parent]] is null, or if <var>node</var> is not an
- [[element]], [[text]], [[comment]], or [[processinginstruction]] node, abort
- this algorithm. <!-- XXX: What to do here? -->
-
- <li>If <var>node</var> is an [[element]]:
-
- <ol>
- <li><span>Clear styles</span> on <var>node</var>, and let <var>new
- nodes</var> be the result.
-
- <li>For each <var>new node</var> in <var>new nodes</var>, <span
- title="style a node">style <var>new node</var></span>, with the same inputs
- as this invocation of the algorithm.
-
- <li>If <var>node</var>'s [[parent]] is null, abort this algorithm.
- </ol>
-
- <li>If <var>node</var> is an [[element]] but not a <span>phrasing
- element</span>:
+ <li>If <var>node</var>'s [[parent]] is not an [[element]], abort this
+ algorithm. <!-- E.g., a text node child of a document fragment. -->
- <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 name</var> is neither null nor equal to <var>property
- value</var>.
-
- <li><span title="style a node">Style</span> each [[node]] in
- <var>children</var>.
-
- <li>Abort this algorithm.
- </ol>
+ <li>If <var>node</var> is an [[element]] and <var>property</var> computes to
+ <var>new value</var> on <var>node</var>, abort this algorithm.
- <li>If <var>node</var>'s [[previoussibling]] is a <span>relevant styling
- element</span>, append <var>node</var> as the last [[child]] of its
- [[previoussibling]] and abort this algorithm.
-
- <li>If <var>node</var>'s [[nextsibling]] is a <span>relevant styling
- element</span>, insert <var>node</var> as the first [[child]] of its
- [[nextsibling]] and abort this algorithm.
-
- <li>If <var>node</var> is a [[comment]] or [[processinginstruction]], abort
- this algorithm. <!-- There's no point in making a new element in this case.
- -->
-
- <li>If <var>node</var> is an [[element]] and the computed style of
- <var>property name</var> for it is <var>property value</var>, abort this
+ <li>If <var>node</var> is not an [[element]] and <var>property</var> computes
+ to <var>new value</var> on <var>node</var>'s [[parent]], abort this
algorithm.
- <li>If <var>node</var> is a [[text]] node and the computed style of
- <var>property name</var> for its [[parent]] is <var>property value</var>,
- abort this algorithm.
-
- <li>Let <var>tag</var> be the first string in <var>tag list</var>, if that is
- not empty, or "span" if it is empty.
-
- <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
- [[ownerdocument]] of <var>node</var>.
-
- <li>Insert <var>new parent</var> in <var>node</var>'s [[parent]] before
- <var>node</var>.
-
- <li>If the computed value of <var>property name</var> for <var>new
- parent</var> is not <var>property value</var>, set the CSS property
- <var>property name</var> of <var>new parent</var> to <var>property
- value</var>.
-
- <li>Append <var>node</var> to <var>new parent</var> as its last [[child]].
-</ol>
-
-
-<h2>Recursively styling a Node</h2>
-<p>When a user agent is to <dfn>recursively style a [[node]]</dfn>
-<var>node</var>, it must run the following steps. There are three inputs: a
-CSS property name <var>property name</var>, a new value <var>property
-value</var>, and a possibly empty list of strings <var>tag list</var>.
-
-<ol>
- <li>If <var>node</var>'s [[parent]] is null, or if <var>node</var> is not an
- [[element]], [[text]], [[comment]], or [[processinginstruction]] node, abort
- this algorithm. <!-- XXX: What to do here? -->
-
- <li>If <var>node</var> is an [[element]]:
-
- <ol>
- <li><span>Recursively clear styles</span> on <var>node</var>, and let
- <var>new nodes</var> be the result.
-
- <li>For each <var>new node</var> in <var>new nodes</var>, <span
- title="recursively style a node">recursively style <var>new
- node</var></span>, with the same inputs as this invocation of the
- algorithm.
-
- <li>If <var>node</var>'s [[parent]] is null, abort this algorithm.
- </ol>
-
- <li><span title="style a node">Style</span> <var>node</var>.
-</ol>
-
-
-<h2>Styling a Range</h2>
-<p>When a user agent is to <dfn>style a [[range]]</dfn>, it must <span
-title="decompose a range">decompose</span> the [[range]], then <span
-title="recursively style a node">recursively style</span> each [[node]] in the
-returned list.
-
-
-<h2>Unstyling a Node</h2>
-<p>When a user agent is to <dfn>unstyle a [[node]]</dfn> <var>node</var>, it
-must run the following steps. There are three inputs: a CSS property name
-<var>property name</var>, a new value <var>new value</var>, and a possibly
-empty list of strings <var>tag list</var>.
-
-<ol>
- <li>If <var>node</var>'s [[parent]] is null, or if <var>node</var> is not an
- [[element]] or [[text]] node, abort this algorithm. <!-- XXX: What to do
- here? We want to ignore comments and PIs, but we might want to support
- detached elements, documents, document fragments, . . . -->
-
- <li>If <var>node</var> is an [[element]]:
-
- <ol>
- <li><span>Recursively clear styles</span> on <var>node</var>, and let
- <var>new nodes</var> be the result.
-
- <li>For each <var>new node</var> in <var>new nodes</var>, <span
- title="unstyle a node">unstyle <var>new node</var></span>, with the same
- inputs as this invocation of the algorithm.
-
- <li>If <var>node</var>'s [[parent]] is null, abort this algorithm.
- </ol>
-
- <li>If <var>node</var> is an [[element]], let <var>current value</var> equal
- the computed value of <var>property name</var> on <var>node</var>.
- Otherwise, let <var>current value</var> equal the computed value of
- <var>property name</var> on <var>node</var>'s [[parent]].
-
- <li>If <var>current value</var> equals <var>new value</var>, abort this
- algorithm.
+ <li>Let <var>current ancestor</var> be <var>node</var>'s [[parent]].
<li>Let <var>ancestor list</var> be a list of [[node]]s, initially empty.
- <li>Let <var>current ancestor</var> equal <var>node</var>.
+ <li>While <var>current ancestor</var> is an [[element]] and
+ <var>property</var> does not compute 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>While <var>current ancestor</var>'s [[parent]] is an [[element]], set
- <var>current ancestor</var> to its [[parent]], then append it to
- <var>ancestor list</var>.
-
- <li>While <var>ancestor list</var> is not empty, and the last member of
- <var>ancestor list</var> has <span>specified style</span> for <var>property
- name</var> equal to <var>new value</var> or null, remove the last member from
- <var>ancestor list</var>.
+ <!-- We can only remove specified styles, so if the style isn't specified,
+ give up. -->
+ <li>If <var>ancestor list</var> is not empty, and the <span>specified
+ style</span> of <var>property</var> on the last member of <var>ancestor
+ list</var> is null, abort this algorithm.
+
+ <!-- If we go all the way up to the root and still don't have the desired
+ style, pushing down styles is pointless. It will create extra markup for no
+ purpose. -->
+ <li>If <var>ancestor list</var> is not empty, and the [[parent]] of the last
+ member of <var>ancestor list</var> is not an [[element]], abort this
+ algorithm.
<li>While <var>ancestor list</var> is not empty:
@@ -618,7 +491,7 @@
<li>Remove the last member from <var>ancestor list</var>.
<li>Let <var>propagated value</var> be the <span>specified style</span> of
- <var>current ancestor</var> for <var>property name</var>.
+ <var>current ancestor</var> for <var>property</var>.
<li>If <var>propagated value</var> is null, continue this loop from the
beginning.
@@ -635,53 +508,223 @@
<var>child</var>.
<li>If <var>child</var> is an [[element]] whose <span>specified
- style</span> for <var>property name</var> is neither null nor equal to
+ style</span> for <var>property</var> is neither null nor equal to
<var>propagated value</var>, continue with the next <var>child</var>.
<li>If <var>child</var> is the last member of <var>ancestor list</var>,
- set <var>child</var>'s CSS property <var>property name</var> to
+ set <var>child</var>'s CSS property <var>property</var> to
<var>propagated value</var> and continue with the next <var>child</var>.
<p class=note>This style will be removed on the next loop iteration and
distributed to its children.
- <li><span title="style a node">Style</span> <var>child</var>, with
- <var>property name</var> and <var>tag list</var> as in this algorithm,
- and <var>property value</var> equal to <var>propagated value</var>.
+ <li><span>Force the style</span> of <var>child</var>, with
+ <var>property</var> as in this algorithm and <var>new value</var> equal
+ to <var>propagated value</var>.
</ol>
</ol>
-
- <!-- We might have a rule inherited from someplace where we can't remove it,
- or maybe even a rule in a stylesheet (although that case is pathological and
- we generally ignore it) -->
- <li>If <var>node</var> is an [[element]] and <var>property name</var> does
- not compute to <var>new value</var> on it, set <var>property name</var> to
- <var>new value</var> on it.
-
- <li>If <var>node</var> is a [[text]] node and <var>property name</var> does
- not compute to <var>new value</var> on its [[parent]]:
-
- <ol>
- <li>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>Set <var>property name</var> to <var>new value</var> on <var>new
- parent</var>.
-
- <li>Insert <var>new parent</var> into <var>node</var>'s [[parent]] before
- <var>node</var>.
-
- <li>Append <var>node</var> as the last [[child]] of <var>new parent</var>.
- </ol>
</ol>
-<h2>Unstyling a Range</h2>
-<p>When a user agent is to <dfn>unstyle a [[range]]</dfn> <var>range</var>, it
-must <span title="decompose a range">decompose</span> the [[range]], then <span
-title="unstyle a node">unstyle</span> each [[node]] in the returned list.
+<h2>Forcing the style of a node</h2>
+<p>When a user agent is to <dfn>force the style</dfn> of a [[node]]
+<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.
+
+<p class=note>This algorithm checks if the node has the desired style, and if
+not, it wraps the node (or, if that's not possible, its descendants) in a
+<span>simple styling element</span>. This is only used as a last resort after
+<span title="clear styles">clearing styles</span> and <span title="push down
+styles">pushing down styles</span> don't work to achieve the desired style.
+After forcing the style, descendants might still have different style.
+
+<ol>
+ <li>If <var>node</var> is an [[element]] and <var>property</var> computes to
+ <var>new value</var> on <var>node</var>, abort this algorithm.
+
+ <li>If <var>node</var> is not an [[element]], <var>node</var>'s [[parent]] is
+ an [[element]], and <var>property</var> computes to <var>new value</var> on
+ <var>node</var>'s [[parent]], abort this algorithm.
+
+ <li>If <var>node</var> is an <span>unwrappable element</span>:
+
+ <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.
+
+ <li>Abort this algorithm.
+ </ol>
+
+ <li>If <var>node</var>'s [[previoussibling]] 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>, append <var>node</var> as
+ the last [[child]] of its [[previoussibling]] and abort this algorithm.
+
+ <li>If <var>node</var>'s [[nextsibling]] 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>, insert <var>node</var> as
+ the first [[child]] of its [[nextsibling]] and abort this algorithm.
+
+ <!-- At this point we have to make a new element as a wrapper. This isn't
+ worth the effort for comments or PIs, so abort in that case. -->
+ <li>If <var>node</var> is a [[comment]] or [[processinginstruction]], abort
+ this algorithm.
+
+ <li>If <var>node</var> is an [[element]] and <var>property</var> computes to
+ <var>new value</var> on <var>node</var>, abort this algorithm.
+
+ <li>If <var>node</var> is not an [[element]], <var>node</var>'s [[parent]] is
+ an [[element]], and <var>property</var> computes to <var>new value</var> on
+ <var>node</var>'s [[parent]], 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>If <var>property</var> is "text-decoration" and <var>new value</var> is
+ "underline", let <var>tag</var> be "u".
+
+ <li>If <var>tag</var> is not set, let <var>tag</var> be "span".
+
+ <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
+ [[ownerdocument]] of <var>node</var>.
+
+ <li>Insert <var>new parent</var> in <var>node</var>'s [[parent]] before
+ <var>node</var>.
+
+ <li>If the computed value of <var>property</var> for <var>new parent</var> is
+ not <var>new value</var>, set the CSS property <var>property</var> of
+ <var>new parent</var> to <var>new value</var>.
+
+ <li>Append <var>node</var> to <var>new parent</var> as its last [[child]].
+
+ <li>If <var>node</var> is an [[element]] and the computed value of
+ <var>property</var> for <var>node</var> is not <var>new value</var>, set the
+ CSS property <var>property</var> of <var>node</var> to <var>new value</var>.
+</ol>
+
+
+<h2>Styling a node</h2>
+<p>When a user agent is to <dfn>style</dfn> a [[node]] <var>node</var>, it must
+run the following steps. There are two inputs: a CSS property name
+<var>property</var> and a new value <var>new value</var>.
+
+<div class=note>
+<p>The effect of this algorithm is to ensure that the node and all its
+descendants have the style requested, no matter what, producing the simplest
+markup possible to achieve that effect. It's inspired by the approach WebKit
+takes. The only places where the algorithm should fail are when there's an
+!important CSS rule that conflicts with the requested style (which we don't try
+to override because we assume it's !important for a reason), or when it's
+literally impossible to succeed (such as when a text-decoration is propagated
+from an ancestor we can't reach). Any other failures are bugs.
+
+<p>First, if the node is an element with an inline style rule for this
+property, we unset it ("clearing styles"). This step also removes <span
+title="simple styling element">simple styling elements</span> entirely, and
+replaces elements like [[b]] or [[font]] with [[span]]s if they aren't simple
+styling elements. This will be sufficient if the desired style is inherited
+from an ancestor, or if it's the default (like font-style: normal) and no
+conflicting style is inherited from an ancestor. Even if clearing styles
+doesn't actually fix the style of the node we're dealing with, we do it anyway
+to simplify the generated markup.
+
+<p>If clearing styles didn't work, and it looks like an ancestor has inline
+style that we're inheriting, we push the style down from that ancestor. Thus
+if we're unbolding the letter "r" in
+
+<xmp><b>foo <i>bar</i> baz</b>,</xmp>
+
+<p>we get
+
+<xmp><b>foo </b><i><b>ba</b>r</i><b> baz</b>.</xmp>
+
+<p>If we didn't push down styles, the final step (forcing styles) would instead
+give us
+
+<xmp><b>foo <i>ba<span style="font-weight: normal">r</span></i> baz</b>,</xmp>
+
+<p>which is much longer and uglier. We take care not to disturb the style or
+semantics of anything but the node we're dealing with.
+
+<p>We'll only push down styles if some ancestor actually has the style we want,
+so we can inherit it. Otherwise, it will just create useless markup.
+
+<p>Finally, if neither of the above strategies worked, we have to add new
+markup to get the desired style ("forcing styles"). First we try just sticking
+it into its previous or next sibling, if that's a <span>simple styling
+element</span> (so it won't add any styles or semantics we don't want).
+Otherwise, we create a new simple styling element and wrap it in that. It's
+common that a previous sibling is the simple styling element we want, because
+often we'll style several consecutive siblings in succession. In that case,
+the element created for the first can be reused for the later ones.
+
+<p>This last step works a bit differently if the node is an <span>unwrappable
+element</span>. In that case, wrapping it in a simple styling element would
+make the document less conforming than it already was. Instead, we recursively
+force style on its children. The recursion will terminate when we hit a node
+that's wrappable, or when there are no further descendants.
+
+<p>After all this, the node is guaranteed to have the style we want, barring
+bugs in the algorithm or the two exceptions noted earlier (!important style
+rules, and impossible cases). We then re-run the algorithm on each child
+recursively. Typically this means just clearing the style of each descendant,
+because it should then inherit the style we just set on its ancestor. In the
+unusual case that a descendant's style is wrong even after we clear style on
+it, such as because of a non-inline style rule (like trying to unbold a
+heading), we'll repeat the above steps to ensure that the style really gets set
+as desired.
+</div>
+
+<ol>
+ <li>If <var>node</var> is a [[document]], <span>style</span> its [[element]]
+ [[child]] (if it has one) and abort this algorithm.
+
+ <li>If <var>node</var> is a [[documentfragment]], let <var>children</var> be
+ a list of its [[children]]. <span>Style</span> each member of [[children]],
+ then abort this algorithm.
+
+ <li>If <var>node</var>'s [[parent]] is null, or if <var>node</var> is a <code
+ data-anolis-spec=domcore>DocumentType</code>, abort this algorithm.
+
+ <p class=XXX>We could style detached elements, but maybe it's not worth the
+ effort. Is execCommand() even supposed to work on things that don't descend
+ from a document? Needs investigation.
+
+ <li>If <var>node</var> is an [[element]]:
+
+ <ol>
+ <li><span>Clear styles</span> on <var>node</var>, and let <var>new
+ nodes</var> be the result.
+
+ <li>For each <var>new node</var> in <var>new nodes</var>,
+ <span>style</span> <var>new node</var>, with the same inputs as this
+ invocation of the algorithm.
+
+ <li>If <var>node</var>'s [[parent]] is null, abort this algorithm.
+ </ol>
+
+ <li><span>Push down styles</span> on <var>node</var>.
+
+ <li><span>Force the style</span> of <var>node</var>.
+
+ <li>Let <var>children</var> be the [[children]] of <var>node</var>.
+
+ <li><span>Style</span> each member of [[children]].
+
+ <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
+ children in full before they begin styling.
+</ol>
<h2>Commands</h2>
@@ -737,10 +780,10 @@
<dt><code title><dfn title=command-backColor>backColor</dfn></code>
<dd><p><strong>Action</strong>: If <var>value</var> is not a valid CSS color,
-the user agent must do nothing and abort these steps. Otherwise, it must <span
-title="style a range">style the [[range]]</span> with <var>property name</var>
-equal to "background-color", <var>property value</var> equal to
-<var>value</var>, and <var>tag list</var> equal to the empty list.
+the user agent must do nothing and abort these steps. Otherwise, it must
+<span>decompose</span> the [[range]], then <span>style</span> each returned
+[[node]] with <var>property</var> equal to "background-color" and <var>new
+value</var> equal to <var>value</var>.
<!-- Firefox documentation says it normally sets the background color of the
document, but I can't get it to work at all in brief testing in 4b11. (It says
it behaves differently in styleWithCss mode.) Opera 11 appears to set the
@@ -767,8 +810,7 @@
<dd><p><strong>Value</strong>: The value is given by the following algorithm:
<ol>
- <li>Let <var>element</var> be the <span>beginning element</span> of the
- [[range]].
+ <li class=XXX>...
<li>While the computed style of "background-color" on <var>element</var>
is any fully transparent value, set <var>element</var> to its parent.
@@ -788,16 +830,17 @@
<dt><code title><dfn title=command-bold>bold</dfn></code>
-<dd><p><strong>Action</strong>: If the state of the [[range]] for this command
-is false, the user agent must <span title="style a range">style the
-[[range]]</span> with <var>property name</var> "font-weight", <var>property
-value</var> "bold", and <var>tag list</var> ["b", "strong"]. Otherwise, it
-must <span title="unstyle a range">unstyle it</span> with <var>property
-name</var> "font-weight", <var>property value</var> "normal", and <var>tag
-list</var> ["b", "strong"].
+<dd><p><strong>Action</strong>: <span>Decompose</span> the [[range]]. If the
+state of the [[range]] for this command is then true, <span>style</span> each
+returned [[node]] with <var>property</var> "font-weight" and <var>new
+value</var> "bold". Otherwise, <span>style</span> them with <var>new
+value</var> "normal".
-<dd><p><strong>State</strong>: True if the <span>beginning element</span> of the
-[[range]] has font-weight with computed value less than 700, otherwise false.
+<dd><p><strong>State</strong>: True if every [[element]] that is
+<span>effectively contained</span> in the [[range]] has computed font-weight at
+least 700, and the [[parent]] of every [[text]] node that is <span>effectively
+contained</span> in the [[range]] has computed font-weight at least 700.
+Otherwise false.
<dd><p><strong>Value</strong>: Always the empty string.
<!-- We have lots of options here (and presumably for all the others where
@@ -823,8 +866,8 @@
specify "#" for the value, or the author can rewrite it, so it's not like
this makes the API less useful. -->
- <li>Let <var>node list</var> be the result of <span title="decompose a
- range">decomposing</span> the [[range]].
+ <li>Let <var>node list</var> be the result of <span
+ title=decompose>decomposing</span> the [[range]].
<li>For each <var>node</var> in <var>node list</var>, in order:
@@ -902,10 +945,9 @@
<dt><code title><dfn title=command-fontname>fontName</dfn></code>
-<dd><p><strong>Action</strong>: The user agent must <span title="style a
-range">style the [[range]]</span> with <var>property name</var> equal to
-"font-family", <var>property value</var> equal to <var>value</var>, and
-<var>tag list</var> equal to the empty list.
+<dd><p><strong>Action</strong>: <span>Decompose</span> the [[range]], then
+<span>style</span> each returned [[node]] with <var>property</var> equal to
+"font-family" and <var>new value</var> equal to <var>value</var>.
<!-- UAs differ a bit in the details here:
IE 9 RC: Empty string sets <font face="">
@@ -930,7 +972,7 @@
<dd><p><strong>State</strong>: Always false.
<dd><p><strong>Value</strong>: The computed value of the CSS property
-"font-family" for the <span>beginning element</span> of the [[range]].
+"font-family" for . . .
<!-- Complicated.
IE 9 RC: Always the empty string. Not very useful.
@@ -967,9 +1009,9 @@
except in Opera, which tries to parse it in some crazy way and winds up with
"#00b025". rgba() colors don't work as uniformly, but I don't see any reason
to prohibit them. Best to just match CSS. -->
-Otherwise, it must <span title="style a range">style the [[range]]</span> with
-<var>property name</var> equal to "color", <var>property value</var> equal to
-<var>value</var>, and <var>tag list</var> equal to the empty list.
+Otherwise, it must <span>decompose</span> the [[range]], then
+<span>style</span> each returned [[node]] with <var>property</var> equal to
+"color" and <var>new value</var> equal to <var>value</var>.
<dd><p><strong>State</strong>: Always false.
<!-- This matches IE 9 RC and Chrome 10. Opera 11 seems to return true if
@@ -979,7 +1021,7 @@
least as much sense. -->
<dd><p><strong>Value</strong>: The computed value of the CSS property "color"
-for the <span>beginning element</span> of the [[range]].
+for . . .
<!-- IE 9 RC returns the number 0 always, which makes no sense at all. This
matches the other browsers. -->
@@ -1034,17 +1076,17 @@
<dt><code title><dfn title=command-italic>italic</dfn></code>
-<dd><p><strong>Action</strong>: If the of the [[range]] for this command is
-false, the user agent must <span title="style a range">style the
-[[range]]</span> with <var>property name</var> "font-style", <var>property
-value</var> "italic", <var>tag list</var> ["i", "em"]. Otherwise, it must
-<span title="unstyle a range">unstyle it</span> with <var>property name</var>
-"font-style", <var>property value</var> "normal", and <var>tag list</var> ["i",
-"em"].
+<dd><p><strong>Action</strong>: <span>Decompose</span> the [[range]]. If the
+state of the [[range]] for this command is then true, <span>style</span> each
+returned [[node]] with <var>property</var> "font-style" and <var>new
+value</var> "italic". Otherwise, <span>style</span> them with <var>new
+value</var> "normal".
-<dd><p><strong>State</strong>: True if the <span>beginning element</span> of the
-[[range]] has font-style with computed value "italic" or "oblique", otherwise
-false.
+<dd><p><strong>State</strong>: True if every [[element]] that is
+<span>effectively contained</span> in the [[range]] has computed font-style
+"italic" or "oblique", and the [[parent]] of every [[text]] node that is
+<span>effectively contained</span> in the [[range]] has computed font-style
+"italic" or "oblique". Otherwise false.
<dd><p><strong>Value</strong>: Always the empty string.