--- a/editcommands.html Fri Jul 08 11:27:42 2011 -0600
+++ b/editcommands.html Fri Jul 08 12:51:44 2011 -0600
@@ -1062,18 +1062,41 @@
<h3 id=inline-formatting-command-definitions><span class=secno>7.1 </span>Inline formatting command definitions</h3>
-<p>A <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> is <dfn id=effectively-contained>effectively contained</dfn> in a <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</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 class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a>; or it is the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>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>, it is a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node, 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 class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>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-offset title=concept-boundary-point-offset>offset</a>; or it is the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</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 <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node, and the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</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; or it has at least one <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>, and all 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> are <a href=#effectively-contained>effectively contained</a> in the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a>.
-<!-- The difference between "contained" and "effectively contained" is
-basically that 1) in <b>[foo]</b>, the <b> is effectively contained but not
-contained; and 2) in <b>f[o]o</b>, the text node is effectively contained but
-not contained. This is used mostly for the "decompose" algorithm, and also for
-most inline commands' states. -->
+<p>A <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> <var title="">node</var> is <dfn id=effectively-contained>effectively contained</dfn> in a
+<a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-range title=concept-range>range</a> <var title="">range</var> if at least one of the following holds:
+<!--
+The difference between "contained" and "effectively contained" is basically
+that 1) in <b>[foo]</b>, the text node and the <b> are effectively contained
+but not contained; and 2) in <b>f[o]o</b>, the text node is effectively
+contained but not contained, and the <b> is neither effectively contained nor
+contained. This is used mostly for the "decompose" algorithm, and also for
+most inline commands' states.
+-->
+<ul>
+ <li><var title="">node</var> is <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">range</var>.
+
+ <li><var title="">node</var> is <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>, it is a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code>
+ node, 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 <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-offset title=concept-boundary-point-offset>offset</a>.
+
+ <li><var title="">node</var> is <var title="">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>, it is a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node,
+ and <var title="">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-offset title=concept-boundary-point-offset>offset</a> is not 0.
+
+ <li><var title="">node</var> has at least one <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-child title=concept-tree-child>child</a>; and all 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> are
+ <a href=#effectively-contained>effectively contained</a> in <var title="">range</var>; and either
+ <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 not a <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 <var title="">node</var>
+ or is not a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node or <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-offset title=concept-boundary-point-offset>offset</a> is zero; and
+ either <var title="">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 a <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
+ <var title="">node</var> or is not a <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#text>Text</a></code> node or <var title="">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-offset title=concept-boundary-point-offset>offset</a>
+ is 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>'s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#concept-node-length title=concept-node-length>length</a>.
+ <!--
+ Basically, anything whose children are all effectively contained should be
+ effectively contained itself, except that in a case like <b>f[o]o</b> we
+ don't want <b> to be effectively contained even though the text node is.
+ That's because as soon as we decompose the range, the text node is split and
+ the <b> will no longer be effectively contained.
+ -->
+</ul>
<p>A <dfn id=modifiable-element>modifiable element</dfn> is a <code class=external data-anolis-spec=html title="the b element"><a href=http://www.whatwg.org/html/#the-b-element>b</a></code>, <code class=external data-anolis-spec=html title="the em element"><a href=http://www.whatwg.org/html/#the-em-element>em</a></code>, <code class=external data-anolis-spec=html title="the i element"><a href=http://www.whatwg.org/html/#the-i-element>i</a></code>, <code class=external data-anolis-spec=html title="the s element"><a href=http://www.whatwg.org/html/#the-s-element>s</a></code>, <code class=external data-anolis-spec=html title="the span element"><a href=http://www.whatwg.org/html/#the-span-element>span</a></code>,
<code class=external data-anolis-spec=html title="the strike element"><a href=http://www.whatwg.org/html/#the-strike-element>strike</a></code>, <code class=external data-anolis-spec=html title="the strong element"><a href=http://www.whatwg.org/html/#the-strong-element>strong</a></code>, <code class=external data-anolis-spec=html title="the sub and sup elements"><a href=http://www.whatwg.org/html/#the-sub-and-sup-elements>sub</a></code>, <code class=external data-anolis-spec=html title="the sub and sup elements"><a href=http://www.whatwg.org/html/#the-sub-and-sup-elements>sup</a></code>, or <code class=external data-anolis-spec=html title="the u element"><a href=http://www.whatwg.org/html/#the-u-element>u</a></code> element with no attributes
@@ -2643,53 +2666,29 @@
<img>, although Firefox adds tabindex=0 (???), so I'm assuming the rest are
similar. Also, I'll keep all foreign elements and form elements.
-
Browsers will split up all these inline elements if the selection is contained
within them. Opera does strip unrecognized elements with display: block if
they're within the selection, but doesn't split them up if they contain the
selection.
-Upon consideration, I've decided to go for something for now that's totally
-different from what any browser does: get rid of all elements actually
-contained in the selection (pretty much matching browsers), but for elements
-containing the selection, I'll just run all the other styling commands in a
-fashion that will reset the style in normal cases. This avoids having to
-create a lot of new logic to decide exactly what we can split up or not, and
-should be able to correctly remove anything that can actually be created by
-these algorithms.
-
-This approach currently results in incorrect behavior in some cases for
-non-modifiable elements with default styling, like <code>. The correct
-approach is probably to declare these elements modifiable; this would roughly
-match what browsers do. I'm ignoring the issue for now, because such elements
-cannot actually be created by implementations of execCommand(), so they're not
-likely to be common. Also, the way pushing down styles works right now is that
-the element is destroyed and the style is recreated, which isn't going to work
-for elements like <code> or <tt> or <mark> that we don't normally create.
+Chrome 14 dev removes style attributes from every element in the range, but
+IE10PP2, Firefox 7.0a2, and Opera 11.50 do not, so I go with them.
-->
<p><a href=#action>Action</a>:
<ol>
- <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 <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 <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=#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
- everything had categories, we'd want something like "either it's
- unrecognized, or it's phrasing content that's not also embedded or
- interactive". Except this has weird corner-cases like ins and del that are
- sometimes phrasing and sometimes flow.
+ <a href=#html-element title="HTML element">HTML elements</a> <a href=#effectively-contained>effectively
+ contained</a> in the <a href=#active-range>active range</a>, excluding those with
+ <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> "a", "audio", "br", "img", "video", or "wbr", and excluding
+ <a href=#prohibited-paragraph-child title="prohibited paragraph child">prohibited paragraph
+ children</a>.
+
+ <p class=XXX>Double-check that this element list is correct.
+
+ <p class=XXX>Do we want to go with this whitelist approach, or a blacklist?
+ If a whitelist, should we also whitelist display: block elements?
<li>For each <var title="">element</var> in <var title="">elements to remove</var>:
@@ -2701,30 +2700,36 @@
<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>.
</ol>
- <li>For each of the entries in the following table, in the given order:
+ <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 <var title="">node</var> in <var title="">node list</var>, while <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=#editable>editable</a> <a href=#html-element>HTML element</a> <a href=#in-the-same-editing-host>in the
+ same editing host</a> as <var title="">node</var>, and <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 a <a href=#prohibited-paragraph-child>prohibited paragraph child</a> and does not have
+ <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> "a" or "audio" or "br" or "img" or "video" or "wbr",
+ <a href=#split-the-parent>split the parent</a> of the one-<a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>node</a> list consisting of
+ <var title="">node</var>.
+
+ <li>For each of the entries in the following list, in the given order:
<a href=#decompose>decompose</a> the <a href=#active-range>active range</a> again; then <a href=#set-the-value>set
- the value</a> of the resulting <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a>, with <var title="">command</var> and
- <var title="">new value</var> as given.
-
- <p class=XXX>This has no relationship to what browsers actually do, although
- it mostly works okay. If I don't throw it out and replace it with something
- more like what browsers do, it still probably needs refinement to handle some
- elements that it doesn't deal with yet.
-
- <table>
- <tr><th><var title="">command</var> <th><var title="">new value</var>
- <tr><td>subscript <td>"baseline"
+ the value</a> of the resulting <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-node title=concept-node>nodes</a> to null, with <var title="">command</var>
+ as given.
+ <!-- For cases like <p style=font-weight:bold>foo[bar]baz</p>. -->
+
+ <ol>
+ <li>subscript
<!-- superscript not needed, subscript does the same thing. We run this
first so <sub>/<sup> won't upset fontSize. -->
- <tr><td>bold <td>"normal"
- <tr><td>fontName <td>null
- <tr><td>fontSize <td>null
- <tr><td>foreColor <td>null
- <tr><td>hiliteColor <td>null
- <tr><td>italic <td>"normal"
- <tr><td>strikethrough <td>null
- <tr><td>underline <td>null
- </table>
+ <li>bold
+ <li>fontName
+ <li>fontSize
+ <li>foreColor
+ <li>hiliteColor
+ <li>italic
+ <li>strikethrough
+ <li>underline
+ </ol>
</ol>
--- a/implementation.js Fri Jul 08 11:27:42 2011 -0600
+++ b/implementation.js Fri Jul 08 12:51:44 2011 -0600
@@ -1281,35 +1281,46 @@
///// Inline formatting command definitions /////
//@{
-/**
- * "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; or it has at least one
- * child, and all its children are effectively contained in the Range."
- */
+// "A node node is effectively contained in a range range if at least one of
+// the following holds:"
function isEffectivelyContained(node, range) {
+ // "node is contained in range."
if (isContained(node, range)) {
return true;
}
+
+ // "node is range's start node, it is a Text node, and its length is
+ // different from range's start offset."
if (node == range.startContainer
&& node.nodeType == Node.TEXT_NODE
&& getNodeLength(node) != range.startOffset) {
return true;
}
+
+ // "node is range's end node, it is a Text node, and range's end offset is
+ // not 0."
if (node == range.endContainer
&& node.nodeType == Node.TEXT_NODE
&& range.endOffset != 0) {
return true;
}
- if (node.childNodes.length != 0) {
- for (var i = 0; i < node.childNodes.length; i++) {
- if (!isEffectivelyContained(node.childNodes[i], range)) {
- return false;
- }
- }
+
+ // "node has at least one child; and all its children are effectively
+ // contained in range; and either range's start node is not a descendant of
+ // node or is not a Text node or range's start offset is zero; and either
+ // range's end node is not a descendant of node or is not a Text node or
+ // range's end offset is its end node's length."
+ if (node.hasChildNodes()
+ && [].every.call(node.childNodes, function(child) { return isEffectivelyContained(child, range) })
+ && (!isDescendant(range.startContainer, node)
+ || range.startContainer.nodeType != Node.TEXT_NODE
+ || range.startOffset == 0)
+ && (!isDescendant(range.endContainer, node)
+ || range.endContainer.nodeType != Node.TEXT_NODE
+ || range.endOffset == getNodeLength(range.endContainer))) {
return true;
}
+
return false;
}
@@ -2958,76 +2969,65 @@
//@{
commands.removeformat = {
action: function() {
- // "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 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");
- }
- 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 = [];
- nodeList.forEach(function(node) {
- elementsToRemove.push(node);
- [].push.apply(elementsToRemove, getDescendants(node));
- });
- elementsToRemove = elementsToRemove.filter(function(node) {
+ // "Let elements to remove be a list of all editable HTML elements
+ // effectively contained in the active range, excluding those with
+ // local name "a", "audio", "br", "img", "video", or "wbr", and
+ // excluding prohibited paragraph children."
+ var elementsToRemove = getAllEffectivelyContainedNodes(getActiveRange(), 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;
+ && ["A", "AUDIO", "BR", "IMG", "VIDEO", "WBR"].indexOf(node.tagName) == -1
+ && !isProhibitedParagraphChild(node);
});
// "For each element in elements to remove:"
- for (var i = 0; i < elementsToRemove.length; i++) {
- var element = elementsToRemove[i];
-
+ elementsToRemove.forEach(function(element) {
// "While element has children, insert the first child of element
// into the parent of element immediately before element,
// preserving ranges."
- while (element.childNodes.length) {
+ while (element.hasChildNodes()) {
movePreservingRanges(element.firstChild, element.parentNode, getNodeIndex(element));
}
// "Remove element from its parent."
element.parentNode.removeChild(element);
- }
-
- // "For each of the entries in the following table, in the given order:
+ });
+
+ // "Decompose the active range, and let node list be the result."
+ var nodeList = decomposeRange(getActiveRange());
+
+ // "For each node in node list, while node's parent is an editable HTML
+ // element in the same editing host as node, and node's parent is not a
+ // prohibited paragraph child and does not have local name "a" or
+ // "audio" or "br" or "img" or "video" or "wbr", split the parent of
+ // the one-node list consisting of node."
+ nodeList.forEach(function(node) {
+ while (isEditable(node.parentNode)
+ && isHtmlElement(node.parentNode)
+ && !isProhibitedParagraphChild(node.parentNode)
+ && ["A", "AUDIO", "BR", "IMG", "VIDEO", "WBR"].indexOf(node.parentNode.tagName) == -1) {
+ splitParent([node]);
+ }
+ });
+
+ // "For each of the entries in the following list, in the given order:
// decompose the active range again; then set the value of the
- // resulting nodes, with command and new value as given."
- var table = {
- "subscript": "baseline",
- "bold": "normal",
- "fontname": null,
- "fontsize": null,
- "forecolor": null,
- "hilitecolor": null,
- "italic": "normal",
- "strikethrough": null,
- "underline": null,
- };
- for (var command in table) {
- var nodeList = decomposeRange(getActiveRange());
- for (var i = 0; i < nodeList.length; i++) {
- setNodeValue(nodeList[i], command, table[command]);
- }
- }
+ // resulting nodes to null, with command as given."
+ [
+ "subscript",
+ "bold",
+ "fontname",
+ "fontsize",
+ "forecolor",
+ "hilitecolor",
+ "italic",
+ "strikethrough",
+ "underline",
+ ].forEach(function(command) {
+ decomposeRange(getActiveRange()).forEach(function(node) {
+ setNodeValue(node, command, null);
+ });
+ });
}
};
//@}
--- a/source.html Fri Jul 08 11:27:42 2011 -0600
+++ b/source.html Fri Jul 08 12:51:44 2011 -0600
@@ -1017,18 +1017,41 @@
<h3>Inline formatting command definitions</h3>
<!-- @{ -->
-<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; or it has at least one [[child]], and all its
-[[children]] are <span>effectively contained</span> in the [[range]].
-<!-- The difference between "contained" and "effectively contained" is
-basically that 1) in <b>[foo]</b>, the <b> is effectively contained but not
-contained; and 2) in <b>f[o]o</b>, the text node is effectively contained but
-not contained. This is used mostly for the "decompose" algorithm, and also for
-most inline commands' states. -->
+<p>A [[node]] <var>node</var> is <dfn>effectively contained</dfn> in a
+[[range]] <var>range</var> if at least one of the following holds:
+<!--
+The difference between "contained" and "effectively contained" is basically
+that 1) in <b>[foo]</b>, the text node and the <b> are effectively contained
+but not contained; and 2) in <b>f[o]o</b>, the text node is effectively
+contained but not contained, and the <b> is neither effectively contained nor
+contained. This is used mostly for the "decompose" algorithm, and also for
+most inline commands' states.
+-->
+<ul>
+ <li><var>node</var> is [[contained]] in <var>range</var>.
+
+ <li><var>node</var> is <var>range</var>'s [[startnode]], it is a [[text]]
+ node, and its [[nodelength]] is different from <var>range</var>'s
+ [[startoffset]].
+
+ <li><var>node</var> is <var>range</var>'s [[endnode]], it is a [[text]] node,
+ and <var>range</var>'s [[endoffset]] is not 0.
+
+ <li><var>node</var> has at least one [[child]]; and all its [[children]] are
+ <span>effectively contained</span> in <var>range</var>; and either
+ <var>range</var>'s [[startnode]] is not a [[descendant]] of <var>node</var>
+ or is not a [[text]] node or <var>range</var>'s [[startoffset]] is zero; and
+ either <var>range</var>'s [[endnode]] is not a [[descendant]] of
+ <var>node</var> or is not a [[text]] node or <var>range</var>'s [[endoffset]]
+ is its [[endnode]]'s [[length]].
+ <!--
+ Basically, anything whose children are all effectively contained should be
+ effectively contained itself, except that in a case like <b>f[o]o</b> we
+ don't want <b> to be effectively contained even though the text node is.
+ That's because as soon as we decompose the range, the text node is split and
+ the <b> will no longer be effectively contained.
+ -->
+</ul>
<p>A <dfn>modifiable element</dfn> is a [[b]], [[em]], [[i]], [[s]], [[span]],
[[strike]], [[strong]], [[sub]], [[sup]], or [[u]] element with no attributes
@@ -2620,53 +2643,29 @@
<img>, although Firefox adds tabindex=0 (???), so I'm assuming the rest are
similar. Also, I'll keep all foreign elements and form elements.
-
Browsers will split up all these inline elements if the selection is contained
within them. Opera does strip unrecognized elements with display: block if
they're within the selection, but doesn't split them up if they contain the
selection.
-Upon consideration, I've decided to go for something for now that's totally
-different from what any browser does: get rid of all elements actually
-contained in the selection (pretty much matching browsers), but for elements
-containing the selection, I'll just run all the other styling commands in a
-fashion that will reset the style in normal cases. This avoids having to
-create a lot of new logic to decide exactly what we can split up or not, and
-should be able to correctly remove anything that can actually be created by
-these algorithms.
-
-This approach currently results in incorrect behavior in some cases for
-non-modifiable elements with default styling, like <code>. The correct
-approach is probably to declare these elements modifiable; this would roughly
-match what browsers do. I'm ignoring the issue for now, because such elements
-cannot actually be created by implementations of execCommand(), so they're not
-likely to be common. Also, the way pushing down styles works right now is that
-the element is destroyed and the style is recreated, which isn't going to work
-for elements like <code> or <tt> or <mark> that we don't normally create.
+Chrome 14 dev removes style attributes from every element in the range, but
+IE10PP2, Firefox 7.0a2, and Opera 11.50 do not, so I go with them.
-->
<p><span>Action</span>:
<ol>
- <li><span>Decompose</span> the <span>active range</span>, and let <var>node
- 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 <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>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
- everything had categories, we'd want something like "either it's
- unrecognized, or it's phrasing content that's not also embedded or
- interactive". Except this has weird corner-cases like ins and del that are
- sometimes phrasing and sometimes flow.
+ <span title="HTML element">HTML elements</span> <span>effectively
+ contained</span> in the <span>active range</span>, excluding those with
+ [[localname]] "a", "audio", "br", "img", "video", or "wbr", and excluding
+ <span title="prohibited paragraph child">prohibited paragraph
+ children</span>.
+
+ <p class=XXX>Double-check that this element list is correct.
+
+ <p class=XXX>Do we want to go with this whitelist approach, or a blacklist?
+ If a whitelist, should we also whitelist display: block elements?
<li>For each <var>element</var> in <var>elements to remove</var>:
@@ -2678,30 +2677,36 @@
<li>Remove <var>element</var> from its [[parent]].
</ol>
- <li>For each of the entries in the following table, in the given order:
+ <li><span>Decompose</span> the <span>active range</span>, and let <var>node
+ list</var> be the result.
+
+ <li>For each <var>node</var> in <var>node list</var>, while <var>node</var>'s
+ [[parent]] is an <span>editable</span> <span>HTML element</span> <span>in the
+ same editing host</span> as <var>node</var>, and <var>node</var>'s [[parent]]
+ is not a <span>prohibited paragraph child</span> and does not have
+ [[localname]] "a" or "audio" or "br" or "img" or "video" or "wbr",
+ <span>split the parent</span> of the one-[[node]] list consisting of
+ <var>node</var>.
+
+ <li>For each of the entries in the following list, in the given order:
<span>decompose</span> the <span>active range</span> again; then <span>set
- the value</span> of the resulting [[nodes]], with <var>command</var> and
- <var>new value</var> as given.
-
- <p class=XXX>This has no relationship to what browsers actually do, although
- it mostly works okay. If I don't throw it out and replace it with something
- more like what browsers do, it still probably needs refinement to handle some
- elements that it doesn't deal with yet.
-
- <table>
- <tr><th><var>command</var> <th><var>new value</var>
- <tr><td>subscript <td>"baseline"
+ the value</span> of the resulting [[nodes]] to null, with <var>command</var>
+ as given.
+ <!-- For cases like <p style=font-weight:bold>foo[bar]baz</p>. -->
+
+ <ol>
+ <li>subscript
<!-- superscript not needed, subscript does the same thing. We run this
first so <sub>/<sup> won't upset fontSize. -->
- <tr><td>bold <td>"normal"
- <tr><td>fontName <td>null
- <tr><td>fontSize <td>null
- <tr><td>foreColor <td>null
- <tr><td>hiliteColor <td>null
- <tr><td>italic <td>"normal"
- <tr><td>strikethrough <td>null
- <tr><td>underline <td>null
- </table>
+ <li>bold
+ <li>fontName
+ <li>fontSize
+ <li>foreColor
+ <li>hiliteColor
+ <li>italic
+ <li>strikethrough
+ <li>underline
+ </ol>
</ol>
<!-- @} -->