Skip to content

Commit

Permalink
WIP Core: Switch $.parseHTML from document.implementation to `DOM…
Browse files Browse the repository at this point in the history
…Parser`

Firefox has a bug:
https://bugzilla.mozilla.org/show_bug.cgi?id=1205631
where assignment to `innerHTML` produces a different DOM tree than passing the
HTML to `document.write()`; other browsers use the same algorithm in both
places, the same one Firefox uses for `document.write()`. Firefox's behavior
used to be spec-compliant but the spec changed in:
whatwg/html#6399

Because `$.parseHTML` used to use:
```js
document.implementation.createHTMLDocument( "" )
```
followed by an `innerHTML` assignment under the hood, Firefox was hitting that
issue.

TODO we cannot pass `data` to `parseFromString` like that as it goes through
`buildFragment` later anyway.

Ref whatwg/html#5117
Ref whatwg/html#6399
  • Loading branch information
mgol committed Oct 20, 2024
1 parent d928106 commit bd67b93
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 11 deletions.
14 changes: 3 additions & 11 deletions src/core/parseHTML.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { jQuery } from "../core.js";
import { document } from "../var/document.js";
import { rsingleTag } from "./var/rsingleTag.js";
import { buildFragment } from "../manipulation/buildFragment.js";
import { isObviousHtml } from "./isObviousHtml.js";
Expand All @@ -17,20 +16,13 @@ jQuery.parseHTML = function( data, context, keepScripts ) {
context = false;
}

var base, parsed, scripts;
var parsed, scripts;

if ( !context ) {

// Stop scripts or inline event handlers from being executed immediately
// by using document.implementation
context = document.implementation.createHTMLDocument( "" );

// Set the base href for the created document
// so any parsed elements with URLs
// are based on the document's URL (gh-2965)
base = context.createElement( "base" );
base.href = document.location.href;
context.head.appendChild( base );
// by using DOMParser
context = ( new window.DOMParser() ).parseFromString( data, "text/html" );
}

parsed = rsingleTag.exec( data );
Expand Down
41 changes: 41 additions & 0 deletions test/unit/manipulation.js
Original file line number Diff line number Diff line change
Expand Up @@ -3073,6 +3073,47 @@ QUnit.test( "Sanitized HTML doesn't get unsanitized", function( assert ) {
}
} );

QUnit.test( "Parsing consistent with `document.write`", function( assert ) {
var domStructure;

assert.expect( 1 );

function repeatString( str, count ) {
var ret = "";
while ( count ) {
ret += str;
count--;
}
return ret;
}

function serializeNodeNames( nodes, offset ) {
var i, node,
result = "";
offset = offset || 0;

for ( i = 0; i < nodes.length; i++ ) {
node = nodes[ i ];
result += repeatString( " ", offset ) + node.nodeName.toLowerCase() + "\n";
result += serializeNodeNames( node.childNodes, offset + 1 );
}

return result;
}

domStructure = jQuery.parseHTML(
"<svg><p><style><img src=\"</style><img//\">" );

assert.strictEqual( serializeNodeNames( domStructure ),
"svg\n" +
"p\n" +
" style\n" +
" #text\n" +
" img\n" +
"",
"Parsing consistent with `document.write`" );
} );

QUnit.test( "Works with invalid attempts to close the table wrapper", function( assert ) {
assert.expect( 3 );

Expand Down

0 comments on commit bd67b93

Please sign in to comment.