diff --git a/src/.jshintrc b/src/.jshintrc
index b3211355..1202b644 100644
--- a/src/.jshintrc
+++ b/src/.jshintrc
@@ -138,6 +138,7 @@
"JQLitePrototype": false,
"addEventListenerFn": false,
"removeEventListenerFn": false,
+ "jqLiteIsTextNode": false,
/* apis.js */
"hashKey": false,
diff --git a/src/jqLite.js b/src/jqLite.js
index 738f47a9..d03ea67b 100644
--- a/src/jqLite.js
+++ b/src/jqLite.js
@@ -179,6 +179,81 @@ function jqLitePatchJQueryRemove(name, dispatchThis, filterElems, getterIfNoArgu
}
}
+var SINGLE_TAG_REGEXP = /^<(\w+)\s*\/?>(?:<\/\1>|)$/;
+var HTML_REGEXP = /<|?\w+;/;
+var TAG_NAME_REGEXP = /<([\w:]+)/;
+var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi;
+
+var wrapMap = {
+ 'option': [1, ''],
+
+ 'thead': [1, '
'],
+ 'col': [2, ''],
+ 'tr': [2, ''],
+ 'td': [3, ''],
+ '_default': [0, "", ""]
+};
+
+wrapMap.optgroup = wrapMap.option;
+wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
+wrapMap.th = wrapMap.td;
+
+function jqLiteIsTextNode(html) {
+ return !HTML_REGEXP.test(html);
+}
+
+function jqLiteBuildFragment(html, context) {
+ var elem, tmp, tag, wrap,
+ fragment = context.createDocumentFragment(),
+ nodes = [], i;
+
+ if (jqLiteIsTextNode(html)) {
+ // Convert non-html into a text node
+ nodes.push(context.createTextNode(html));
+ } else {
+ // Convert html into DOM nodes
+ tmp = tmp || fragment.appendChild(context.createElement("div"));
+ tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
+ wrap = wrapMap[tag] || wrapMap._default;
+ tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1>$2>") + wrap[2];
+
+ // Descend through wrappers to the right content
+ i = wrap[0];
+ while (i--) {
+ tmp = tmp.lastChild;
+ }
+
+ nodes = concat(nodes, tmp.childNodes);
+
+ tmp = fragment.firstChild;
+ tmp.textContent = "";
+ }
+
+ // Remove wrapper from fragment
+ fragment.textContent = "";
+ fragment.innerHTML = ""; // Clear inner HTML
+ forEach(nodes, function(node) {
+ fragment.appendChild(node);
+ });
+
+ return fragment;
+}
+
+function jqLiteParseHTML(html, context) {
+ context = context || document;
+ var parsed;
+
+ if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
+ return [context.createElement(parsed[1])];
+ }
+
+ if ((parsed = jqLiteBuildFragment(html, context))) {
+ return parsed.childNodes;
+ }
+
+ return [];
+}
+
/////////////////////////////////////////////
function JQLite(element) {
if (element instanceof JQLite) {
@@ -195,14 +270,7 @@ function JQLite(element) {
}
if (isString(element)) {
- var div = document.createElement('div');
- // Read about the NoScope elements here:
- // http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
- div.innerHTML = '
' + element; // IE insanity to make NoScope elements work!
- div.removeChild(div.firstChild); // remove the superfluous div
- jqLiteAddNodes(this, div.childNodes);
- var fragment = jqLite(document.createDocumentFragment());
- fragment.append(this); // detach the elements from the temporary DOM div.
+ jqLiteAddNodes(this, jqLiteParseHTML(element));
} else {
jqLiteAddNodes(this, element);
}
diff --git a/src/ng/compile.js b/src/ng/compile.js
index 58c3b5fc..98159551 100644
--- a/src/ng/compile.js
+++ b/src/ng/compile.js
@@ -513,8 +513,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
var hasDirectives = {},
Suffix = 'Directive',
COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,
- CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/,
- TABLE_CONTENT_REGEXP = /^<\s*(tr|th|td|thead|tbody|tfoot)(\s+[^>]*)?>/i;
+ CLASS_DIRECTIVE_REGEXP = /(([\d\w\-_]+)(?:\:([^;]+))?;?)/;
// Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
// The assumption is that future DOM event attribute names will begin with
@@ -1259,7 +1258,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
if (directive.replace) {
replaceDirective = directive;
- $template = directiveTemplateContents(directiveValue);
+ if (jqLiteIsTextNode(directiveValue)) {
+ $template = [];
+ } else {
+ $template = jqLite(directiveValue);
+ }
compileNode = $template[0];
if ($template.length != 1 || compileNode.nodeType !== 1) {
@@ -1658,27 +1661,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
}
- function directiveTemplateContents(template) {
- var type;
- template = trim(template);
- if ((type = TABLE_CONTENT_REGEXP.exec(template))) {
- type = type[1].toLowerCase();
- var table = jqLite('');
- if (/(thead|tbody|tfoot)/.test(type)) {
- return table.children(type);
- }
- table = table.children('tbody');
- if (type === 'tr') {
- return table.children('tr');
- }
- return table.children('tr').contents();
- }
- return jqLite('' +
- template +
- '
').contents();
- }
-
-
function compileTemplateUrl(directives, $compileNode, tAttrs,
$rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
var linkQueue = [],
@@ -1703,7 +1685,11 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
content = denormalizeTemplate(content);
if (origAsyncDirective.replace) {
- $template = directiveTemplateContents(content);
+ if (jqLiteIsTextNode(content)) {
+ $template = [];
+ } else {
+ $template = jqLite(content);
+ }
compileNode = $template[0];
if ($template.length != 1 || compileNode.nodeType !== 1) {
diff --git a/test/jqLiteSpec.js b/test/jqLiteSpec.js
index faf1c98c..f9c6f3a2 100644
--- a/test/jqLiteSpec.js
+++ b/test/jqLiteSpec.js
@@ -95,6 +95,36 @@ describe('jqLite', function() {
expect(fragment.length).toBe(1);
expect(fragment[0].nodeType).toBe(11);
});
+
+
+ it('should allow construction of