Skip to content

Commit

Permalink
Work around fact that latest 1.x jQuery doesn't correctly parse eleme…
Browse files Browse the repository at this point in the history
…nts like with tr-component, tbody-component, etc. Also fix issue with parsed <option> being selected in IE 8.
  • Loading branch information
mbest committed Aug 28, 2015
1 parent aae6bf0 commit 200f196
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 12 deletions.
10 changes: 3 additions & 7 deletions spec/parseHtmlFragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ describe('Parse HTML fragment', function() {
{ html: '<tbody></tbody>', parsed: ['<tbody></tbody>'] },
{ html: '<table><tbody></tbody></table>', parsed: ['<table><tbody></tbody></table>'] },
{ html: '<div></div><div></div>', parsed: ['<div></div>', '<div></div>'] },
{ html: '<optgroup label="x"><option>text</option></optgroup>', parsedChoices: [ [ '<optgroup label="x"><option>text</option></optgroup>' ], [ '<optgroup label=x><option selected>text</option></optgroup>' ] ] },
{ html: '<option>text</option>', parsedChoices: [ [ '<option>text</option>' ], [ '<option selected>text</option>' ] ] }
{ html: '<optgroup label="x"><option>text</option></optgroup>', parsed: [ '<optgroup label="?x"?><option>text</option></optgroup>' ] },
{ html: '<option>text</option>', parsed: [ '<option>text</option>' ] }
], function (data) {
it('should parse ' + data.html + ' correctly', function () {
var parsedNodes = ko.utils.parseHtmlFragment(data.html, document);
Expand All @@ -31,11 +31,7 @@ describe('Parse HTML fragment', function() {
var parsedStrings = ko.utils.arrayMap(parsedNodes, function (node) {
return node.outerHTML && node.outerHTML.toLowerCase().replace(/\r\n/g, "");
});
if (data.parsedChoices) {
expect(parsedStrings).toEqualOneOf(data.parsedChoices);
} else {
expect(parsedStrings).toEqual(data.parsed);
}
expect(parsedStrings).toMatch(data.parsed);
}
});
});
Expand Down
20 changes: 15 additions & 5 deletions src/utils.domManipulation.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
table = [1, "<table>", "</table>"],
tbody = [2, "<table><tbody>", "</tbody></table>"],
tr = [3, "<table><tbody><tr>", "</tr></tbody></table>"],
select = [1, "<select>", "</select>"],
select = [1, "<select multiple='multiple'>", "</select>"],
lookup = {
'thead': table,
'tbody': table,
Expand All @@ -13,7 +13,8 @@
'th': tr,
'option': select,
'optgroup': select
};
},
jQueryCanParseTrComponent;

function getWrap(tags) {
var m = tags.match(/^<([a-z]+)[ >]/);
Expand Down Expand Up @@ -53,6 +54,14 @@
return ko.utils.makeArray(div.lastChild.childNodes);
}

function shouldUseJQueryToParse(html) {
if (jQueryCanParseTrComponent === undefined) {
jQueryCanParseTrComponent = (jQueryHtmlParse('<tr-component></tr-component>').length > 0);
}
var isCustomElement = /^<[a-z]+-[a-z]+[ >]/.test(html);
return !isCustomElement || jQueryCanParseTrComponent;
}

function jQueryHtmlParse(html, documentContext) {
// jQuery's "parseHTML" function was introduced in jQuery 1.8.0 and is a documented public API.
if (jQueryInstance['parseHTML']) {
Expand All @@ -79,8 +88,9 @@
}

ko.utils.parseHtmlFragment = function(html, documentContext) {
return jQueryInstance ? jQueryHtmlParse(html, documentContext) // As below, benefit from jQuery's optimisations where possible
: simpleHtmlParse(html, documentContext); // ... otherwise, this simple logic will do in most common cases.
return (jQueryInstance && shouldUseJQueryToParse(html)) ?
jQueryHtmlParse(html, documentContext) : // As below, benefit from jQuery's optimisations where possible
simpleHtmlParse(html, documentContext); // ... otherwise, this simple logic will do in most common cases.
};

ko.utils.setHtml = function(node, html) {
Expand All @@ -96,7 +106,7 @@
// jQuery contains a lot of sophisticated code to parse arbitrary HTML fragments,
// for example <tr> elements which are not normally allowed to exist on their own.
// If you've referenced jQuery we'll use that rather than duplicating its code.
if (jQueryInstance) {
if (jQueryInstance && shouldUseJQueryToParse(html)) {
jQueryInstance(node)['html'](html);
} else {
// ... otherwise, use KO's own parsing logic.
Expand Down

0 comments on commit 200f196

Please sign in to comment.