--- a/editcommands.html Tue Jul 05 15:56:37 2011 -0600
+++ b/editcommands.html Thu Jul 07 13:32:42 2011 -0600
@@ -38,7 +38,7 @@
<body class=draft>
<div class=head id=head>
<h1>HTML Editing Commands</h1>
-<h2 class="no-num no-toc" id=work-in-progress-—-last-update-5-july-2011>Work in Progress — Last Update 5 July 2011</h2>
+<h2 class="no-num no-toc" id=work-in-progress-—-last-update-7-july-2011>Work in Progress — Last Update 7 July 2011</h2>
<dl>
<dt>Editor
<dd>Aryeh Gregor <ayg+spec@aryeh.name>
@@ -449,10 +449,12 @@
those listed in <a href=#miscellaneous-commands>Miscellaneous commands</a> are
always <a href=#enabled>enabled</a>. The other <a href=#command title=command>commands</a>
defined here are <a href=#enabled>enabled</a> if the <a href=#active-range>active range</a> is not
-null, and are not <a href=#enabled>enabled</a> if it is.
-
-<p class=XXX>Not clear that this definition is right. It doesn't match any
-browser. Needs more testing and thought.
+null, and either there is some <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <a href=#effectively-contained>effectively contained</a> in
+it that is an <a href=#editing-host>editing host</a> or the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendant</a> of an
+<a href=#editing-host>editing host</a>, or 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> or <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 an
+<a href=#editing-host>editing host</a> or the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendant</a> of an <a href=#editing-host>editing
+host</a>.
+
<!--
Testing with bold and formatBlock:
@@ -462,18 +464,25 @@
descends from something editable).
Firefox 6.0a2 seems to always return true if there's anything editable on the
-page, and throw otherwise. Opera 11.11 seems to always return true if there's
-anything editable on the page, and false otherwise. Neither behavior makes
-much sense.
+page, and throw otherwise.
Chrome 14 dev seems to do something like return true if every node effectively
-contained in the selection is editable, false otherwise. This makes the most
-sense, but it's too narrow for us, because we take some action in many cases
-even if there's some non-editable stuff around.
-
-What we really want this to do is return true if we'd do something when you run
-the command, false otherwise. But that's impractically complicated for little
-benefit. Some approximation closer to IE or Chrome is likely in order.
+contained in the selection is editable, false otherwise.
+
+Opera 11.11 seems to always return true if there's anything editable on the
+page, and false otherwise.
+
+Firefox and Opera behave more or less uselessly. Chrome is not ideal because
+we want commands to be enabled if they'll have any effect at all, and basically
+all commands have an effect if there are some non-editable nodes effectively
+contained in the selection as I've specced it currently. IE is conservative,
+in that it will return true in some cases even if running the command will have
+no effect, but it's pretty simple and it will only return false if there's no
+way the command will have an effect.
+
+Thus I go with IE. Note that at least createLink and unlink can have an effect
+if the entire selection is non-editable, if something descends from an editable
+<a>, so we want to remain enabled in that case.
-->
@@ -1405,6 +1414,9 @@
<ol>
<li>Let <var title="">command</var> be the current <a href=#command>command</a>.
+ <li>If <var title="">element</var> is not <a href=#editable>editable</a>, return the empty
+ list.
+
<li>If <var title="">element</var>'s <a href=#specified-value>specified value</a> for
<var title="">command</var> is null, return the empty list. <!-- We want to abort
early so that we don't try unsetting background-color on a non-inline
@@ -2132,9 +2144,9 @@
<li><a href=#decompose>Decompose</a> the <a href=#active-range>active range</a>, and let <var title="">node
list</var> be the result.
- <li>For each <code class=external data-anolis-spec=html title="the a element"><a href=http://www.whatwg.org/html/#the-a-element>a</a></code> element that has an <code class=external data-anolis-spec=html title=attr-hyperlink-href><a href=http://www.whatwg.org/html/#attr-hyperlink-href>href</a></code> attribute and is an
- <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-ancestor title=concept-tree-ancestor>ancestor</a> of some <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> in <var title="">node list</var>, set that element's
- <code class=external data-anolis-spec=html title=attr-hyperlink-href><a href=http://www.whatwg.org/html/#attr-hyperlink-href>href</a></code> attribute to <var title="">value</var>.
+ <li>For each <a href=#editable>editable</a> <code class=external data-anolis-spec=html title="the a element"><a href=http://www.whatwg.org/html/#the-a-element>a</a></code> element that has an <code class=external data-anolis-spec=html title=attr-hyperlink-href><a href=http://www.whatwg.org/html/#attr-hyperlink-href>href</a></code>
+ attribute and is an <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-ancestor title=concept-tree-ancestor>ancestor</a> of some <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> in <var title="">node list</var>,
+ set that element's <code class=external data-anolis-spec=html title=attr-hyperlink-href><a href=http://www.whatwg.org/html/#attr-hyperlink-href>href</a></code> attribute to <var title="">value</var>.
<!-- There are three approaches here. For instance, if you ask browsers to
create a link to "http://example.org" on the "b" here:
@@ -2649,13 +2661,14 @@
list</var> be the result.
<li>For each <var title="">node</var> in <var title="">node list</var>, unset the <code class=external data-anolis-spec=html title="the style attribute"><a href=http://www.whatwg.org/html/#the-style-attribute>style</a></code>
- attribute of <var title="">node</var> (if it's an <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code>) and then all its
+ attribute of <var title="">node</var> if it's an <a href=#editable>editable</a> <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code>,
+ then unset the <code class=external data-anolis-spec=html title="the style attribute"><a href=http://www.whatwg.org/html/#the-style-attribute>style</a></code> attribute of all its <a href=#editable>editable</a>
<code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code> <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendants</a>.
- <li>Let <var title="">elements to remove</var> be a list of all <a href=#html-element title="HTML
- element">HTML elements</a> that are the same as or <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendants</a> of some
- member of <var title="">node list</var> and have non-null <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>parents</a> and satisfy
- (insert conditions here).
+ <li>Let <var title="">elements to remove</var> be a list of all <a href=#editable>editable</a>
+ <a href=#html-element title="HTML element">HTML elements</a> that are the same as or
+ <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-descendant title=concept-tree-descendant>descendants</a> of some member of <var title="">node list</var> and have non-null
+ <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>parents</a> and satisfy (insert conditions here).
<p class=XXX>The conditions are not so simple to define, because we want to
include non-conforming elements, which HTML doesn't give content models. If
@@ -5857,6 +5870,9 @@
<!-- Chrome 14 dev and Opera 11.11 do this even if the value is empty.
Firefox 5.0a2 throws an exception. -->
+ <li>If the <a href=#active-range>active range</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> is neither
+ <a href=#editable>editable</a> nor an <a href=#editing-host>editing host</a>, abort these steps.
+
<li>Let <var title="">frag</var> be the result of calling <code class=external data-anolis-spec=domps title=dom-Range-createContextualFragment><a href=http://html5.org/specs/dom-parsing.html#dom-range-createcontextualfragment>createContextualFragment(<var title="">value</var>)</a></code>
on the <a href=#active-range>active range</a>.
@@ -5916,6 +5932,9 @@
<li><a href=#delete-the-contents>Delete the contents</a> of <var title="">range</var>.
+ <li>If the <a href=#active-range>active range</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> is neither
+ <a href=#editable>editable</a> nor an <a href=#editing-host>editing host</a>, abort these steps.
+
<li>If <var title="">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 a <a href=#prohibited-paragraph-child>prohibited paragraph
child</a> whose sole <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a> is a <code class=external data-anolis-spec=html title="the br element"><a href=http://www.whatwg.org/html/#the-br-element>br</a></code>, and 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-offset title=concept-boundary-point-offset>offset</a> is 0,
remove 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>'s <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> from it.
@@ -5971,6 +5990,9 @@
<p class=XXX>This might blow up non-contenteditable stuff.
+ <li>If the <a href=#active-range>active range</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> is neither
+ <a href=#editable>editable</a> nor an <a href=#editing-host>editing host</a>, abort these steps.
+
<li>Let <var title="">hr</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Document-createElement><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-document-createelement>createElement("hr")</a></code> on the
<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>.
@@ -6020,6 +6042,9 @@
<ol>
<li><a href=#delete-the-contents>Delete the contents</a> of the <a href=#active-range>active range</a>.
+ <li>If the <a href=#active-range>active range</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> is neither
+ <a href=#editable>editable</a> nor an <a href=#editing-host>editing host</a>, abort these steps.
+
<li>If the <a href=#active-range>active range</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> is an <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#element>Element</a></code>, and
"br" is not an <a href=#allowed-child>allowed child</a> of it, abort these steps.
<!-- script, xmp, table, . . . -->
@@ -6107,6 +6132,9 @@
<ol>
<li><a href=#delete-the-contents>Delete the contents</a> of the <a href=#active-range>active range</a>.
+ <li>If the <a href=#active-range>active range</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> is neither
+ <a href=#editable>editable</a> nor an <a href=#editing-host>editing host</a>, abort these steps.
+
<li>Let <var title="">range</var> be the <a href=#active-range>active range</a>.
<li>Let <var title="">node</var> and <var title="">offset</var> be <var title="">range</var>'s
@@ -6426,15 +6454,18 @@
This is still a huge headache, though.
-->
+<p class=XXX>This doesn't work well if the input contains things that aren't
+supposed to appear in HTML, like carriage returns or nulls. Nor is it going to
+work well if the current cursor position is in between two halves of a non-BMP
+character. This will result in unserializability. The current spec disregards
+this, as Chrome 14 dev does.
+
<ol>
<li><a href=#delete-the-contents>Delete the contents</a> of the <a href=#active-range>active range</a>.
<!-- Chrome 14 dev does this even if passed the empty string. -->
- <p class=XXX>This doesn't work well if the input contains things that aren't
- supposed to appear in HTML, like carriage returns or nulls. Nor is it going
- to work well if the current cursor position is in between two halves of a
- non-BMP character. This will result in unserializability. The current spec
- disregards this, as Chrome 14 dev does.
+ <li>If the <a href=#active-range>active range</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> is neither
+ <a href=#editable>editable</a> nor an <a href=#editing-host>editing host</a>, abort these steps.
<li>If <var title="">value</var>'s <a href=http://es5.github.com/#x15.5.5.1>length</a> is greater than one:
--- a/implementation.js Tue Jul 05 15:56:37 2011 -0600
+++ b/implementation.js Thu Jul 07 13:32:42 2011 -0600
@@ -602,9 +602,23 @@
//
// "Among commands defined in this specification, those listed in
// Miscellaneous commands are always enabled. The other commands defined
- // here are enabled if the active range is not null, and are not enabled if
- // it is."
- return getActiveRange() || ["copy", "cut", "paste", "selectall", "stylewithcss", "usecss"].indexOf(command) != -1;
+ // here are enabled if the active range is not null, and either there is
+ // some node effectively contained in it that is an editing host or the
+ // descendant of an editing host, or its start node or end node is an
+ // editing host or the descendant of an editing host."
+ if (["copy", "cut", "paste", "selectall", "stylewithcss", "usecss"].indexOf(command) != -1) {
+ return true;
+ }
+
+ return getActiveRange()
+ && (getAllEffectivelyContainedNodes(getActiveRange(), function(node) {
+ return isEditingHost(node)
+ || getAncestors(node).some(isEditingHost);
+ }).length
+ || isEditingHost(getActiveRange().startContainer)
+ || getAncestors(getActiveRange().startContainer).some(isEditingHost)
+ || isEditingHost(getActiveRange().endContainer)
+ || getAncestors(getActiveRange().endContainer).some(isEditingHost));
}
function myQueryCommandIndeterm(command, range) {
@@ -1941,6 +1955,11 @@
//@{
function clearValue(element, command) {
+ // "If element is not editable, return the empty list."
+ if (!isEditable(element)) {
+ return [];
+ }
+
// "If element's specified value for command is null, return the empty
// list."
if (getSpecifiedValue(element, command) === null) {
@@ -2574,19 +2593,21 @@
// "Decompose the active range, and let node list be the result."
var nodeList = decomposeRange(getActiveRange());
- // "For each a element that has an href attribute and is an ancestor of
- // some node in node list, set that element's href attribute to value."
- for (var i = 0; i < nodeList.length; i++) {
- var candidate = nodeList[i].parentNode;
- while (candidate) {
- if (isHtmlElement(candidate, "A")
- && candidate.hasAttribute("href")) {
- candidate.setAttribute("href", value);
+ // "For each editable a element that has an href attribute and is an
+ // ancestor of some node in node list, set that element's href
+ // attribute to value."
+ //
+ // TODO: We don't actually do this in tree order, not that it matters
+ // unless you're spying with mutation events.
+ nodeList.forEach(function(node) {
+ getAncestors(node).forEach(function(ancestor) {
+ if (isEditable(ancestor)
+ && isHtmlElement(ancestor, "a")
+ && ancestor.hasAttribute("href")) {
+ ancestor.setAttribute("href", value);
}
-
- candidate = candidate.parentNode;
- }
- }
+ });
+ });
// "Set the value of each node in node list to value."
for (var i = 0; i < nodeList.length; i++) {
@@ -2921,38 +2942,37 @@
// "Decompose the active range, and let node list be the result."
var nodeList = decomposeRange(getActiveRange());
- // "For each node in node list, unset the style attribute of node (if
- // it's an Element) and then all its Element descendants."
- for (var i = 0; i < nodeList.length; i++) {
- for (
- var node = nodeList[i];
- node != nextNodeDescendants(nodeList[i]);
- node = nextNode(node)
- ) {
- if (node.nodeType == Node.ELEMENT_NODE) {
- node.removeAttribute("style");
- }
+ // "For each node in node list, unset the style attribute of node if
+ // it's an editable Element, then unset the style attribute of all its
+ // editable Element descendants."
+ nodeList.forEach(function(node) {
+ if (isEditable(node)
+ && node.nodeType == Node.ELEMENT_NODE) {
+ node.removeAttribute("style");
}
- }
-
- // "Let elements to remove be a list of all HTML elements that are the
- // same as or descendants of some member of node list and have non-null
- // parents and satisfy (insert conditions here)."
+ getDescendants(node).forEach(function(descendant) {
+ if (isEditable(descendant)
+ && descendant.nodeType == Node.ELEMENT_NODE) {
+ descendant.removeAttribute("style");
+ }
+ });
+ });
+
+ // "Let elements to remove be a list of all editable HTML elements that
+ // are the same as or descendants of some member of node list and have
+ // non-null parents and satisfy (insert conditions here)."
var elementsToRemove = [];
- for (var i = 0; i < nodeList.length; i++) {
- for (
- var node = nodeList[i];
- node == nodeList[i] || isDescendant(node, nodeList[i]);
- node = nextNode(node)
- ) {
- if (isHtmlElement(node)
+ nodeList.forEach(function(node) {
+ elementsToRemove.push(node);
+ [].push.apply(elementsToRemove, getDescendants(node));
+ });
+ elementsToRemove = elementsToRemove.filter(function(node) {
+ return isEditable(node)
+ && isHtmlElement(node)
&& node.parentNode
// FIXME: Extremely partial list for testing
- && ["A", "AUDIO", "BR", "DIV", "HR", "IMG", "P", "TD", "VIDEO", "WBR"].indexOf(node.tagName) == -1) {
- elementsToRemove.push(node);
- }
- }
- }
+ && ["A", "AUDIO", "BR", "DIV", "HR", "IMG", "P", "TD", "VIDEO", "WBR"].indexOf(node.tagName) == -1;
+ });
// "For each element in elements to remove:"
for (var i = 0; i < elementsToRemove.length; i++) {
@@ -5951,6 +5971,13 @@
// "Run deleteContents() on the range."
range.deleteContents();
+ // "If the active range's start node is neither editable nor an editing
+ // host, abort these steps."
+ if (!isEditable(getActiveRange().startContainer)
+ && !isEditingHost(getActiveRange().startContainer)) {
+ return;
+ }
+
// "Let hr be the result of calling createElement("hr") on the
// context object."
var hr = document.createElement("hr");
@@ -5983,6 +6010,13 @@
// "Delete the contents of the active range."
deleteContents(getActiveRange());
+ // "If the active range's start node is neither editable nor an editing
+ // host, abort these steps."
+ if (!isEditable(getActiveRange().startContainer)
+ && !isEditingHost(getActiveRange().startContainer)) {
+ return;
+ }
+
// "Let frag be the result of calling createContextualFragment(value)
// on the active range."
var frag = getActiveRange().createContextualFragment(value);
@@ -6039,6 +6073,13 @@
// "Delete the contents of range."
deleteContents(range);
+ // "If the active range's start node is neither editable nor an editing
+ // host, abort these steps."
+ if (!isEditable(getActiveRange().startContainer)
+ && !isEditingHost(getActiveRange().startContainer)) {
+ return;
+ }
+
// "If range's start node is a prohibited paragraph child whose sole
// child is a br, and its start offset is 0, remove its start node's
// child from it."
@@ -6086,6 +6127,13 @@
// "Delete the contents of the active range."
deleteContents(getActiveRange());
+ // "If the active range's start node is neither editable nor an editing
+ // host, abort these steps."
+ if (!isEditable(getActiveRange().startContainer)
+ && !isEditingHost(getActiveRange().startContainer)) {
+ return;
+ }
+
// "If the active range's start node is an Element, and "br" is not an
// allowed child of it, abort these steps."
if (getActiveRange().startContainer.nodeType == Node.ELEMENT_NODE
@@ -6166,6 +6214,13 @@
// "Delete the contents of the active range."
deleteContents(getActiveRange());
+ // "If the active range's start node is neither editable nor an editing
+ // host, abort these steps."
+ if (!isEditable(getActiveRange().startContainer)
+ && !isEditingHost(getActiveRange().startContainer)) {
+ return;
+ }
+
// "Let range be the active range."
var range = getActiveRange();
@@ -6443,6 +6498,13 @@
// "Delete the contents of the active range."
deleteContents(getActiveRange());
+ // "If the active range's start node is neither editable nor an editing
+ // host, abort these steps."
+ if (!isEditable(getActiveRange().startContainer)
+ && !isEditingHost(getActiveRange().startContainer)) {
+ return;
+ }
+
// "If value's length is greater than one:"
if (value.length > 1) {
// "For each element el in value, take the action for the
--- a/source.html Tue Jul 05 15:56:37 2011 -0600
+++ b/source.html Thu Jul 07 13:32:42 2011 -0600
@@ -387,10 +387,12 @@
those listed in <a href=#miscellaneous-commands>Miscellaneous commands</a> are
always <span>enabled</span>. The other <span title=command>commands</span>
defined here are <span>enabled</span> if the <span>active range</span> is not
-null, and are not <span>enabled</span> if it is.
-
-<p class=XXX>Not clear that this definition is right. It doesn't match any
-browser. Needs more testing and thought.
+null, and either there is some [[node]] <span>effectively contained</span> in
+it that is an <span>editing host</span> or the [[descendant]] of an
+<span>editing host</span>, or its [[startnode]] or [[endnode]] is an
+<span>editing host</span> or the [[descendant]] of an <span>editing
+host</span>.
+
<!--
Testing with bold and formatBlock:
@@ -400,18 +402,25 @@
descends from something editable).
Firefox 6.0a2 seems to always return true if there's anything editable on the
-page, and throw otherwise. Opera 11.11 seems to always return true if there's
-anything editable on the page, and false otherwise. Neither behavior makes
-much sense.
+page, and throw otherwise.
Chrome 14 dev seems to do something like return true if every node effectively
-contained in the selection is editable, false otherwise. This makes the most
-sense, but it's too narrow for us, because we take some action in many cases
-even if there's some non-editable stuff around.
-
-What we really want this to do is return true if we'd do something when you run
-the command, false otherwise. But that's impractically complicated for little
-benefit. Some approximation closer to IE or Chrome is likely in order.
+contained in the selection is editable, false otherwise.
+
+Opera 11.11 seems to always return true if there's anything editable on the
+page, and false otherwise.
+
+Firefox and Opera behave more or less uselessly. Chrome is not ideal because
+we want commands to be enabled if they'll have any effect at all, and basically
+all commands have an effect if there are some non-editable nodes effectively
+contained in the selection as I've specced it currently. IE is conservative,
+in that it will return true in some cases even if running the command will have
+no effect, but it's pretty simple and it will only return false if there's no
+way the command will have an effect.
+
+Thus I go with IE. Note that at least createLink and unlink can have an effect
+if the entire selection is non-editable, if something descends from an editable
+<a>, so we want to remain enabled in that case.
-->
<!-- @} -->
@@ -1363,6 +1372,9 @@
<ol>
<li>Let <var>command</var> be the current <span>command</span>.
+ <li>If <var>element</var> is not <span>editable</span>, return the empty
+ list.
+
<li>If <var>element</var>'s <span>specified value</span> for
<var>command</var> is null, return the empty list. <!-- We want to abort
early so that we don't try unsetting background-color on a non-inline
@@ -2109,9 +2121,9 @@
<li><span>Decompose</span> the <span>active range</span>, and let <var>node
list</var> be the result.
- <li>For each [[a]] element that has an [[href]] attribute and is an
- [[ancestor]] of some [[node]] in <var>node list</var>, set that element's
- [[href]] attribute to <var>value</var>.
+ <li>For each <span>editable</span> [[a]] element that has an [[href]]
+ attribute and is an [[ancestor]] of some [[node]] in <var>node list</var>,
+ set that element's [[href]] attribute to <var>value</var>.
<!-- There are three approaches here. For instance, if you ask browsers to
create a link to "http://example.org" on the "b" here:
@@ -2626,13 +2638,14 @@
list</var> be the result.
<li>For each <var>node</var> in <var>node list</var>, unset the [[style]]
- attribute of <var>node</var> (if it's an [[element]]) and then all its
+ attribute of <var>node</var> if it's an <span>editable</span> [[element]],
+ then unset the [[style]] attribute of all its <span>editable</span>
[[element]] [[descendants]].
- <li>Let <var>elements to remove</var> be a list of all <span title="HTML
- element">HTML elements</span> that are the same as or [[descendants]] of some
- member of <var>node list</var> and have non-null [[parents]] and satisfy
- (insert conditions here).
+ <li>Let <var>elements to remove</var> be a list of all <span>editable</span>
+ <span title="HTML element">HTML elements</span> that are the same as or
+ [[descendants]] of some member of <var>node list</var> and have non-null
+ [[parents]] and satisfy (insert conditions here).
<p class=XXX>The conditions are not so simple to define, because we want to
include non-conforming elements, which HTML doesn't give content models. If
@@ -5864,6 +5877,9 @@
<!-- Chrome 14 dev and Opera 11.11 do this even if the value is empty.
Firefox 5.0a2 throws an exception. -->
+ <li>If the <span>active range</span>'s [[startnode]] is neither
+ <span>editable</span> nor an <span>editing host</span>, abort these steps.
+
<li>Let <var>frag</var> be the result of calling <code data-anolis-spec=domps
title=dom-Range-createContextualFragment>createContextualFragment(<var>value</var>)</code>
on the <span>active range</span>.
@@ -5924,6 +5940,9 @@
<li><span>Delete the contents</span> of <var>range</var>.
+ <li>If the <span>active range</span>'s [[startnode]] is neither
+ <span>editable</span> nor an <span>editing host</span>, abort these steps.
+
<li>If <var>range</var>'s [[startnode]] is a <span>prohibited paragraph
child</span> whose sole [[child]] is a [[br]], and its [[startoffset]] is 0,
remove its [[startnode]]'s [[child]] from it.
@@ -5980,6 +5999,9 @@
<p class=XXX>This might blow up non-contenteditable stuff.
+ <li>If the <span>active range</span>'s [[startnode]] is neither
+ <span>editable</span> nor an <span>editing host</span>, abort these steps.
+
<li>Let <var>hr</var> be the result of calling <code
data-anolis-spec=domcore
title=dom-Document-createElement>createElement("hr")</code> on the
@@ -6035,6 +6057,9 @@
<ol>
<li><span>Delete the contents</span> of the <span>active range</span>.
+ <li>If the <span>active range</span>'s [[startnode]] is neither
+ <span>editable</span> nor an <span>editing host</span>, abort these steps.
+
<li>If the <span>active range</span>'s [[startnode]] is an [[element]], and
"br" is not an <span>allowed child</span> of it, abort these steps.
<!-- script, xmp, table, . . . -->
@@ -6122,6 +6147,9 @@
<ol>
<li><span>Delete the contents</span> of the <span>active range</span>.
+ <li>If the <span>active range</span>'s [[startnode]] is neither
+ <span>editable</span> nor an <span>editing host</span>, abort these steps.
+
<li>Let <var>range</var> be the <span>active range</span>.
<li>Let <var>node</var> and <var>offset</var> be <var>range</var>'s
@@ -6444,15 +6472,18 @@
This is still a huge headache, though.
-->
+<p class=XXX>This doesn't work well if the input contains things that aren't
+supposed to appear in HTML, like carriage returns or nulls. Nor is it going to
+work well if the current cursor position is in between two halves of a non-BMP
+character. This will result in unserializability. The current spec disregards
+this, as Chrome 14 dev does.
+
<ol>
<li><span>Delete the contents</span> of the <span>active range</span>.
<!-- Chrome 14 dev does this even if passed the empty string. -->
- <p class=XXX>This doesn't work well if the input contains things that aren't
- supposed to appear in HTML, like carriage returns or nulls. Nor is it going
- to work well if the current cursor position is in between two halves of a
- non-BMP character. This will result in unserializability. The current spec
- disregards this, as Chrome 14 dev does.
+ <li>If the <span>active range</span>'s [[startnode]] is neither
+ <span>editable</span> nor an <span>editing host</span>, abort these steps.
<li>If <var>value</var>'s [[strlen]] is greater than one: