']
+};
+markupWrap['optgroup'] = markupWrap['option'];
+markupWrap['tbody'] = markupWrap['thead'];
+markupWrap['tfoot'] = markupWrap['thead'];
+markupWrap['colgroup'] = markupWrap['thead'];
+markupWrap['caption'] = markupWrap['thead'];
+markupWrap['th'] = markupWrap['td'];
+
+/**
+ * In IE8, certain elements cannot render alone, so wrap all elements.
+ */
+var defaultWrap = [1, '?
', '
'];
+
+/**
+ * Feature detection, remove wraps that are unnecessary for the current browser.
+ */
+if (dummyNode) {
+ for (var nodeName in markupWrap) {
+ if (!markupWrap.hasOwnProperty(nodeName)) {
+ continue;
+ }
+ dummyNode.innerHTML = '<' + nodeName + '>' + nodeName + '>';
+ if (dummyNode.firstChild) {
+ markupWrap[nodeName] = null;
+ }
+ }
+ dummyNode.innerHTML = '';
+ if (dummyNode.firstChild) {
+ defaultWrap = null;
+ }
+}
+
+/**
+ * Renders markup into nodes. The returned HTMLCollection is live and should be
+ * used immediately (or at least before the next invocation to `renderMarkup`).
+ *
+ * NOTE: Extracting the `nodeName` does not require a regular expression match
+ * because we make assumptions about React-generated markup (i.e. there are no
+ * spaces surrounding the opening tag and there is at least one attribute).
+ * @see http://jsperf.com/extract-nodename
+ *
+ * @param {string} markup
+ * @return {*} An HTMLCollection.
+ */
+function renderMarkup(markup) {
+ var node = dummyNode;
+ var nodeName = markup.substring(1, markup.indexOf(' '));
+
+ var wrap = markupWrap[nodeName.toLowerCase()] || defaultWrap;
+ if (wrap) {
+ node.innerHTML = wrap[1] + markup + wrap[2];
+
+ var wrapDepth = wrap[0];
+ while (wrapDepth--) {
+ node = node.lastChild;
+ }
+ } else {
+ node.innerHTML = markup;
+ }
+ return node.childNodes;
}
/**
@@ -122,9 +196,7 @@ function dangerouslyInsertMarkupAt(parentNode, markup, index) {
if (__DEV__) {
validateMarkupParams(parentNode, markup);
}
- var parentDummy = getParentDummy(parentNode);
- parentDummy.innerHTML = markup;
- var htmlCollection = parentDummy.childNodes;
+ var htmlCollection = renderMarkup(markup);
var afterNode = index ? parentNode.childNodes[index - 1] : null;
inefficientlyInsertHTMLCollectionAfter(parentNode, htmlCollection, afterNode);
}
@@ -143,9 +215,7 @@ function dangerouslyReplaceNodeWithMarkup(childNode, markup) {
if (__DEV__) {
validateMarkupParams(parentNode, markup);
}
- var parentDummy = getParentDummy(parentNode);
- parentDummy.innerHTML = markup;
- var htmlCollection = parentDummy.childNodes;
+ var htmlCollection = renderMarkup(markup);
if (__DEV__) {
throwIf(htmlCollection.length !== 1, NO_MULTI_MARKUP);
}
diff --git a/src/dom/__tests__/Danger-test.js b/src/dom/__tests__/Danger-test.js
new file mode 100644
index 0000000000..480c42f5d7
--- /dev/null
+++ b/src/dom/__tests__/Danger-test.js
@@ -0,0 +1,69 @@
+/**
+ * Copyright 2013 Facebook, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * @jsx React.DOM
+ * @emails react-core
+ */
+
+/*jslint evil: true */
+
+var React = require('React');
+
+describe('Danger', function() {
+
+ describe('dangerouslyInsertMarkupAt', function() {
+ var Danger;
+ var transaction;
+
+ beforeEach(function() {
+ require('mock-modules').dumpCache();
+ Danger = require('Danger');
+
+ var ReactReconcileTransaction = require('ReactReconcileTransaction');
+ transaction = new ReactReconcileTransaction();
+ });
+
+ it('should render markup', function() {
+ var markup = ().mountComponent('.rX', transaction);
+ var parent = document.createElement('div');
+
+ Danger.dangerouslyInsertMarkupAt(parent, markup, 0);
+
+ expect(parent.innerHTML).toBe('');
+ });
+
+ it('should render markup with props', function() {
+ var markup = ().mountComponent('.rX', transaction);
+ var parent = document.createElement('div');
+
+ Danger.dangerouslyInsertMarkupAt(parent, markup, 0);
+
+ expect(parent.innerHTML).toBe(
+ ''
+ );
+ });
+
+ it('should render wrapped markup', function() {
+ var markup = (