jQuery: The Write Less, Do More JavaScript Library

Changeset 4062

Show
Ignore:
Timestamp:
12/07/07 01:52:21 (8 months ago)
Author:
davidserduke
Message:

Fixed #1039 and #1733 by going through the core API and making them text node and comment node safe.

Location:
trunk/jquery
Files:
8 modified

Legend:

Unmodified
Added
Removed
  • trunk/jquery/src/core.js

    r4041 r4062  
    252252    append: function() { 
    253253        return this.domManip(arguments, true, false, function(elem){ 
    254             this.appendChild( elem ); 
     254            if (this.nodeType == 1) 
     255                this.appendChild( elem ); 
    255256        }); 
    256257    }, 
     
    258259    prepend: function() { 
    259260        return this.domManip(arguments, true, true, function(elem){ 
    260             this.insertBefore( elem, this.firstChild ); 
     261            if (this.nodeType == 1) 
     262                this.insertBefore( elem, this.firstChild ); 
    261263        }); 
    262264    }, 
     
    403405        } else 
    404406            return this.each(function(){ 
     407                if ( this.nodeType != 1 ) 
     408                    return; 
     409 
    405410                if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) 
    406411                    this.checked = (jQuery.inArray(this.value, value) >= 0 || 
     
    723728        add: function( elem, classNames ) { 
    724729            jQuery.each((classNames || "").split(/\s+/), function(i, className){ 
    725                 if ( !jQuery.className.has( elem.className, className ) ) 
     730                if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) 
    726731                    elem.className += (elem.className ? " " : "") + className; 
    727732            }); 
     
    730735        // internal only, use removeClass("class") 
    731736        remove: function( elem, classNames ) { 
    732             elem.className = classNames != undefined ? 
    733                 jQuery.grep(elem.className.split(/\s+/), function(className){ 
    734                     return !jQuery.className.has( classNames, className );   
    735                 }).join(" ") : 
    736                 ""; 
     737            if (elem.nodeType == 1) 
     738                elem.className = classNames != undefined ? 
     739                    jQuery.grep(elem.className.split(/\s+/), function(className){ 
     740                        return !jQuery.className.has( classNames, className );   
     741                    }).join(" ") : 
     742                    ""; 
    737743        }, 
    738744 
     
    10151021     
    10161022    attr: function( elem, name, value ) { 
     1023        // don't set attributes on text and comment nodes 
     1024        if (!elem || elem.nodeType == 3 || elem.nodeType == 8) 
     1025            return undefined; 
     1026 
    10171027        var fix = jQuery.isXMLDoc( elem ) ? 
    10181028            {} : 
     
    12681278    removeAttr: function( name ) { 
    12691279        jQuery.attr( this, name, "" ); 
    1270         this.removeAttribute( name ); 
     1280        if (this.nodeType == 1)  
     1281            this.removeAttribute( name ); 
    12711282    }, 
    12721283 
  • trunk/jquery/src/event.js

    r4001 r4062  
    99    // Original by Dean Edwards 
    1010    add: function(element, type, handler, data) { 
     11        if ( element.nodeType == 3 || element.nodeType == 8 ) 
     12            return; 
     13 
    1114        // For whatever reason, IE has trouble passing the window object 
    1215        // around, causing it to be cloned in the process 
     
    8487    // Detach an event or set of events from an element 
    8588    remove: function(element, type, handler) { 
     89        // don't do events on text and comment nodes 
     90        if ( element.nodeType == 3 || element.nodeType == 8 ) 
     91            return; 
     92 
    8693        var events = jQuery.data(element, "events"), ret, index; 
    8794 
     
    148155        // Handle triggering a single element 
    149156        } else { 
     157            // don't do events on text and comment nodes 
     158            if ( element.nodeType == 3 || element.nodeType == 8 ) 
     159                return; 
     160 
    150161            var val, ret, fn = jQuery.isFunction( element[ type ] || null ), 
    151162                // Check to see if we need to provide a fake event, or not 
     
    274285            var doc = document.documentElement, body = document.body; 
    275286            event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0); 
    276             event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientLeft || 0); 
     287            event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientLeft || 0); 
    277288        } 
    278289             
     
    438449    // If Safari or IE is used 
    439450    // Continually check to see if the document is ready 
    440     if (jQuery.browser.msie || jQuery.browser.safari ) (function(){ 
     451    if (jQuery.browser.msie || jQuery.browser.safari ) (function(){ 
    441452        try { 
    442453            // If IE is used, use the trick by Diego Perini 
  • trunk/jquery/src/fx.js

    r3989 r4062  
    7070 
    7171        return this[ optall.queue === false ? "each" : "queue" ](function(){ 
     72            if ( this.nodeType != 1) 
     73                return false; 
     74 
    7275            var opt = jQuery.extend({}, optall); 
    7376            var hidden = jQuery(this).is(":hidden"), self = this; 
     
    136139 
    137140        return this.each(function(){ 
     141            if ( this.nodeType != 1) 
     142                return; 
     143 
    138144            if ( fn.constructor == Array ) 
    139145                queue(this, type, fn); 
  • trunk/jquery/src/selector.js

    r4035 r4062  
    9797            return [ t ]; 
    9898 
    99         // Make sure that the context is a DOM Element 
    100         if ( context && !context.nodeType ) 
    101             context = null; 
     99        // check to make sure context is a DOM element or a document 
     100        if ( context && context.nodeType != 1 && context.nodeType != 9) 
     101            return [ ]; 
    102102 
    103103        // Set the correct context (if none is provided) 
  • trunk/jquery/test/index.html

    r4029 r4062  
    172172                </div> 
    173173            </form> 
     174            <div id="nonnodes"><span>hi</span> there <!-- mon ami --></div> 
    174175        </div> 
    175176    </div> 
  • trunk/jquery/test/unit/core.js

    r4041 r4062  
    142142        ok( jQuery.isFunction(fn), "Recursive Function Call" ); 
    143143 
    144         fn({ some: "data" }); 
     144        fn({ some: "data" }); 
    145145    }; 
    146146 
    147147    callme(function(){ 
    148         callme(function(){}); 
     148        callme(function(){}); 
    149149    }); 
    150150}); 
     
    153153 
    154154test("$('html')", function() { 
    155     expect(4); 
     155    expect(5); 
    156156 
    157157    reset(); 
     
    167167     
    168168    reset(); 
     169 
     170    var j = $("<span>hi</span> there <!-- mon ami -->"); 
     171    ok( j.length >= 2, "Check node,textnode,comment creation (some browsers delete comments)" ); 
    169172}); 
    170173 
     
    233236    var pass = true; 
    234237    for ( var i = 0; i < div.size(); i++ ) { 
    235       if ( div.get(i).foo != "zoo" ) pass = false; 
     238        if ( div.get(i).foo != "zoo" ) pass = false; 
    236239    } 
    237240    ok( pass, "Execute a function, Relative" ); 
     
    278281 
    279282if ( !isLocal ) { 
    280     test("attr(String) in XML Files", function() { 
    281         expect(2); 
    282         stop(); 
    283         $.get("data/dashboard.xml", function(xml) { 
    284             ok( $("locations", xml).attr("class") == "foo", "Check class attribute in XML document" ); 
    285             ok( $("location", xml).attr("for") == "bar", "Check for attribute in XML document" ); 
    286             start(); 
    287         }); 
    288     }); 
     283    test("attr(String) in XML Files", function() { 
     284        expect(2); 
     285        stop(); 
     286        $.get("data/dashboard.xml", function(xml) { 
     287            ok( $("locations", xml).attr("class") == "foo", "Check class attribute in XML document" ); 
     288            ok( $("location", xml).attr("for") == "bar", "Check for attribute in XML document" ); 
     289            start(); 
     290        }); 
     291    }); 
    289292} 
    290293 
     
    299302    var pass = true; 
    300303    $("div").attr({foo: 'baz', zoo: 'ping'}).each(function(){ 
    301       if ( this.getAttribute('foo') != "baz" && this.getAttribute('zoo') != "ping" ) pass = false; 
     304        if ( this.getAttribute('foo') != "baz" && this.getAttribute('zoo') != "ping" ) pass = false; 
    302305    }); 
    303306    ok( pass, "Set Multiple Attributes" ); 
     
    305308 
    306309test("attr(String, Object)", function() { 
    307     expect(16); 
     310    expect(17); 
    308311    var div = $("div"); 
    309312    div.attr("foo", "bar"); 
    310313    var pass = true; 
    311314    for ( var i = 0; i < div.size(); i++ ) { 
    312       if ( div.get(i).getAttribute('foo') != "bar" ) pass = false; 
     315        if ( div.get(i).getAttribute('foo') != "bar" ) pass = false; 
    313316    } 
    314317    ok( pass, "Set Attribute" ); 
     
    339342    equals( $("#name").attr('someAttr'), 1, 'Set attribute to the number 1' ); 
    340343 
     344    // using contents will get comments regular, text, and comment nodes 
     345    var j = $("#nonnodes").contents(); 
     346 
     347    j.attr("name", "attrvalue"); 
     348    equals( j.attr("name"), "attrvalue", "Check node,textnode,comment for attr" ); 
     349    j.removeAttr("name") 
     350 
    341351    reset(); 
    342352 
     
    363373 
    364374if ( !isLocal ) { 
    365     test("attr(String, Object) - Loaded via XML document", function() { 
    366         expect(2); 
    367         stop(); 
    368         $.get('data/dashboard.xml', function(xml) {  
    369               var titles = []; 
    370               $('tab', xml).each(function() { 
    371                     titles.push($(this).attr('title')); 
    372               }); 
    373               equals( titles[0], 'Location', 'attr() in XML context: Check first title' ); 
    374               equals( titles[1], 'Users', 'attr() in XML context: Check second title' ); 
    375               start(); 
    376         }); 
    377     }); 
     375    test("attr(String, Object) - Loaded via XML document", function() { 
     376        expect(2); 
     377        stop(); 
     378        $.get('data/dashboard.xml', function(xml) {  
     379            var titles = []; 
     380            $('tab', xml).each(function() { 
     381                titles.push($(this).attr('title')); 
     382            }); 
     383            equals( titles[0], 'Location', 'attr() in XML context: Check first title' ); 
     384            equals( titles[1], 'Users', 'attr() in XML context: Check second title' ); 
     385            start(); 
     386        }); 
     387    }); 
    378388} 
    379389 
     
    409419 
    410420test("css(String, Object)", function() { 
    411     expect(19); 
     421    expect(20); 
    412422    ok( $('#foo').is(':visible'), 'Modifying CSS display: Assert element is visible'); 
    413423    $('#foo').css('display', 'none'); 
     
    438448    } 
    439449    equals( $('#foo').css('opacity'), '1', "Assert opacity is 1 when a different filter is set in IE, #1438" ); 
     450 
     451    // using contents will get comments regular, text, and comment nodes 
     452    var j = $("#nonnodes").contents(); 
     453    j.css("padding-left", "1px"); 
     454    equals( j.css("padding-left"), "1px", "Check node,textnode,comment css works" ); 
    440455}); 
    441456 
     
    468483 
    469484test("wrap(String|Element)", function() { 
    470     expect(6); 
     485    expect(8); 
    471486    var defaultText = 'Try them out:' 
    472487    var result = $('#first').wrap('<div class="red"><span></span></div>').text(); 
     
    487502        ok( checkbox.checked, "Checkbox's state is erased after wrap() action, see #769" ); 
    488503    }).click(); 
     504 
     505    // using contents will get comments regular, text, and comment nodes 
     506    var j = $("#nonnodes").contents(); 
     507    j.wrap("<i></i>"); 
     508    equals( $("#nonnodes > i").length, 3, "Check node,textnode,comment wraps ok" ); 
     509    equals( $("#nonnodes > i").text(), j.text() + j[1].nodeValue, "Check node,textnode,comment wraps doesn't hurt text" ); 
    489510}); 
    490511 
     
    526547 
    527548test("append(String|Element|Array&lt;Element&gt;|jQuery)", function() { 
    528     expect(18); 
     549    expect(21); 
    529550    var defaultText = 'Try them out:' 
    530551    var result = $('#first').append('<b>buga</b>'); 
     
    562583    reset(); 
    563584    $("#sap").append(document.getElementById('form')); 
    564     ok( $("#sap>form").size() == 1, "Check for appending a form" ); // Bug #910 
     585    ok( $("#sap>form").size() == 1, "Check for appending a form" ); // Bug #910 
    565586 
    566587    reset(); 
     
    598619     
    599620    t( "Append Select", "#appendSelect1, #appendSelect2", ["appendSelect1", "appendSelect2"] ); 
     621 
     622    // using contents will get comments regular, text, and comment nodes 
     623    var j = $("#nonnodes").contents(); 
     624    var d = $("<div/>").appendTo("#nonnodes").append(j); 
     625    equals( $("#nonnodes").length, 1, "Check node,textnode,comment append moved leaving just the div" ); 
     626    ok( d.contents().length >= 2, "Check node,textnode,comment append works" ); 
     627    d.contents().appendTo("#nonnodes"); 
     628    d.remove(); 
     629    ok( $("#nonnodes").contents().length >= 2, "Check node,textnode,comment append cleanup worked" ); 
    600630}); 
    601631 
     
    826856 
    827857test("find(String)", function() { 
    828     expect(1); 
     858    expect(2); 
    829859    ok( 'Yahoo' == $('#foo').find('.blogTest').text(), 'Check for find' ); 
     860 
     861    // using contents will get comments regular, text, and comment nodes 
     862    var j = $("#nonnodes").contents(); 
     863    equals( j.find("div").length, 0, "Check node,textnode,comment to find zero divs" ); 
    830864}); 
    831865 
    832866test("clone()", function() { 
    833     expect(3); 
     867    expect(4); 
    834868    ok( 'This is a normal link: Yahoo' == $('#en').text(), 'Assert text for #en' ); 
    835869    var clone = $('#yahoo').clone(); 
    836870    ok( 'Try them out:Yahoo' == $('#first').append(clone).text(), 'Check for clone' ); 
    837871    ok( 'This is a normal link: Yahoo' == $('#en').text(), 'Reassert text for #en' ); 
     872    // using contents will get comments regular, text, and comment nodes 
     873    var cl = $("#nonnodes").contents().clone(); 
     874    ok( cl.length >= 2, "Check node,textnode,comment clone works (some browsers delete comments on clone)" ); 
    838875}); 
    839876 
     
    874911 
    875912    var settings = { xnumber1: 5, xnumber2: 7, xstring1: "peter", xstring2: "pan" }, 
    876         options =     { xnumber2: 1, xstring2: "x", xxx: "newstring" }, 
     913        options = { xnumber2: 1, xstring2: "x", xxx: "newstring" }, 
    877914        optionsCopy = { xnumber2: 1, xstring2: "x", xxx: "newstring" }, 
    878915        merged = { xnumber1: 5, xnumber2: 1, xstring1: "peter", xstring2: "x", xxx: "newstring" }, 
     
    920957    var defaults = { xnumber1: 5, xnumber2: 7, xstring1: "peter", xstring2: "pan" }, 
    921958        defaultsCopy = { xnumber1: 5, xnumber2: 7, xstring1: "peter", xstring2: "pan" }, 
    922         options1 =     { xnumber2: 1, xstring2: "x" }, 
     959        options1 = { xnumber2: 1, xstring2: "x" }, 
    923960        options1Copy = { xnumber2: 1, xstring2: "x" }, 
    924         options2 =     { xstring2: "xx", xxx: "newstringx" }, 
     961        options2 = { xstring2: "xx", xxx: "newstringx" }, 
    925962        options2Copy = { xstring2: "xx", xxx: "newstringx" }, 
    926963        merged2 = { xnumber1: 5, xnumber2: 1, xstring1: "peter", xstring2: "xx", xxx: "newstringx" }; 
     
    942979 
    943980test("val(String)", function() { 
    944     expect(3); 
     981    expect(4); 
    945982    document.getElementById('text1').value = "bla"; 
    946983    ok( $("#text1").val() == "bla", "Check for modified value of input element" ); 
     
    950987    $("#select1").val("3"); 
    951988    ok( $("#select1").val() == "3", "Check for modified (via val(String)) value of select element" ); 
     989 
     990    // using contents will get comments regular, text, and comment nodes 
     991    var j = $("#nonnodes").contents(); 
     992    j.val("asdf"); 
     993    equals( j.val(), "asdf", "Check node,textnode,comment with val()" ); 
     994    j.removeAttr("value"); 
    952995}); 
    953996 
     
    955998 
    956999test("html(String)", function() { 
    957     expect(10); 
     1000    expect(11); 
    9581001    var div = $("#main > div"); 
    9591002    div.html("<b>test</b>"); 
     
    9641007    ok( pass, "Set HTML" ); 
    9651008 
     1009    reset(); 
     1010    // using contents will get comments regular, text, and comment nodes 
     1011    var j = $("#nonnodes").contents(); 
     1012    j.html("<b>bold</b>"); 
     1013    equals( j.html().toLowerCase(), "<b>bold</b>", "Check node,textnode,comment with html()" ); 
     1014 
    9661015    $("#main").html("<select/>"); 
    9671016    $("#main select").html("<option>O1</option><option selected='selected'>O2</option><option>O3</option>"); 
     
    9801029 
    9811030test("filter()", function() { 
    982     expect(4); 
     1031    expect(6); 
    9831032    isSet( $("#form input").filter(":checked").get(), q("radio2", "check1"), "filter(String)" ); 
    9841033    isSet( $("p").filter("#ap, #sndp").get(), q("ap", "sndp"), "filter('String, String')" ); 
    9851034    isSet( $("p").filter("#ap,#sndp").get(), q("ap", "sndp"), "filter('String,String')" ); 
    9861035    isSet( $("p").filter(function() { return !$("a", this).length }).get(), q("sndp", "first"), "filter(Function)" ); 
     1036 
     1037    // using contents will get comments regular, text, and comment nodes 
     1038    var j = $("#nonnodes").contents(); 
     1039    equals( j.filter("span").length, 1, "Check node,textnode,comment to filter the one span" ); 
     1040    equals( j.filter("[name]").length, 0, "Check node,textnode,comment to filter the one span" ); 
    9871041}); 
    9881042 
     
    10561110    var pass = true, div = $("div"); 
    10571111    div.show().each(function(){ 
    1058       if ( this.style.display == "none" ) pass = false; 
     1112        if ( this.style.display == "none" ) pass = false; 
    10591113    }); 
    10601114    ok( pass, "Show" ); 
     
    10621116 
    10631117test("addClass(String)", function() { 
    1064     expect(1); 
     1118    expect(2); 
    10651119    var div = $("div"); 
    10661120    div.addClass("test"); 
     
    10701124    } 
    10711125    ok( pass, "Add Class" ); 
     1126 
     1127    // using contents will get regular, text, and comment nodes 
     1128    var j = $("#nonnodes").contents(); 
     1129    j.addClass("asdf"); 
     1130    ok( j.hasClass("asdf"), "Check node,textnode,comment for addClass" ); 
    10721131}); 
    10731132 
    10741133test("removeClass(String) - simple", function() { 
    1075     expect(3); 
     1134    expect(4); 
    10761135    var div = $("div").addClass("test").removeClass("test"), 
    10771136        pass = true; 
     
    10941153    ok( div.is('.test'), "Empty string passed to removeClass" ); 
    10951154     
     1155    // using contents will get regular, text, and comment nodes 
     1156    var j = $("#nonnodes").contents(); 
     1157    j.removeClass("asdf"); 
     1158    ok( !j.hasClass("asdf"), "Check node,textnode,comment for removeClass" ); 
    10961159}); 
    10971160 
     
    11121175 
    11131176test("text(String)", function() { 
    1114     expect(1); 
     1177    expect(4); 
    11151178    ok( $("#foo").text("<div><b>Hello</b> cruel world!</div>")[0].innerHTML == "&lt;div&gt;&lt;b&gt;Hello&lt;/b&gt; cruel world!&lt;/div&gt;", "Check escaped text" ); 
     1179 
     1180    // using contents will get comments regular, text, and comment nodes 
     1181    var j = $("#nonnodes").contents(); 
     1182    j.text("hi!"); 
     1183    equals( $(j[0]).text(), "hi!", "Check node,textnode,comment with text()" ); 
     1184    equals( j[1].nodeValue, " there ", "Check node,textnode,comment with text()" ); 
     1185    equals( j[2].nodeType, 8, "Check node,textnode,comment with text()" ); 
    11161186}); 
    11171187 
     
    11561226 
    11571227test("remove()", function() { 
    1158     expect(4); 
     1228    expect(6); 
    11591229    $("#ap").children().remove(); 
    11601230    ok( $("#ap").text().length > 10, "Check text is not removed" ); 
     
    11651235    ok( $("#ap").text().length > 10, "Check text is not removed" ); 
    11661236    ok( $("#ap").children().length == 1, "Check filtered remove" ); 
     1237 
     1238    // using contents will get comments regular, text, and comment nodes 
     1239    equals( $("#nonnodes").contents().length, 3, "Check node,textnode,comment remove works" ); 
     1240    $("#nonnodes").contents().remove(); 
     1241    equals( $("#nonnodes").contents().length, 0, "Check node,textnode,comment remove works" ); 
    11671242}); 
    11681243 
    11691244test("empty()", function() { 
    1170     expect(2); 
     1245    expect(3); 
    11711246    ok( $("#ap").children().empty().text().length == 0, "Check text is removed" ); 
    11721247    ok( $("#ap").children().length == 4, "Check elements are not removed" ); 
     1248 
     1249    // using contents will get comments regular, text, and comment nodes 
     1250    var j = $("#nonnodes").contents(); 
     1251    j.empty(); 
     1252    equals( j.html(), "", "Check node,textnode,comment empty works" ); 
    11731253}); 
    11741254 
     
    12041284 
    12051285test("contents()", function() { 
    1206     expect(10); 
     1286    expect(12); 
    12071287    equals( $("#ap").contents().length, 9, "Check element contents" ); 
    12081288    ok( $("#iframe").contents()[0], "Check existance of IFrame document" ); 
     
    12281308    $("table", ibody).remove(); 
    12291309    equals( $("div", ibody).length, 1, "Check for JS error on add and delete of a table in IFrame" ); 
    1230 }); 
     1310 
     1311    // using contents will get comments regular, text, and comment nodes 
     1312    var c = $("#nonnodes").contents().contents(); 
     1313    equals( c.length, 1, "Check node,textnode,comment contents is just one" ); 
     1314    equals( c[0].nodeValue, "hi", "Check node,textnode,comment contents is just the one from span" ); 
     1315}); 
  • trunk/jquery/test/unit/event.js

    r4001 r4062  
    22 
    33test("bind()", function() { 
    4     expect(15); 
     4    expect(16); 
    55 
    66    var handler = function(event) { 
     
    6868    // Trigger the remaining fn (1) 
    6969    $("#firstp").trigger("click"); 
     70 
     71    // using contents will get comments regular, text, and comment nodes 
     72    $("#nonnodes").contents().bind("tester", function () { 
     73        equals(this.nodeType, 1, "Check node,textnode,comment bind just does real nodes" ); 
     74    }).trigger("tester"); 
    7075}); 
    7176 
  • trunk/jquery/test/unit/fx.js

    r3989 r4062  
    22 
    33test("animate(Hash, Object, Function)", function() { 
    4     expect(1); 
     4    expect(3); 
    55    stop(); 
    66    var hash = {opacity: 'show'}; 
     
    88    $('#foo').animate(hash, 0, function() { 
    99        ok( hash.opacity == hashCopy.opacity, 'Check if animate changed the hash parameter' ); 
     10    }); 
     11    // using contents will get comments regular, text, and comment nodes 
     12    $("#nonnodes").contents().animate({paddingLeft:"5px"}, 100, function () { 
     13        equals(this.nodeType, 1, "Check node,textnode,comment animate just does real nodes" ); 
     14        equals($(this).css("paddingLeft"), "5px", "Check node,textnode,comment animate just does real nodes" ); 
    1015        start(); 
    1116    });