4

Changes in jQuery or jQuery-UI are incompatible to plugin jquery.illuminate.0.7

The plugin jquery.illuminate.0.7 works in chrome 30, firefox 22 and IE 10. It uses

  • jquery_1.6.1.min.js
  • jquery-ui_1.8.13.min.js
  • jquery.illuminate.0.7.js

But changing the version of jQuery and jQuery-UI the causes the demo of the illuminate plugin to only work in chrome 30. The demo uses

  • jquery_1.9.1.js and
  • jquery-ui_1.10.3.js
  • jquery.illuminate.0.7.js

In firefox 22 it causes the following error:

TypeError: $.css(...) is undefined pointing to jquery.illuminate.0.7.js:223 

HTML and js code

<script>
window.onload = function(){
    $("#illuminate").illuminate({
        'intensity': '0.3',
        'color': '#98cb00',
        'blink': 'true',
        'blinkSpeed': '1200',
        'outerGlow': 'true',
        'outerGlowSize': '30px',
        'outerGlowColor': '#98cb00'
    });
};
</script>

The relevant html is only the button

<button type="submit" class="btn" id="illuminate" >submit</button>

What have i tried

I looked through the source code of the illuminate plugin to see where the error occurs. The method $.cssHooks.boxShadowBlur contains this js:

$.cssHooks.boxShadowBlur = {
     get: function ( elem, computed, extra ) {
        return $.css(elem, support.boxShadow).split(rWhitespace)[5];
     },
     set: function( elem, value ) {     
              elem.style[ support.boxShadow ] = 
                 insert_into($.css(elem, support.boxShadow), value, 5);                
     }
};

The github page of jquery still contains a matching function (see line 111):

jQuery.fn.extend({
  css: function( name, value ) { ....

My Question

  • Did any breaking change occur in jQuery.js or jQuery-ui that could be responsible for $.css(...) failing
  • what can i do to make the plugin compatible to the latest (or at least 1.9.1) version of jquery and jquery-ui (1.10.3)

Updates and Pointers so far

User Dave asked how i load the javascript libraries. I load them synchronously in the following order:

<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js"></script>
<script src="jquery.illuminate.0.7.js"></script>

User Sumurai pointed out that it could have to do with the deprecated curCSS. I found the following code in jQuery 1.9.1:

jQuery.extend({
// Add in style property hooks for overriding the default
// behavior of getting and setting a style property
cssHooks: {
   opacity: {
         get: function( elem, computed ) {
        if ( computed ) {
        // We should always get a number back from opacity
        var ret = curCSS( elem, "opacity" );
        return ret === "" ? "1" : ret;
        }//if
     }//get
   }//opacity
},//cssHooks
    // more properties for jQuery.extend ....

So jQuery 1.9.1 still uses curCSS for the cssHooks.opacity. The plugin illuminate adds another property to cssHooks: $.cssHooks.boxShadowBlur. But as far as i can tell this method has nothing to do with cssHooks.opacity. Therefore the curCSS should have no effect.

surfmuggle
  • 5,527
  • 7
  • 48
  • 77
  • See [this question/my answer](http://stackoverflow.com/questions/18042259/why-do-i-get-the-this-error-css-is-undefined-when-javascript-run/18042511#18042511). – Sumurai8 Aug 04 '13 at 12:53
  • I looked through the source of the illuminate plugin `jquery.illuminate.0.7.js` and `jquery-ui-1.10.3` and could not find any use of `curCSS`. Only in `jquery_1.9.1.js` were several uses of curCSS. So it is difficult to understand why it would be triggerd. Could you elaborate? – surfmuggle Aug 04 '13 at 13:16
  • How are you loading the scripts? Synchronously? In what order? – Dave Aug 04 '13 at 13:37
  • Hmm, stepping through their code with FireBug breakpoints, it occurs to me that I've never seen `$.css(elem,blah)` syntax before. It should be `$(elem).css(blah)`. Maybe the syntax it's using was deprecated? – Dave Aug 04 '13 at 14:04
  • I think it's probably reporting one of the *other* .css calls. Unless you changed all of them. – Dave Aug 04 '13 at 14:15
  • Actually no, if it says `$(...).css` then it's complaining about that one... hmm – Dave Aug 04 '13 at 14:16
  • Sorry I was wrong about that (deleted comment). I've now tracked it down to a capitalisation issue. When curCSS is called, it should be `calledWithValuesLikeThis` but for boxShadow it is being called `WithACapitalLikeThis`. I'm just trying to find out why. – Dave Aug 04 '13 at 14:45
  • OK, well I've tracked it down to this: `jQuery.cssProps` is an array which should normalise the values, but for some reason it has `BoxShadow:BoxShadow` instead of `BoxShadow:boxShadow`. I have no idea why, because I can't find the point where it is set. I will say that the page you're sharing the code on is actually including 2 versions of jQuery (I'd recommend jsFiddle in future; it's much more robust). But I tested it outside that environment and that's not what's messing it up. – Dave Aug 04 '13 at 15:00

1 Answers1

2

Whew, well that took some debugging.

The problem is that illuminate assumes that jQuery doesn't support the box-shadow property, but the newer jQuery version does. That means that when vendor prefixes aren't available (which they aren't in the latest FireFox), you get either an infinite loop or an undefined property. Fortunately illuminate went with an undefined property BoxShadow instead of the infinite loop which would have come from using boxShadow (as I found out, leading to several browser hangs).

So that's the problem, what's the fix? Strip the offending code from illuminate. All cases of support.boxShadow should be changed to simply 'boxShadow', and the cssHooks.boxShadow block removed. You can also delete the bit which sets support.boxShadow in the first place.

My test case is here: http://jsfiddle.net/JbTcs/2/ and works in FireFox and Chrome, and I'm told IE10. The fixed source code for illuminate is:

/*
 * jQuery Illuminate v0.7 - http://www.tonylea.com/
 *
 * Illuminate elements in jQuery, Function takes the background color of an element
 * and illuminates the element.
 *
 * TERMS OF USE - jQuery Illuminate
 * 
 * Open source under the BSD License. 
 *
 * Currently incompatible with FireFox v.4
 * 
 * Copyright © 2011 Tony Lea
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,     
 * are permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list of 
 * conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright notice, this list 
 * of conditions and the following disclaimer in the documentation and/or other materials 
 * provided with the distribution.
 * 
 * Neither the name of the author nor the names of contributors may be used to endorse 
 * or promote products derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 * OF THE POSSIBILITY OF SUCH DAMAGE. 
 *
 * modified version
 *
 */
(function($){
$.fn.illuminate = function(options) {
    var defaults = {
        intensity: '0.05',
        color: '',
        blink: 'true',
        blinkSpeed: '600',
        outerGlow: 'true',
        outerGlowSize: '30px',
        outerGlowColor: ''
    };
    var options = $.extend(defaults, options);
    var original_color = '';
    var new_color = '';
    var dead = false;
    $.fn.illuminateDie = function() {
        dead = true;
        options.intensity = '0.05';
        options.color = '';
        options.blink = 'true';
        options.blinkSpeed = '600';
        options.outerGlow = 'true';
        options.outerGlowSize = '30px';
        options.outerGlowColor = '';
        $(this).css({'boxShadow': '0px 0px 0px', 'background-color': "#" + original_color});
    }
    function toggleIllumination(obj, original_color, new_color, outerGlow) {
        if(rgb2hex(obj.css('background-color')).toUpperCase() == original_color.toUpperCase()) {    

            obj.animate({"background-color": "#" + new_color, 'boxShadowBlur': outerGlow }, parseInt(options.blinkSpeed), 
                function(){
                    if(!dead)
                        toggleIllumination($(this), original_color, new_color, outerGlow);
                });
        }
        if(rgb2hex(obj.css('background-color')).toUpperCase() == new_color.toUpperCase()) { 
            obj.animate({"background-color": "#" + original_color, 'boxShadowBlur': '0px' }, parseInt(options.blinkSpeed), 
                function(){
                    if(!dead)
                        toggleIllumination($(this), original_color, new_color, outerGlow);
                });
        }
    }
    function colorAdd(hex, percent) {
        percentHex = parseInt(Math.round(parseFloat(percent)*16));
        return hexAdd(hex[0], percentHex) + hexAdd(hex[1], percentHex) + hexAdd(hex[2], percentHex) + hexAdd(hex[3], percentHex) + hexAdd(hex[4], percentHex) + hexAdd(hex[5], percentHex);
    }
    function hexAdd(val, val2) {
        result = parseInt(val, 16) + val2;
        if(result > 15) return 'F';
        return result.toString(16).toUpperCase();
    }
    function rgb2hex(rgb) {
        rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
        function hex(x) {
            return ("0" + parseInt(x).toString(16)).slice(-2);
        }
        return hex(rgb[1]) + hex(rgb[2]) + hex(rgb[3]);
    }
    return this.each(function() {
        obj = $(this);
        if(obj.is("input")){
            if(obj.css('border') == ''){ obj.css('border', 'none') };
        }
        dead = false;
        original_color = rgb2hex(obj.css('background-color'));
        if(options.color == ''){
            new_color = colorAdd(original_color, options.intensity);
        } else {
            new_color = options.color.replace('#', '');
        }
        var BlurColor = '';
        if(options.outerGlowColor == ''){
            BlurColor = new_color;
        } else {
            BlurColor = options.outerGlowColor.replace('#', '');
        }
        obj.css('boxShadow','0px 0px 0px #'+BlurColor);
        var firstColor = '';
        var firstBlur = '';
        if(options.blink == 'true'){
            firstColor = original_color;
            firstBlur = '0px';
        } else {
            firstColor = new_color;
            firstBlur = options.outerGlowSize;
        }
        var outerGlow = '';
        if(options.outerGlow == 'true'){
            outerGlow = options.outerGlowSize;
        } else {
            outerGlow = '0px';
        }
        obj.animate({"background-color": "#" + firstColor, 'boxShadowBlur': firstBlur }, parseInt(options.blinkSpeed), 
            function(){
                if(options.blink == 'true')
                    toggleIllumination($(this), original_color, new_color, outerGlow);
            });
    });
};
var div = document.createElement('div'),
    divStyle = div.style,
    support = $.support,
    rWhitespace = /\s/,
    rParenWhitespace = /\)\s/;
div = null;
function insert_into(string, value, index) {
    var parts  = string.split(rWhitespace);
    parts[index] = value;
    return parts.join(" ");
}
$.cssHooks.boxShadowBlur = {
    get: function ( elem, computed, extra ) {
        return $.css(elem, 'boxShadow').split(rWhitespace)[5];
    },
    set: function( elem, value ) {
        elem.style[ 'boxShadow' ] = insert_into($.css(elem, 'boxShadow'), value, 5);
    }
};
$.fx.step[ "boxShadowBlur" ] = function( fx ) {
    $.cssHooks[ "boxShadowBlur" ].set( fx.elem, fx.now + fx.unit );
};
})(jQuery);
Dave
  • 44,275
  • 12
  • 65
  • 105
  • I added a note. For future reference things like that are fine to leave as comments; editing the post is relevant if you need to fix something to make it work in (say) IE10. Future users can always look at the comments if they want to know more about it. – Dave Aug 05 '13 at 20:16