Skip to content

Commit

Permalink
Manipulation: Make an HTML interception point
Browse files Browse the repository at this point in the history
Fixes gh-1747
Closes gh-2203

(cherry picked from commit 225bde3)

Conflicts:
	src/manipulation.js
	test/unit/manipulation.js
  • Loading branch information
gibson042 committed Apr 30, 2015
1 parent 4cafb58 commit fb25bac
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 51 deletions.
9 changes: 6 additions & 3 deletions src/manipulation.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,10 @@ function fixCloneNodeIssues( src, dest ) {
}

jQuery.extend({
htmlPrefilter: function( html ) {
return html.replace( rxhtmlTag, "<$1></$2>" );
},

clone: function( elem, dataAndEvents, deepDataAndEvents ) {
var destElements, node, clone, i, srcElements,
inPage = jQuery.contains( elem.ownerDocument, elem );
Expand Down Expand Up @@ -304,8 +308,7 @@ jQuery.extend({
// Deserialize a standard representation
tag = (rtagName.exec( elem ) || [ "", "" ])[ 1 ].toLowerCase();
wrap = wrapMap[ tag ] || wrapMap._default;

tmp.innerHTML = wrap[1] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[2];
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];

// Descend through wrappers to the right content
j = wrap[0];
Expand Down Expand Up @@ -549,7 +552,7 @@ jQuery.fn.extend({
( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) &&
!wrapMap[ (rtagName.exec( value ) || [ "", "" ])[ 1 ].toLowerCase() ] ) {

value = value.replace( rxhtmlTag, "<$1></$2>" );
value = jQuery.htmlPrefilter( value );

try {
for (; i < l; i++ ) {
Expand Down
12 changes: 4 additions & 8 deletions test/unit/core.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ test("jQuery()", function() {
img = jQuery("<img/>"),
div = jQuery("<div/><hr/><code/><b/>"),
exec = false,
lng = "",
expected = 22,
expected = 23,
attrObj = {
"text": "test",
"class": "test2",
Expand Down Expand Up @@ -141,12 +140,9 @@ test("jQuery()", function() {
}
equal( elem[0].defaultValue, "TEST", "Ensure cached nodes are cloned properly (Bug #6655)" );

// manually clean up detached elements
elem.remove();

for ( i = 0; i < 128; i++ ) {
lng += "12345678";
}
elem = jQuery( "<input type='hidden'>", {} );
strictEqual( elem[ 0 ].ownerDocument, document,
"Empty attributes object is not interpreted as a document (trac-8950)" );
});

test("jQuery(selector, context)", function() {
Expand Down
115 changes: 75 additions & 40 deletions test/unit/manipulation.js
Original file line number Diff line number Diff line change
Expand Up @@ -2137,7 +2137,7 @@ test( "jQuery.cleanData", function() {
}
});

test( "jQuery.buildFragment - no plain-text caching (Bug #6779)", function() {
test( "domManip plain-text caching (trac-6779)", function() {

expect( 1 );

Expand All @@ -2156,42 +2156,43 @@ test( "jQuery.buildFragment - no plain-text caching (Bug #6779)", function() {
$f.remove();
});

test( "jQuery.html - execute scripts escaped with html comment or CDATA (#9221)", function() {
test( "domManip executes scripts containing html comments or CDATA (trac-9221)", function() {

expect( 3 );

jQuery([
"<script type='text/javascript'>",
"<!--",
"ok( true, '<!-- handled' );",
"//-->",
"</script>"
].join("\n")).appendTo("#qunit-fixture");
jQuery([
"<script type='text/javascript'>",
"<![CDATA[",
"ok( true, '<![CDATA[ handled' );",
"//]]>",
"</script>"
].join("\n")).appendTo("#qunit-fixture");
jQuery([
"<script type='text/javascript'>",
"<!--//--><![CDATA[//><!--",
"ok( true, '<!--//--><![CDATA[//><!-- (Drupal case) handled' );",
"//--><!]]>",
"</script>"
].join("\n")).appendTo("#qunit-fixture");
});

test( "jQuery.buildFragment - plain objects are not a document #8950", function() {

expect( 1 );

try {
jQuery( "<input type='hidden'>", {} );
ok( true, "Does not allow attribute object to be treated like a doc object" );
} catch ( e ) {}
});
jQuery( [
"<script type='text/javascript'>",
"<!--",
"ok( true, '<!-- handled' );",
"//-->",
"</script>"
].join( "\n" ) ).appendTo( "#qunit-fixture" );

jQuery( [
"<script type='text/javascript'>",
"<![CDATA[",
"ok( true, '<![CDATA[ handled' );",
"//]]>",
"</script>"
].join( "\n" ) ).appendTo( "#qunit-fixture" );

jQuery( [
"<script type='text/javascript'>",
"<!--//--><![CDATA[//><!--",
"ok( true, '<!--//--><![CDATA[//><!-- (Drupal case) handled' );",
"//--><!]]>",
"</script>"
].join( "\n" ) ).appendTo( "#qunit-fixture" );
});

testIframeWithCallback(
"domManip tolerates window-valued document[0] in IE9/10 (trac-12266)",
"manipulation/iframe-denied.html",
function( test ) {
expect( 1 );
ok( test.status, test.description );
}
);

test( "jQuery.clone - no exceptions for object elements #9587", function() {

Expand Down Expand Up @@ -2360,12 +2361,6 @@ test( "manipulate mixed jQuery and text (#12384, #12346)", function() {
equal( div.find("*").length, 3, "added 2 paragraphs after inner div" );
});

testIframeWithCallback( "buildFragment works even if document[0] is iframe's window object in IE9/10 (#12266)", "manipulation/iframe-denied.html", function( test ) {
expect( 1 );

ok( test.status, test.description );
});

test( "script evaluation (#11795)", function() {

expect( 13 );
Expand Down Expand Up @@ -2449,6 +2444,46 @@ test( "jQuery._evalUrl (#12838)", function() {
jQuery._evalUrl = evalUrl;
});

test( "jQuery.htmlPrefilter (gh-1747)", function( assert ) {

assert.expect( 5 );

var expectedArgument,
invocations = 0,
htmlPrefilter = jQuery.htmlPrefilter,
fixture = jQuery( "<div/>" ).appendTo( "#qunit-fixture" ),
poison = "<script>jQuery.htmlPrefilter.assert.ok( false, 'script not executed' );</script>",
done = assert.async();

jQuery.htmlPrefilter = function( html ) {
invocations++;
assert.equal( html, expectedArgument, "Expected input" );

// Remove <script> and <del> elements
return htmlPrefilter.apply( this, arguments )
.replace( /<(script|del)(?=[\s>])[\w\W]*?<\/\1\s*>/ig, "" );
};
jQuery.htmlPrefilter.assert = assert;

expectedArgument = "A-" + poison + "B-" + poison + poison + "C-";
fixture.html( expectedArgument );

expectedArgument = "D-" + poison + "E-" + "<del/><div>" + poison + poison + "</div>" + "F-";
fixture.append( expectedArgument );

expectedArgument = poison;
fixture.find( "div" ).replaceWith( expectedArgument );

assert.equal( invocations, 3, "htmlPrefilter invoked for all DOM manipulations" );
assert.equal( fixture.html(), "A-B-C-D-E-F-", "htmlPrefilter modified HTML" );

// Allow asynchronous script execution to generate assertions
setTimeout( function() {
jQuery.htmlPrefilter = htmlPrefilter;
done();
}, 100 );
});

test( "insertAfter, insertBefore, etc do not work when destination is original element. Element is removed (#4087)", function() {

expect( 10 );
Expand Down

0 comments on commit fb25bac

Please sign in to comment.