Clean up and implement insertImage
authorAryeh Gregor <AryehGregor+gitcommit@gmail.com>
Tue, 12 Apr 2011 15:31:49 -0600
changeset 56 c540bdbe5897
parent 55 cdfb46b20f06
child 57 862c9fe11c1c
Clean up and implement insertImage
autoimplementation.html
editcommands.html
implementation.js
source.html
--- a/autoimplementation.html	Tue Apr 12 15:09:14 2011 -0600
+++ b/autoimplementation.html	Tue Apr 12 15:31:49 2011 -0600
@@ -25,7 +25,7 @@
 dfn { font-style: italic }
 /* We don't want test cells to not wrap */
 listing, plaintext, pre, xmp { white-space: pre-wrap }
-video { width: 50px }
+img, video { width: 50px }
 </style>
 <p>Legend: {[ are the selection anchor, }] are the selection focus, {}
 represent an element boundary point, [] represent a text node boundary point.
@@ -50,6 +50,7 @@
 	<li><a href=#fontsize>fontsize</a>
 	<li><a href=#forecolor>forecolor</a>
 	<li><a href=#hilitecolor>hilitecolor</a>
+	<li><a href=#insertimage>insertimage</a>
 	<li><a href=#italic>italic</a>
 	<li><a href=#removeformat>removeformat</a>
 	<li><a href=#strikethrough>strikethrough</a>
@@ -150,6 +151,17 @@
 <button onclick="addTest('hilitecolor')">Add test</button>
 </div>
 
+<div id=insertimage>
+<h1>insertimage</h1>
+
+<button onclick="runTests('insertimage')">Run tests</button>
+
+<table border=1><tr><th>Input <th>Spec <th>Browser <th>Same?</table>
+
+<p><label>New test input: <input></label><label>New test value: <input></label>
+<button onclick="addTest('insertimage')">Add test</button>
+</div>
+
 <div id=italic>
 <h1>italic</h1>
 
@@ -564,6 +576,11 @@
 		'<div style="background-color: #ff8888"><p style="background-color: aqua">b[ar]</p></div>',
 		'<span style="display: block; background-color: #ff8888"><span style="display: block; background-color: aqua">b[ar]</span></span>',
 	],
+	insertimage: [
+		["", 'foo[bar]baz'],
+		'foo[bar]baz',
+		'foo<b>{bar}</b>baz',
+	],
 	italic: [
 		'foo[bar]baz',
 		'foo]bar[baz',
@@ -982,6 +999,7 @@
 	fontsize: "4",
 	forecolor: "#FF0000",
 	hilitecolor: "#FF8888",
+	insertimage: "/img/lion.svg",
 };
 
 function runTests(command) {
--- a/editcommands.html	Tue Apr 12 15:09:14 2011 -0600
+++ b/editcommands.html	Tue Apr 12 15:31:49 2011 -0600
@@ -1572,7 +1572,7 @@
 
 <dt><code title=""><dfn id=command-insertimage title=command-insertimage>insertImage</dfn></code>
 
-<dd><strong>Action</strong>: The user agent must run the following steps:
+<dd><strong>Action</strong>:
 
 <ol>
   <li>If <var title="">value</var> is the empty string, abort these steps and do
@@ -1588,18 +1588,27 @@
   <li>Let (<var title="">node</var>, <var title="">offset</var>) be 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>.
 
-  <li>Let <var title="">img</var> be a new <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> "img", the same <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> as <var title="">node</var>, and a
-  single <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> "src" and with
-  <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> <var title="">value</var>.
+  <li>If <var title="">node</var> 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> or <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment>Comment</a></code> node 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 null, abort these steps and do nothing.
+
+  <li>Let <var title="">img</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("img")</a></code> on the
+  <code class=external data-anolis-spec=domcore title=dom-Node-ownerDocument><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-ownerdocument>ownerDocument</a></code> of <var title="">node</var> (or on <var title="">node</var> itself if it's a
+  <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#document>Document</a></code>).
+
+  <li>Run <code class=external data-anolis-spec=domcore title=dom-Element-setAttribute><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-element-setattribute>setAttribute("src", <var title="">value</var>)</a></code>
+  on <var title="">img</var>.
   <!-- No alt text, so it's invalid.  This matches all browsers. -->
 
   <li>If <var title="">node</var> 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="">offset</var> is not
   equal to 0 or 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 <var title="">node</var>, run <code class=external data-anolis-spec=domcore title=dom-Text-splitText><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-text-splittext>splitText(<var title="">offset</var>)</a></code> on
   <var title="">node</var>.
 
-  <li>If <var title="">node</var> 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>, <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment>Comment</a></code>, or
-  <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#processinginstruction>ProcessingInstruction</a></code> node, run <code class=external data-anolis-spec=domcore title=dom-Node-insertBefore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-insertbefore>insertBefore(<var title="">img</var>,
+  <li>If <var title="">node</var> 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="">offset</var> is 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 <var title="">node</var>, set <var title="">node</var> to its
+  <code class=external data-anolis-spec=domcore title=dom-Node-nextSibling><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-nextsibling>nextSibling</a></code>.
+
+  <li>If <var title="">node</var> is null or 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> or <code class=external data-anolis-spec=domcore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#comment>Comment</a></code> node, run
+  <code class=external data-anolis-spec=domcore title=dom-Node-insertBefore><a href=http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html#dom-node-insertbefore>insertBefore(<var title="">img</var>,
   <var title="">node</var>)</a></code> on the parent of <var title="">node</var>.
 
   <li>Otherwise, let <var title="">child</var> be the <var title="">offset</var>th child of
--- a/implementation.js	Tue Apr 12 15:09:14 2011 -0600
+++ b/implementation.js	Tue Apr 12 15:31:49 2011 -0600
@@ -1828,6 +1828,66 @@
 		}
 		break;
 
+		case "insertimage":
+		// "If value is the empty string, abort these steps and do nothing."
+		if (value === "") {
+			return;
+		}
+
+		// "Run deleteContents() on the range."
+		range.deleteContents();
+
+		// "Let (node, offset) be the range's start."
+		var node = range.startContainer;
+		var offset = range.startOffset;
+
+		// "If node is a Text or Comment node and its parent is null, abort
+		// these steps and do nothing."
+		if (!node.parentNode
+		&& (node.nodeType == Node.TEXT_NODE
+		|| node.nodeType == Node.COMMENT_NODE)) {
+			return;
+		}
+
+		// "Let img be the result of calling createElement("img") on the
+		// ownerDocument of node (or on node itself if it's a Document)."
+		var img = (node.nodeType == Node.DOCUMENT_NODE
+			? node : node.ownerDocument).createElement("img");
+
+		// "Run setAttribute("src", value) on img."
+		img.setAttribute("src", value);
+
+		// "If node is a Text node, and offset is not equal to 0 or the length
+		// of node, run splitText(offset) on node."
+		if (node.nodeType == Node.TEXT_NODE
+		&& offset != 0
+		&& offset != node.length) {
+			node.splitText(offset);
+		}
+
+		// "If node is a Text node, and offset is equal to the length of node,
+		// set node to its nextSibling."
+		if (node.nodeType == Node.TEXT_NODE
+		&& offset == node.length) {
+			node = node.nextSibling;
+		}
+
+		// "If node is null or is a Text or Comment node, run insertBefore(img,
+		// node) on the parent of node."
+		if (!node
+		|| node.nodeType == Node.TEXT_NODE
+		|| node.nodeType == Node.COMMENT_NODE) {
+			node.parentNode.insertBefore(img, node);
+		// "Otherwise, let child be the offsetth child of node (or null if
+		// there is no such child), and run insertBefore(img, child) on node."
+		} else {
+			var child = node.childNodes.length == offset
+				? null
+				: node.childNodes[offset];
+			node.insertBefore(img, child);
+		}
+		break;
+
 		case "italic":
 		// "Decompose the range. If the state of the range for this command is
 		// then true, set the value of each returned node with new value
--- a/source.html	Tue Apr 12 15:09:14 2011 -0600
+++ b/source.html	Tue Apr 12 15:31:49 2011 -0600
@@ -1585,7 +1585,7 @@
 
 <dt><code title><dfn title=command-insertimage>insertImage</dfn></code>
 
-<dd><strong>Action</strong>: The user agent must run the following steps:
+<dd><strong>Action</strong>:
 
 <ol>
   <li>If <var>value</var> is the empty string, abort these steps and do
@@ -1602,10 +1602,18 @@
   <li>Let (<var>node</var>, <var>offset</var>) be the [[range]]'s
   [[rangestart]].
 
-  <li>Let <var>img</var> be a new <span>HTML element</span> with
-  [[localname]] "img", the same [[ownerdocument]] as <var>node</var>, and a
-  single <span>HTML attribute</span> with [[attrlocalname]] "src" and with
-  [[attrvalue]] <var>value</var>.
+  <li>If <var>node</var> is a [[text]] or [[comment]] node and its [[parent]]
+  is null, abort these steps and do nothing.
+
+  <li>Let <var>img</var> be the result of calling <code
+  data-anolis-spec=domcore
+  title=dom-Document-createElement>createElement("img")</code> on the
+  [[ownerdocument]] of <var>node</var> (or on <var>node</var> itself if it's a
+  [[document]]).
+
+  <li>Run <code data-anolis-spec=domcore
+  title=dom-Element-setAttribute>setAttribute("src", <var>value</var>)</code>
+  on <var>img</var>.
   <!-- No alt text, so it's invalid.  This matches all browsers. -->
 
   <li>If <var>node</var> is a [[text]] node, and <var>offset</var> is not
@@ -1614,8 +1622,12 @@
   title=dom-Text-splitText>splitText(<var>offset</var>)</code> on
   <var>node</var>.
 
-  <li>If <var>node</var> is a [[text]], [[comment]], or
-  [[processinginstruction]] node, run <code data-anolis-spec=domcore
+  <li>If <var>node</var> is a [[text]] node, and <var>offset</var> is equal to
+  the [[nodelength]] of <var>node</var>, set <var>node</var> to its
+  [[nextsibling]].
+
+  <li>If <var>node</var> is null or is a [[text]] or [[comment]] node, run
+  <code data-anolis-spec=domcore
   title=dom-Node-insertBefore>insertBefore(<var>img</var>,
   <var>node</var>)</code> on the parent of <var>node</var>.