/*! * jquery color animations v@version * https://github.com/jquery/jquery-color * * copyright 2012 jquery foundation and other contributors * released under the mit license. * http://jquery.org/license * * date: @date */ (function( jquery, undefined ) { var stephooks = "backgroundcolor borderbottomcolor borderleftcolor borderrightcolor bordertopcolor color columnrulecolor outlinecolor textdecorationcolor textemphasiscolor", // plusequals test for += 100 -= 100 rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, // a set of re's that can match strings and generate color tuples. stringparsers = [{ re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, parse: function( execresult ) { return [ execresult[ 1 ], execresult[ 2 ], execresult[ 3 ], execresult[ 4 ] ]; } }, { re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, parse: function( execresult ) { return [ execresult[ 1 ] * 2.55, execresult[ 2 ] * 2.55, execresult[ 3 ] * 2.55, execresult[ 4 ] ]; } }, { // this regex ignores a-f because it's compared against an already lowercased string re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, parse: function( execresult ) { return [ parseint( execresult[ 1 ], 16 ), parseint( execresult[ 2 ], 16 ), parseint( execresult[ 3 ], 16 ) ]; } }, { // this regex ignores a-f because it's compared against an already lowercased string re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, parse: function( execresult ) { return [ parseint( execresult[ 1 ] + execresult[ 1 ], 16 ), parseint( execresult[ 2 ] + execresult[ 2 ], 16 ), parseint( execresult[ 3 ] + execresult[ 3 ], 16 ) ]; } }, { re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, space: "hsla", parse: function( execresult ) { return [ execresult[ 1 ], execresult[ 2 ] / 100, execresult[ 3 ] / 100, execresult[ 4 ] ]; } }], // jquery.color( ) color = jquery.color = function( color, green, blue, alpha ) { return new jquery.color.fn.parse( color, green, blue, alpha ); }, spaces = { rgba: { props: { red: { idx: 0, type: "byte" }, green: { idx: 1, type: "byte" }, blue: { idx: 2, type: "byte" } } }, hsla: { props: { hue: { idx: 0, type: "degrees" }, saturation: { idx: 1, type: "percent" }, lightness: { idx: 2, type: "percent" } } } }, proptypes = { "byte": { floor: true, max: 255 }, "percent": { max: 1 }, "degrees": { mod: 360, floor: true } }, support = color.support = {}, // element for support tests supportelem = jquery( "

" )[ 0 ], // colors = jquery.color.names colors, // local aliases of functions called often each = jquery.each; // determine rgba support immediately supportelem.style.csstext = "background-color:rgba(1,1,1,.5)"; support.rgba = supportelem.style.backgroundcolor.indexof( "rgba" ) > -1; // define cache name and alpha properties // for rgba and hsla spaces each( spaces, function( spacename, space ) { space.cache = "_" + spacename; space.props.alpha = { idx: 3, type: "percent", def: 1 }; }); function clamp( value, prop, allowempty ) { var type = proptypes[ prop.type ] || {}; if ( value == null ) { return (allowempty || !prop.def) ? null : prop.def; } // ~~ is an short way of doing floor for positive numbers value = type.floor ? ~~value : parsefloat( value ); // ie will pass in empty strings as value for alpha, // which will hit this case if ( isnan( value ) ) { return prop.def; } if ( type.mod ) { // we add mod before modding to make sure that negatives values // get converted properly: -10 -> 350 return (value + type.mod) % type.mod; } // for now all property types without mod have min and max return 0 > value ? 0 : type.max < value ? type.max : value; } function stringparse( string ) { var inst = color(), rgba = inst._rgba = []; string = string.tolowercase(); each( stringparsers, function( i, parser ) { var parsed, match = parser.re.exec( string ), values = match && parser.parse( match ), spacename = parser.space || "rgba"; if ( values ) { parsed = inst[ spacename ]( values ); // if this was an rgba parse the assignment might happen twice // oh well.... inst[ spaces[ spacename ].cache ] = parsed[ spaces[ spacename ].cache ]; rgba = inst._rgba = parsed._rgba; // exit each( stringparsers ) here because we matched return false; } }); // found a stringparser that handled it if ( rgba.length ) { // if this came from a parsed string, force "transparent" when alpha is 0 // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) if ( rgba.join() === "0,0,0,0" ) { jquery.extend( rgba, colors.transparent ); } return inst; } // named colors return colors[ string ]; } color.fn = jquery.extend( color.prototype, { parse: function( red, green, blue, alpha ) { if ( red === undefined ) { this._rgba = [ null, null, null, null ]; return this; } if ( red.jquery || red.nodetype ) { red = jquery( red ).css( green ); green = undefined; } var inst = this, type = jquery.type( red ), rgba = this._rgba = []; // more than 1 argument specified - assume ( red, green, blue, alpha ) if ( green !== undefined ) { red = [ red, green, blue, alpha ]; type = "array"; } if ( type === "string" ) { return this.parse( stringparse( red ) || colors._default ); } if ( type === "array" ) { each( spaces.rgba.props, function( key, prop ) { rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); }); return this; } if ( type === "object" ) { if ( red instanceof color ) { each( spaces, function( spacename, space ) { if ( red[ space.cache ] ) { inst[ space.cache ] = red[ space.cache ].slice(); } }); } else { each( spaces, function( spacename, space ) { var cache = space.cache; each( space.props, function( key, prop ) { // if the cache doesn't exist, and we know how to convert if ( !inst[ cache ] && space.to ) { // if the value was null, we don't need to copy it // if the key was alpha, we don't need to copy it either if ( key === "alpha" || red[ key ] == null ) { return; } inst[ cache ] = space.to( inst._rgba ); } // this is the only case where we allow nulls for all properties. // call clamp with alwaysallowempty inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); }); // everything defined but alpha? if ( inst[ cache ] && jquery.inarray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { // use the default of 1 inst[ cache ][ 3 ] = 1; if ( space.from ) { inst._rgba = space.from( inst[ cache ] ); } } }); } return this; } }, is: function( compare ) { var is = color( compare ), same = true, inst = this; each( spaces, function( _, space ) { var localcache, iscache = is[ space.cache ]; if (iscache) { localcache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; each( space.props, function( _, prop ) { if ( iscache[ prop.idx ] != null ) { same = ( iscache[ prop.idx ] === localcache[ prop.idx ] ); return same; } }); } return same; }); return same; }, _space: function() { var used = [], inst = this; each( spaces, function( spacename, space ) { if ( inst[ space.cache ] ) { used.push( spacename ); } }); return used.pop(); }, transition: function( other, distance ) { var end = color( other ), spacename = end._space(), space = spaces[ spacename ], startcolor = this.alpha() === 0 ? color( "transparent" ) : this, start = startcolor[ space.cache ] || space.to( startcolor._rgba ), result = start.slice(); end = end[ space.cache ]; each( space.props, function( key, prop ) { var index = prop.idx, startvalue = start[ index ], endvalue = end[ index ], type = proptypes[ prop.type ] || {}; // if null, don't override start value if ( endvalue === null ) { return; } // if null - use end if ( startvalue === null ) { result[ index ] = endvalue; } else { if ( type.mod ) { if ( endvalue - startvalue > type.mod / 2 ) { startvalue += type.mod; } else if ( startvalue - endvalue > type.mod / 2 ) { startvalue -= type.mod; } } result[ index ] = clamp( ( endvalue - startvalue ) * distance + startvalue, prop ); } }); return this[ spacename ]( result ); }, blend: function( opaque ) { // if we are already opaque - return ourself if ( this._rgba[ 3 ] === 1 ) { return this; } var rgb = this._rgba.slice(), a = rgb.pop(), blend = color( opaque )._rgba; return color( jquery.map( rgb, function( v, i ) { return ( 1 - a ) * blend[ i ] + a * v; })); }, torgbastring: function() { var prefix = "rgba(", rgba = jquery.map( this._rgba, function( v, i ) { return v == null ? ( i > 2 ? 1 : 0 ) : v; }); if ( rgba[ 3 ] === 1 ) { rgba.pop(); prefix = "rgb("; } return prefix + rgba.join() + ")"; }, tohslastring: function() { var prefix = "hsla(", hsla = jquery.map( this.hsla(), function( v, i ) { if ( v == null ) { v = i > 2 ? 1 : 0; } // catch 1 and 2 if ( i && i < 3 ) { v = math.round( v * 100 ) + "%"; } return v; }); if ( hsla[ 3 ] === 1 ) { hsla.pop(); prefix = "hsl("; } return prefix + hsla.join() + ")"; }, tohexstring: function( includealpha ) { var rgba = this._rgba.slice(), alpha = rgba.pop(); if ( includealpha ) { rgba.push( ~~( alpha * 255 ) ); } return "#" + jquery.map( rgba, function( v ) { // default to 0 when nulls exist v = ( v || 0 ).tostring( 16 ); return v.length === 1 ? "0" + v : v; }).join(""); }, tostring: function() { return this._rgba[ 3 ] === 0 ? "transparent" : this.torgbastring(); } }); color.fn.parse.prototype = color.fn; // hsla conversions adapted from: // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/hue2rgb.as?r=5021 function hue2rgb( p, q, h ) { h = ( h + 1 ) % 1; if ( h * 6 < 1 ) { return p + (q - p) * h * 6; } if ( h * 2 < 1) { return q; } if ( h * 3 < 2 ) { return p + (q - p) * ((2/3) - h) * 6; } return p; } spaces.hsla.to = function ( rgba ) { if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { return [ null, null, null, rgba[ 3 ] ]; } var r = rgba[ 0 ] / 255, g = rgba[ 1 ] / 255, b = rgba[ 2 ] / 255, a = rgba[ 3 ], max = math.max( r, g, b ), min = math.min( r, g, b ), diff = max - min, add = max + min, l = add * 0.5, h, s; if ( min === max ) { h = 0; } else if ( r === max ) { h = ( 60 * ( g - b ) / diff ) + 360; } else if ( g === max ) { h = ( 60 * ( b - r ) / diff ) + 120; } else { h = ( 60 * ( r - g ) / diff ) + 240; } // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) if ( diff === 0 ) { s = 0; } else if ( l <= 0.5 ) { s = diff / add; } else { s = diff / ( 2 - add ); } return [ math.round(h) % 360, s, l, a == null ? 1 : a ]; }; spaces.hsla.from = function ( hsla ) { if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { return [ null, null, null, hsla[ 3 ] ]; } var h = hsla[ 0 ] / 360, s = hsla[ 1 ], l = hsla[ 2 ], a = hsla[ 3 ], q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, p = 2 * l - q; return [ math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), math.round( hue2rgb( p, q, h ) * 255 ), math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), a ]; }; each( spaces, function( spacename, space ) { var props = space.props, cache = space.cache, to = space.to, from = space.from; // makes rgba() and hsla() color.fn[ spacename ] = function( value ) { // generate a cache for this space if it doesn't exist if ( to && !this[ cache ] ) { this[ cache ] = to( this._rgba ); } if ( value === undefined ) { return this[ cache ].slice(); } var ret, type = jquery.type( value ), arr = ( type === "array" || type === "object" ) ? value : arguments, local = this[ cache ].slice(); each( props, function( key, prop ) { var val = arr[ type === "object" ? key : prop.idx ]; if ( val == null ) { val = local[ prop.idx ]; } local[ prop.idx ] = clamp( val, prop ); }); if ( from ) { ret = color( from( local ) ); ret[ cache ] = local; return ret; } else { return color( local ); } }; // makes red() green() blue() alpha() hue() saturation() lightness() each( props, function( key, prop ) { // alpha is included in more than one space if ( color.fn[ key ] ) { return; } color.fn[ key ] = function( value ) { var vtype = jquery.type( value ), fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spacename ), local = this[ fn ](), cur = local[ prop.idx ], match; if ( vtype === "undefined" ) { return cur; } if ( vtype === "function" ) { value = value.call( this, cur ); vtype = jquery.type( value ); } if ( value == null && prop.empty ) { return this; } if ( vtype === "string" ) { match = rplusequals.exec( value ); if ( match ) { value = cur + parsefloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); } } local[ prop.idx ] = value; return this[ fn ]( local ); }; }); }); // add csshook and .fx.step function for each named hook. // accept a space separated string of properties color.hook = function( hook ) { var hooks = hook.split( " " ); each( hooks, function( i, hook ) { jquery.csshooks[ hook ] = { set: function( elem, value ) { var parsed, curelem, backgroundcolor = ""; if ( jquery.type( value ) !== "string" || ( parsed = stringparse( value ) ) ) { value = color( parsed || value ); if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { curelem = hook === "backgroundcolor" ? elem.parentnode : elem; while ( (backgroundcolor === "" || backgroundcolor === "transparent") && curelem && curelem.style ) { try { backgroundcolor = jquery.css( curelem, "backgroundcolor" ); curelem = curelem.parentnode; } catch ( e ) { } } value = value.blend( backgroundcolor && backgroundcolor !== "transparent" ? backgroundcolor : "_default" ); } value = value.torgbastring(); } try { elem.style[ hook ] = value; } catch( e ) { // wrapped to prevent ie from throwing errors on "invalid" values like 'auto' or 'inherit' } } }; jquery.fx.step[ hook ] = function( fx ) { if ( !fx.colorinit ) { fx.start = color( fx.elem, hook ); fx.end = color( fx.end ); fx.colorinit = true; } jquery.csshooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); }; }); }; color.hook( stephooks ); jquery.csshooks.bordercolor = { expand: function( value ) { var expanded = {}; each( [ "top", "right", "bottom", "left" ], function( i, part ) { expanded[ "border" + part + "color" ] = value; }); return expanded; } }; // basic color names only. // usage of any of the other color names requires adding yourself or including // jquery.color.svg-names.js. colors = jquery.color.names = { // 4.1. basic color keywords aqua: "#00ffff", black: "#000000", blue: "#0000ff", fuchsia: "#ff00ff", gray: "#808080", green: "#008000", lime: "#00ff00", maroon: "#800000", navy: "#000080", olive: "#808000", purple: "#800080", red: "#ff0000", silver: "#c0c0c0", teal: "#008080", white: "#ffffff", yellow: "#ffff00", // 4.2.3. "transparent" color keyword transparent: [ null, null, null, 0 ], _default: "#ffffff" }; })( jquery );