Avoid duplicating id's
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Tue, 05 Jul 2011 15:38:01 -0600
changeset 364 b15222941c6e
parent 363 02da8d6c63db
child 365 3ff0ff364e74
Avoid duplicating id's

I've decided not to care about duplicate <a name> or anything else.
Unrelatedly, I had to fix a bunch of xref stuff in this commit to get it
to compile, since I updated the spec data I was using.
editcommands.html
implementation.js
preprocess
source.html
--- a/editcommands.html	Tue Jul 05 14:00:32 2011 -0600
+++ b/editcommands.html	Tue Jul 05 15:38:01 2011 -0600
@@ -969,12 +969,7 @@
     <li>Let <var title="">cloned parent</var> be the result of calling <code class=external data-anolis-spec=domcore title=dom-Node-cloneNode><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-clonenode>cloneNode(false)</a></code>
     on <var title="">original parent</var>.
 
-    <p class=XXX>This will duplicate id's, as well as other bad things.  Do we
-    care?  We don't want to not copy attributes at all, because that wouldn't
-    copy style attributes, and Firefox in CSS mode will actually add style
-    attributes to any elements it feels like.  If we do exclude id's, even
-    though they'd only occur if someone manually added them, do we want to
-    exclude other things like itemid or accesskey or . . .
+    <li>If <var title="">original parent</var> has an <code class=external data-anolis-spec=html title="the id attribute"><a href=http://www.whatwg.org/html/#the-id-attribute>id</a></code> attribute, unset it.
 
     <li>Insert <var title="">cloned parent</var> into the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of <var title="">original
     parent</var> immediately before <var title="">original parent</var>.
@@ -1288,7 +1283,7 @@
 
     <li>If <var title="">node</var> is null, return null.
 
-    <li>Return the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-value title=concept-attr-value>value</a> of <var title="">node</var>'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.
+    <li>Return the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-value title=concept-attribute-value>value</a> of <var title="">node</var>'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.
   </ol>
 
   <li>If <var title="">command</var> is "hiliteColor":
@@ -1370,7 +1365,7 @@
 
   <ol>
     <li>If <var title="">element</var> is an <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 and 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, return the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-value title=concept-attr-value>value</a> of that attribute.
+    attribute, return the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-value title=concept-attribute-value>value</a> of that attribute.
 
     <li>Return null.
   </ol>
@@ -4925,7 +4920,7 @@
 
   <li>Let <var title="">element list</var> be a list of all <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>s <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">new range</var> that either has an
-  attribute in 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> whose <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> is "align", or has
+  attribute in 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> whose <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name title=concept-attribute-local-name>local name</a> is "align", or has
   a <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 that sets "text-align", or is a <code class=external data-anolis-spec=html><a href=http://www.whatwg.org/html/#center>center</a></code>.
   <!-- No browser actually removes center, but it makes sense to do so. -->
 
@@ -4933,7 +4928,7 @@
 
   <ol>
     <li>If <var title="">element</var> has an attribute in 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> whose
-    <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> is "align", remove that attribute.
+    <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-local-name title=concept-attribute-local-name>local name</a> is "align", remove that attribute.
 
     <li>Unset the CSS property "text-align" on <var title="">element</var>, if it's set
     by a <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.
@@ -4989,7 +4984,7 @@
 
     <ul>
       <li>An <code class=external data-anolis-spec=html title=attr-div-align><a href=http://www.whatwg.org/html/#attr-div-align>align</a></code>
-      attribute whose <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attr-value title=concept-attr-value>value</a> is an <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#ascii-case-insensitive>ASCII
+      attribute whose <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-attribute-value title=concept-attribute-value>value</a> is an <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#ascii-case-insensitive>ASCII
       case-insensitive</a> match for <var title="">alignment</var>.
 
       <li>A <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 which sets exactly one CSS property (including
@@ -5327,8 +5322,8 @@
   <!-- IE9 requires the brackets.  If they're not provided, it does nothing.
   -->
 
-  <li>Let <var title="">value</var> be <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#converted-to-lowercase>converted to
-  lowercase</a>.
+  <li>Let <var title="">value</var> be <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#converted-to-ascii-lowercase>converted to
+  ASCII lowercase</a>.
 
   <li>If <var title="">value</var> is not "address", "div", "h1", "h2", "h3", "h4",
   "h5", "h6", "p", or "pre", raise a <code class=external data-anolis-spec=domcore title=dom-DOMException-SYNTAX_ERR><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-domexception-syntax_err>SYNTAX_ERR</a></code> exception.
@@ -5575,7 +5570,7 @@
   <li>If <var title="">node</var> is an <a href=#editable>editable</a> <a href=#html-element>HTML element</a>
   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> "address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p",
   or "pre", and <var title="">node</var> is not the <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 a <a href=#prohibited-paragraph-child>prohibited
-  paragraph child</a>, return <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-element-local-name title=concept-element-local-name>local name</a>, <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#converted-to-lowercase>converted to lowercase</a>.
+  paragraph child</a>, return <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-element-local-name title=concept-element-local-name>local name</a>, <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#converted-to-ascii-lowercase>converted to ASCII lowercase</a>.
   <!--
   Chrome 14 dev will report "div" for <div><ol><li>foo</ol></div> or such.
   Opera 11.11 reports "".  IE and Firefox didn't cooperate with testing.  Opera
@@ -6307,21 +6302,26 @@
 
   <li>Copy all attributes of <var title="">container</var> to <var title="">new container</var>.
 
-  <p class=XXX>Copies id's.
+  <li>If <var title="">new container</var> has an <code class=external data-anolis-spec=html title="the id attribute"><a href=http://www.whatwg.org/html/#the-id-attribute>id</a></code> attribute, unset it.
 
   <li>Insert <var title="">new container</var> into the <a class=external data-anolis-spec=domcore href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#concept-tree-parent title=concept-tree-parent>parent</a> of
   <var title="">container</var> immediately after <var title="">container</var>.
 
-  <li>Let <var title="">frag</var> be the result of calling <code class=external data-anolis-spec=domrange title=dom-Range-extractContents><a href=http://html5.org/specs/dom-range.html#dom-range-extractcontents>extractContents()</a></code> on <var title="">new line
-  range</var>.
+  <li>Let <var title="">contained nodes</var> be all <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> <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#contained>contained</a> in <var title="">new
+  line range</var>.
+
+  <li>Let <var title="">frag</var> be the result of calling <code class=external data-anolis-spec=domrange title=dom-Range-extractContents><a href=http://html5.org/specs/dom-range.html#dom-range-extractcontents>extractContents()</a></code> on
+  <var title="">new line range</var>.
 
   <p class=XXX>This blows up any ranges (other than the selection, which we
-  reset), duplicates id's, and other bad stuff.  May or may not be the best
-  solution.  The intermediate fragment is also probably black-box detectable by
-  DOM mutation events, but I like to pretend those don't exist.
-
-  <li>Call <code class=external data-anolis-spec=domcore title=dom-Node-appendChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-appendchild>appendChild(<var title="">frag</var>)</a></code> on <var title="">new
-  container</var>.
+  reset), and maybe other bad stuff.  May or may not be the best solution.  The
+  intermediate fragment is also probably black-box detectable by DOM mutation
+  events, but I like to pretend those don't exist.
+
+  <li>Unset the <code class=external data-anolis-spec=html title="the id attribute"><a href=http://www.whatwg.org/html/#the-id-attribute>id</a></code> attribute (if any) of each <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>descendant</a> of
+  <var title="">frag</var> that is not in <var title="">contained nodes</var>.
+
+  <li>Call <code class=external data-anolis-spec=domcore title=dom-Node-appendChild><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-appendchild>appendChild(<var title="">frag</var>)</a></code> on <var title="">new container</var>.
 
   <li>If <var title="">container</var> has no <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>, call <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("br")</a></code>
   on the <a class=external data-anolis-spec=domrange href=http://html5.org/specs/dom-range.html#context-object>context object</a>, and append the result 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
--- a/implementation.js	Tue Jul 05 14:00:32 2011 -0600
+++ b/implementation.js	Tue Jul 05 15:38:01 2011 -0600
@@ -1203,6 +1203,9 @@
 		// original parent."
 		var clonedParent = originalParent.cloneNode(false);
 
+		// "If original parent has an id attribute, unset it."
+		originalParent.removeAttribute("id");
+
 		// "Insert cloned parent into the parent of original parent immediately
 		// before original parent."
 		originalParent.parentNode.insertBefore(clonedParent, originalParent);
@@ -5448,7 +5451,7 @@
 			value = value.slice(1, -1);
 		}
 
-		// "Let value be converted to lowercase."
+		// "Let value be converted to ASCII lowercase."
 		value = value.toLowerCase();
 
 		// "If value is not "address", "div", "h1", "h2", "h3", "h4", "h5",
@@ -5675,7 +5678,7 @@
 		// "If node is an editable HTML element with local name "address",
 		// "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", or "pre", and node
 		// is not the ancestor of a prohibited paragraph child, return node's
-		// local name, converted to lowercase."
+		// local name, converted to ASCII lowercase."
 		if (isEditable(node)
 		&& isHtmlElement(node, ["address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p", "pre"])
 		&& !getDescendants(node).some(isProhibitedParagraphChild)) {
@@ -6386,14 +6389,30 @@
 			newContainer.setAttributeNS(container.attributes[i].namespaceURI, container.attributes[i].name, container.attributes[i].value);
 		}
 
+		// "If new container has an id attribute, unset it."
+		newContainer.removeAttribute("id");
+
 		// "Insert new container into the parent of container immediately after
 		// container."
 		container.parentNode.insertBefore(newContainer, container.nextSibling);
 
+		// "Let contained nodes be all nodes contained in new line range."
+		var containedNodes = getAllContainedNodes(newLineRange);
+
 		// "Let frag be the result of calling extractContents() on new line
 		// range."
 		var frag = newLineRange.extractContents();
 
+		// "Unset the id attribute (if any) of each Element descendant of frag
+		// that is not in contained nodes."
+		var descendants = getDescendants(frag);
+		for (var i = 0; i < descendants.length; i++) {
+			if (descendants[i].nodeType == Node.ELEMENT_NODE
+			&& containedNodes.indexOf(descendants[i]) == -1) {
+				descendants[i].removeAttribute("id");
+			}
+		}
+
 		// "Call appendChild(frag) on new container."
 		newContainer.appendChild(frag);
 
--- a/preprocess	Tue Jul 05 14:00:32 2011 -0600
+++ b/preprocess	Tue Jul 05 15:38:01 2011 -0600
@@ -10,8 +10,8 @@
     'a': '<code data-anolis-spec=html title="the a element">a</code>',
     'ancestor': '<span data-anolis-spec=domcore title=concept-tree-ancestor>ancestor</span>',
     'ancestorcontainer': '<span data-anolis-spec=domrange title="ancestor container">ancestor container</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>',
+    'attrlocalname': '<span data-anolis-spec=domcore title=concept-attribute-local-name>local name</span>',
+    'attrvalue': '<span data-anolis-spec=domcore title=concept-attribute-value>value</span>',
     'b': '<code data-anolis-spec=html title="the b element">b</code>',
     'blockquote': '<code data-anolis-spec=html title="the blockquote element">blockquote</code>',
     'br': '<code data-anolis-spec=html title="the br element">br</code>',
@@ -43,6 +43,7 @@
     'em': '<code data-anolis-spec=html title="the em element">em</code>',
     'endnode': '<span data-anolis-spec=domrange title=concept-range-end>end</span> <span data-anolis-spec=domrange title=concept-boundary-point-node>node</span>',
     'endoffset': '<span data-anolis-spec=domrange title=concept-range-end>end</span> <span data-anolis-spec=domrange title=concept-boundary-point-offset>offset</span>',
+    'extractcontents': '<code data-anolis-spec=domrange title=dom-Range-extractContents>extractContents()</code>',
     'firstchild': '<code data-anolis-spec=domcore title=dom-Node-firstChild>firstChild</code>',
     'followingsibling': '<span data-anolis-spec=domcore title="concept-tree-following-sibling">following sibling</span>',
     'font': '<code data-anolis-spec=html title=font>font</code>',
@@ -55,6 +56,7 @@
     'hr': '<code data-anolis-spec=html title="the hr element">hr</code>',
     'href': '<code data-anolis-spec=html title=attr-hyperlink-href>href</code>',
     'i': '<code data-anolis-spec=html title="the i element">i</code>',
+    'id': '<code data-anolis-spec=html title="the id attribute">id</code>',
     'img': '<code data-anolis-spec=html title="the img element">img</code>',
     'index': '<span data-anolis-spec=domrange title=concept-indexof>index</span>',
     'lastchild': '<code data-anolis-spec=domcore title=dom-Node-lastChild>lastChild</code>',
@@ -124,6 +126,7 @@
     s = s.replace("[[" + key.capitalize() + "]]", capreplace)
 
 fnreplace = {
+    'appendchild': '<code data-anolis-spec=domcore title=dom-Node-appendChild>appendChild(\\1)</code>',
     'createelement': '<code data-anolis-spec=domcore title=dom-Document-createElement>createElement(\\1)</code>',
     'deletedata': '<code data-anolis-spec=domcore title=dom-CharacterData-deleteData>deleteData(\\1)</code>',
     'extend': '<code data-anolis-spec=domrange title=dom-Selection-extend>extend(\\1)</code>',
@@ -139,7 +142,7 @@
     s = re.sub(r"\[\[" + key + "\|([^]]*)\]\]", fnreplace[key], s)
 
 if "[[" in s:
-    raise Exception("Something mistyped?  " + s[s.find("[["):s.rfind("]]") + 2])
+    raise Exception("Something mistyped?  " + s[s.find("[["):s.find("]]") + 2])
 
 s = s.replace("<var>", "<var title>")
 
--- a/source.html	Tue Jul 05 14:00:32 2011 -0600
+++ b/source.html	Tue Jul 05 15:38:01 2011 -0600
@@ -920,12 +920,7 @@
     data-anolis-spec=domcore title=dom-Node-cloneNode>cloneNode(false)</code>
     on <var>original parent</var>.
 
-    <p class=XXX>This will duplicate id's, as well as other bad things.  Do we
-    care?  We don't want to not copy attributes at all, because that wouldn't
-    copy style attributes, and Firefox in CSS mode will actually add style
-    attributes to any elements it feels like.  If we do exclude id's, even
-    though they'd only occur if someone manually added them, do we want to
-    exclude other things like itemid or accesskey or . . .
+    <li>If <var>original parent</var> has an [[id]] attribute, unset it.
 
     <li>Insert <var>cloned parent</var> into the [[parent]] of <var>original
     parent</var> immediately before <var>original parent</var>.
@@ -5333,7 +5328,7 @@
   -->
 
   <li>Let <var>value</var> be <span data-anolis-spec=domcore>converted to
-  lowercase</span>.
+  ASCII lowercase</span>.
 
   <li>If <var>value</var> is not "address", "div", "h1", "h2", "h3", "h4",
   "h5", "h6", "p", or "pre", raise a [[SYNTAX_ERR]] exception.
@@ -5581,7 +5576,7 @@
   with [[localname]] "address", "div", "h1", "h2", "h3", "h4", "h5", "h6", "p",
   or "pre", and <var>node</var> is not the [[ancestor]] of a <span>prohibited
   paragraph child</span>, return <var>node</var>'s [[localname]], <span
-  data-anolis-spec=domcore>converted to lowercase</span>.
+  data-anolis-spec=domcore>converted to ASCII lowercase</span>.
   <!--
   Chrome 14 dev will report "div" for <div><ol><li>foo</ol></div> or such.
   Opera 11.11 reports "".  IE and Firefox didn't cooperate with testing.  Opera
@@ -6325,24 +6320,26 @@
 
   <li>Copy all attributes of <var>container</var> to <var>new container</var>.
 
-  <p class=XXX>Copies id's.
+  <li>If <var>new container</var> has an [[id]] attribute, unset it.
 
   <li>Insert <var>new container</var> into the [[parent]] of
   <var>container</var> immediately after <var>container</var>.
 
-  <li>Let <var>frag</var> be the result of calling <code
-  data-anolis-spec=domrange
-  title=dom-Range-extractContents>extractContents()</code> on <var>new line
-  range</var>.
+  <li>Let <var>contained nodes</var> be all [[nodes]] [[contained]] in <var>new
+  line range</var>.
+
+  <li>Let <var>frag</var> be the result of calling [[extractcontents]] on
+  <var>new line range</var>.
 
   <p class=XXX>This blows up any ranges (other than the selection, which we
-  reset), duplicates id's, and other bad stuff.  May or may not be the best
-  solution.  The intermediate fragment is also probably black-box detectable by
-  DOM mutation events, but I like to pretend those don't exist.
-
-  <li>Call <code data-anolis-spec=domcore
-  title=dom-Node-appendChild>appendChild(<var>frag</var>)</code> on <var>new
-  container</var>.
+  reset), and maybe other bad stuff.  May or may not be the best solution.  The
+  intermediate fragment is also probably black-box detectable by DOM mutation
+  events, but I like to pretend those don't exist.
+
+  <li>Unset the [[id]] attribute (if any) of each [[element]] [[descendant]] of
+  <var>frag</var> that is not in <var>contained nodes</var>.
+
+  <li>Call [[appendchild|<var>frag</var>]] on <var>new container</var>.
 
   <li>If <var>container</var> has no [[children]], call [[createelement|"br"]]
   on the [[contextobject]], and append the result as the last [[child]] of