Permalink
Browse files

Manipulation: Make an HTML interception point

Fixes gh-1747
Closes gh-2203
  • Loading branch information...
gibson042 committed Apr 10, 2015
1 parent 4b27ae1 commit 225bde37c997f5ddd9fe00fdfb8e9a43545cfbbc
Showing with 85 additions and 50 deletions.
  1. +6 −2 src/manipulation.js
  2. +4 −8 test/unit/core.js
  3. +75 −40 test/unit/manipulation.js
View
@@ -159,6 +159,10 @@ function fixInput( src, dest ) {
}
jQuery.extend({
+ htmlPrefilter: function( html ) {
+ return html.replace( rxhtmlTag, "<$1></$2>" );
+ },
+
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
var i, l, srcElements, destElements,
clone = elem.cloneNode( true ),
@@ -230,7 +234,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 ];
@@ -422,7 +426,7 @@ jQuery.fn.extend({
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
- value = value.replace( rxhtmlTag, "<$1></$2>" );
+ value = jQuery.htmlPrefilter( value );
try {
for ( ; i < l; i++ ) {
View
@@ -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",
@@ -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() {
View
@@ -2080,7 +2080,7 @@ test( "jQuery.cleanData eliminates all private data (gh-2127)", function() {
div.remove();
});
-test( "jQuery.buildFragment - no plain-text caching (Bug #6779)", function() {
+test( "domManip plain-text caching (trac-6779)", function() {
expect( 1 );
@@ -2099,42 +2099,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() {
@@ -2296,12 +2297,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 );
@@ -2385,6 +2380,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 );

0 comments on commit 225bde3

Please sign in to comment.