├── .gitattributes ├── .gitignore ├── tests ├── unit │ ├── boxsizing.js │ ├── columns.js │ ├── boxreflect.js │ ├── borderimage.js │ ├── transform.js │ ├── color.js │ ├── transition.js │ ├── bgpos.js │ ├── gradients.js │ ├── marginpadding.js │ ├── borderradius.js │ ├── userinterface.js │ ├── borderradiusalt.js │ ├── boxshadow.js │ └── textshadow.js ├── qunit │ ├── qunit.css │ └── qunit.js └── index.html ├── boxsizing.js ├── boxreflect.js ├── borderimage.js ├── marginpadding.js ├── LICENSE.txt ├── columns.js ├── transition.js ├── userinterface.js ├── textshadow.js ├── README.md ├── bgpos.js ├── borderradius.js ├── gradients.js ├── boxshadow.js ├── skeleton.js ├── border-radius.htc ├── borderradiusalt.js ├── color.js └── transform.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * crlf=input 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.diff 3 | *.patch 4 | -------------------------------------------------------------------------------- /tests/unit/boxsizing.js: -------------------------------------------------------------------------------- 1 | module("boxSizing"); 2 | 3 | test("boxSizing", 2, function() { 4 | equals( jQuery("#test").css("boxSizing"), "border-box", "returns correct value" ); 5 | equals( jQuery("#test").css("boxSizing","content-box").css("boxSizing"), "content-box", "sets and gets correct value" ); 6 | }); -------------------------------------------------------------------------------- /tests/unit/columns.js: -------------------------------------------------------------------------------- 1 | module("Multiplecolumns"); 2 | 3 | test("columnCount", 2, function() { 4 | equals( jQuery("#test").css("columnCount"), "2", "returns correct value" ); 5 | equals( jQuery("#test").css("columnCount", "4").css("columnCount"), "4", "sets and retrieves new property" ); 6 | }); 7 | -------------------------------------------------------------------------------- /tests/unit/boxreflect.js: -------------------------------------------------------------------------------- 1 | module("boxreflect"); 2 | 3 | test("boxReflect", 2, function() { 4 | equals( jQuery("#test").css("boxReflect"), "below 3px none", "returns correct value" ); 5 | equals( jQuery("#test").css('boxReflect', 'above 3px').css("boxReflect"), "above 3px none", "sets and retrieves new property" ); 6 | }); -------------------------------------------------------------------------------- /tests/unit/borderimage.js: -------------------------------------------------------------------------------- 1 | module("borderImage"); 2 | 3 | test("borderImage", 2, function() { 4 | ok( /^url(.*) 27 27 27 27 round round$/i.test( jQuery("#test").css("borderImage") ) , "returns correct value" ); 5 | ok( /^url(.*) 30 27 30 27 round round$/i.test( jQuery("#test").css("borderImage", "url(border.png) 30 27 30 27 round round").css("borderImage") ) , "sets and returns correct value" ); 6 | }); -------------------------------------------------------------------------------- /tests/unit/transform.js: -------------------------------------------------------------------------------- 1 | module("transform"); 2 | 3 | test("transform", 1, function() { 4 | var $test = jQuery("#test"); 5 | // clear transforms in IE 6 | $test[0].style.filter = ""; 7 | // clear transforms in other browsers 8 | $test[0].setAttribute('style', ''); 9 | $test.css('transform', 'rotate(90deg) scale(2) translateX(100px)'); 10 | ok( ~jQuery("#test").css("transform").indexOf('matrix'), "computed matrix is not 'none'" ); 11 | }); 12 | -------------------------------------------------------------------------------- /boxsizing.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk) 3 | * Box Sizing cssHook for jQuery 4 | * Limitations: 5 | - Works with jQuery 1.4.3 and higher 6 | * Licensed under the MIT License (LICENSE.txt). 7 | */ 8 | (function($) { 9 | 10 | var div = document.createElement("div"), 11 | divStyle = div.style; 12 | 13 | $.support.boxSizing = 14 | divStyle.boxSizing === ''? 'boxSizing' : 15 | (divStyle.MozBoxSizing === ''? 'MozBoxSizing' : 16 | (divStyle.WebkitBoxSizing === ''? 'WebkitBoxSizing' : 17 | (divStyle.MsBoxSizing === ''? 'msBoxSizing' : false))); 18 | 19 | if ( $.support.boxSizing && $.support.boxSizing !== "boxSizing" ){ 20 | 21 | $.cssHooks.boxSizing = { 22 | get: function( elem, computed, extra ) { 23 | return $.css(elem, $.support.boxSizing); 24 | }, 25 | set: function( elem, value ) { 26 | elem.style[ $.support.boxSizing ] = value; 27 | } 28 | }; 29 | } 30 | 31 | div = divStyle = null; 32 | 33 | })(jQuery); -------------------------------------------------------------------------------- /boxreflect.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk) 3 | * Box Reflect cssHook for jQuery 4 | * Limitations: 5 | - Works with jQuery 1.4.3 and higher 6 | - Doesn't currently support gradients 7 | * Licensed under the MIT License (LICENSE.txt). 8 | */ 9 | (function($) { 10 | var div = document.createElement('div'), 11 | divStyle = div.style; 12 | 13 | $.support.boxReflect = 14 | divStyle.boxReflect === '' ? 'boxReflect' : 15 | (divStyle.MozBoxReflect === '' ? 'MozBoxReflect' : 16 | (divStyle.WebkitBoxReflect === '' ? 'WebkitBoxReflect' : 17 | (divStyle.OBoxReflect === '' ? 'OBoxReflect' : false))); 18 | 19 | if ( $.support.boxReflect && $.support.boxReflect !== 'boxReflect' ) { 20 | 21 | $.cssHooks.boxReflect = { 22 | get: function( elem, computed, extra ) { 23 | return $.css( elem, $.support.boxReflect ); 24 | }, 25 | set: function( elem, value ) { 26 | elem.style[$.support.boxReflect] = value; 27 | } 28 | }; 29 | } 30 | div = divStyle = null; 31 | 32 | })(jQuery); -------------------------------------------------------------------------------- /borderimage.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk) 3 | * Border Image cssHook for jQuery 4 | * Limitations: 5 | - Works with jQuery 1.4.3 and higher 6 | - Doesn't work in all CSS3 browers (currently) 7 | * Licensed under the MIT License (LICENSE.txt). 8 | */ 9 | (function($) { 10 | 11 | var div = document.createElement( "div" ), 12 | divStyle = div.style; 13 | 14 | $.support.borderImage = 15 | divStyle.borderImage === '' ? 'borderImage' : 16 | (divStyle.MozBorderImage === '' ? 'MozBorderImage' : 17 | (divStyle.WebkitBorderImage === '' ? 'WebkitBorderImage' : false)); 18 | 19 | if ( $.support.borderImage && $.support.borderImage !== "borderImage" ) { 20 | $.cssHooks.borderImage = { 21 | get: function( elem, computed, extra ) { 22 | return $.css(elem, $.support.borderImage); 23 | }, 24 | set: function( elem, value ) { 25 | elem.style[$.support.borderImage] = value; 26 | } 27 | }; 28 | } 29 | 30 | div = divStyle = null; 31 | 32 | })(jQuery) -------------------------------------------------------------------------------- /marginpadding.js: -------------------------------------------------------------------------------- 1 | /*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net) 2 | * Licensed under the MIT License (LICENSE.txt). 3 | */ 4 | (function($) { 5 | // padding and margin get hooks 6 | var dirs = "Top Right Bottom Left".split(" "); 7 | $.each(["margin", "padding"], function( i, hook ) { 8 | $.cssHooks[ hook ] = { 9 | get: function( elem, computed, extra ) { 10 | return $.map(dirs, function( dir ) { 11 | return $.css( elem, hook + dir ); 12 | }).join(" "); 13 | }, 14 | set: function( elem, value ) { 15 | var parts = value.split(/\s/), 16 | values = { 17 | "Top": parts[0], 18 | "Right": parts[1] || parts[0], 19 | "Bottom": parts[2] || parts[0], 20 | "Left": parts[3] || parts[1] || parts[0] 21 | }; 22 | $.each(dirs, function( i, dir ) { 23 | elem.style[ hook + dir ] = values[ dir ]; 24 | }); 25 | } 26 | }; 27 | }); 28 | })(jQuery); 29 | -------------------------------------------------------------------------------- /tests/unit/color.js: -------------------------------------------------------------------------------- 1 | module("color"); 2 | 3 | test("Basic getting & setting", 10, function() { 4 | equals( jQuery("#test").css("color"), "rgb(0, 0, 0)", "returns just the color" ); 5 | equals( jQuery("#test").css("color", "rgb(100, 150, 200)").css("color"), "rgb(100, 150, 200)", "sets the color properly" ); 6 | equals( jQuery("#test").css("color", "#bada55").css("color"), "rgb(186, 218, 85)", "sets the color properly" ); 7 | equals( jQuery("#test").css("color", "red").css("color"), "rgb(255, 0, 0)", "sets the color properly" ); 8 | equals( jQuery("#test").css("color", "lawngreen").css("color"), "rgb(124, 252, 0)", "sets the color properly" ); 9 | equals( jQuery("#test").css("color", "rgba(0, 0, 0, 0.3)").css("color"), "rgba(0, 0, 0, 0.3)", "sets the color properly" ); 10 | equals( jQuery("#test").css("color", "rgba(0, 255, 0, 0.5)").css("color"), "rgba(0, 255, 0, 0.5)", "sets the color properly" ); 11 | equals( jQuery("#test").css("color", "rgb(33%, 66%, 99%)").css("color"), "rgb(84, 168, 252)", "sets the color properly" ); 12 | equals( jQuery("#test").css("color", "hsl(75%, 50%, 25%)").css("color"), "rgb(63, 31, 95)", "sets the color properly" ); 13 | equals( jQuery("#test").css("color", "hsla(10%, 20%, 30%, 0.4)").css("color"), "rgba(91, 79, 61, 0.4)", "sets the color properly" ); 14 | }); -------------------------------------------------------------------------------- /tests/unit/transition.js: -------------------------------------------------------------------------------- 1 | module("transition"); 2 | 3 | test("transition", 2, function() { 4 | equals( jQuery("#test").css("transition"), "border 1s cubic-bezier(0, 0, 1, 1)", "returns values in the correct order" ); 5 | equals( jQuery("#test").css("transition", "color 2s ease-in").css("transition"), "color 2s cubic-bezier(0.42, 0, 1, 1)", "sets the values properly" ); 6 | }); 7 | 8 | test("transitionProperty", 2, function() { 9 | equals( jQuery("#test").css("transitionProperty"), "border", "returns proper value" ); 10 | equals( jQuery("#test").css("transitionProperty", "color").css("transitionProperty"), "color", "sets the values properly" ); 11 | }); 12 | 13 | test("transitionDuration", 2, function() { 14 | equals( jQuery("#test").css("transitionDuration"), "1s", "returns proper value" ); 15 | equals( jQuery("#test").css("transitionDuration", "2s").css("transitionDuration"), "2s", "sets the values properly" ); 16 | }); 17 | 18 | test("transitionTimingFunction", 2, function() { 19 | equals( jQuery("#test").css("transitionTimingFunction"), "cubic-bezier(0, 0, 1, 1)", "returns proper value" ); 20 | equals( jQuery("#test").css("transitionTimingFunction", "ease-in").css("transitionTimingFunction"), "cubic-bezier(0.42, 0, 1, 1)", "sets the values properly" ); 21 | }); 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright 2011 Brandon Aaron (http://brandonaaron.net), Burin Asavesna (http://helloburin.com), Tom Ellis (http://www.webmuse.co.uk), 2 | Phil Dokas (http://jetless.org) and Louis-Rémi Babé (http://twitter.com/louis_remi). 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/unit/bgpos.js: -------------------------------------------------------------------------------- 1 | module("backgroundPosition"); 2 | 3 | test("backgroundPosition", 2, function() { 4 | equals( jQuery("#test").css("backgroundPosition"), "3px 5px", "returns values in the correct order" ); 5 | equals( jQuery("#test").css("backgroundPosition", "1px 2px").css("backgroundPosition"), "1px 2px", "sets the values properly" ); 6 | }); 7 | 8 | test("backgroundPositionX", 3, function() { 9 | equals( jQuery("#test").css("backgroundPositionX"), "3px", "returns proper value" ); 10 | equals( jQuery("#test").css("backgroundPositionX", "1px").css("backgroundPositionX"), "1px", "sets the value properly" ); 11 | stop(); 12 | jQuery("#test").animate({ backgroundPositionX: 10 }, 100, function() { 13 | equals( jQuery("#test").css("backgroundPositionX"), "10px", "animates the value properly" ); 14 | start(); 15 | }); 16 | }); 17 | 18 | test("backgroundPositionY", 3, function() { 19 | equals( jQuery("#test").css("backgroundPositionY"), "5px", "returns proper value" ); 20 | equals( jQuery("#test").css("backgroundPositionY", "1px").css("backgroundPositionY"), "1px", "sets the value properly" ); 21 | stop(); 22 | jQuery("#test").animate({ backgroundPositionY: 10 }, 100, function() { 23 | equals( jQuery("#test").css("backgroundPositionY"), "10px", "animates the value properly" ); 24 | start(); 25 | }); 26 | }); 27 | 28 | -------------------------------------------------------------------------------- /tests/unit/gradients.js: -------------------------------------------------------------------------------- 1 | module("gradient"); 2 | 3 | test("linearGradient", 3, function() { 4 | ok( /linear-gradient/i.test( jQuery("#test2").css("backgroundImage", "linear-gradient(top, blue, red)").css("backgroundImage") ) , "returns correct value using colour names" ); 5 | ok( /linear-gradient/i.test( jQuery("#test2").css("backgroundImage", "linear-gradient(top, rgb(0,0,225), rgb(255,0,0))").css("backgroundImage") ) , "returns correct value using rgb values" ); 6 | ok( /linear-gradient/i.test( jQuery("#test2").css("backgroundImage", "linear-gradient(top, hsl(240,100%, 50%), hsl(0,100%, 50%))").css("backgroundImage") ) , "returns correct value using hsl values" ); 7 | }); 8 | 9 | test("radialGradient", 3, function() { 10 | jQuery("#test").css("backgroundImage", "radial-gradient(50% 50%, circle, red, blue)"); 11 | ok( /radial-gradient/i.test( jQuery("#test2").css("backgroundImage","radial-gradient(50% 50%, circle, grey, blue)").css("backgroundImage") ) , "returns correct value using colour names" ); 12 | ok( /radial-gradient/i.test( jQuery("#test2").css("backgroundImage", "radial-gradient(50% 50%, circle, top, rgb(0,0,225), rgb(255,0,0))").css("backgroundImage") ) , "returns correct value using rgb colours" ); 13 | ok( /radial-gradient/i.test( jQuery("#test2").css("backgroundImage", "radial-gradient(50% 50%, circle, top, hsl(240,100%, 50%), hsl(0,100%, 50%))").css("backgroundImage") ) , "returns correct value using rgb colours" ); 14 | }); -------------------------------------------------------------------------------- /tests/unit/marginpadding.js: -------------------------------------------------------------------------------- 1 | module("marginpadding"); 2 | 3 | test("margin", 5, function() { 4 | equals( jQuery("#test").css("margin"), "1px 2px 3px 4px", "returns values in the correct order" ); 5 | equals( jQuery("#test").css("margin", "4px 3px 2px 1px").css("margin"), "4px 3px 2px 1px", "sets the top, right, bottom, left values properly" ); 6 | equals( jQuery("#test").css("margin", "5px 6px 7px").css("margin"), "5px 6px 7px 6px", "sets the top, right & left, bottom values properly" ); 7 | equals( jQuery("#test").css("margin", "8px 9px").css("margin"), "8px 9px 8px 9px", "sets the top & bottom, left & right values properly" ); 8 | equals( jQuery("#test").css("margin", "1px").css("margin"), "1px 1px 1px 1px", "sets all the values properly" ); 9 | }); 10 | 11 | test("padding", 5, function() { 12 | equals( jQuery("#test").css("padding"), "1px 2px 3px 4px", "returns values in the correct order" ); 13 | equals( jQuery("#test").css("padding", "4px 3px 2px 1px").css("padding"), "4px 3px 2px 1px", "sets the top, right, bottom, left values properly" ); 14 | equals( jQuery("#test").css("padding", "5px 6px 7px").css("padding"), "5px 6px 7px 6px", "sets the top, right & left, bottom values properly" ); 15 | equals( jQuery("#test").css("padding", "8px 9px").css("padding"), "8px 9px 8px 9px", "sets the top & bottom, left & right values properly" ); 16 | equals( jQuery("#test").css("padding", "1px").css("padding"), "1px 1px 1px 1px", "sets all the values properly" ); 17 | }); 18 | 19 | -------------------------------------------------------------------------------- /columns.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk) 3 | * Columns cssHook for jQuery 4 | * Limitations: 5 | - Works with jQuery 1.4.3 and higher 6 | * Licensed under the MIT License (LICENSE.txt). 7 | */ 8 | (function($) { 9 | 10 | var div = document.createElement("div"), 11 | divStyle = div.style, 12 | rWhitespace = /\s/, 13 | column = "Column", 14 | props = "Span Count Gap Width RuleColor RuleStyle RuleWidth".split(rWhitespace), 15 | prefix = divStyle.WebkitColumnGap === ''? 'Webkit' : (divStyle.MozColumnGap === '' ? 'Moz' : ''), 16 | getCssProperty = function( prefix, prop ) { 17 | return prefix + ( (prefix === '') ? column.toLowerCase() : column ) + prop; 18 | }; 19 | 20 | $.support.columnCount = 21 | divStyle.columnCount === '' ? 'columnCount' : 22 | (divStyle.MozColumnCount === ''? 'MozColumnCount' : 23 | (divStyle.WebkitColumnCount === ''? 'WebkitColumnCount' : false)); 24 | 25 | if ( $.support.columnCount && $.support.columnCount !== "columnCount" ) { 26 | 27 | $.each(props, function( i, prop ) { 28 | 29 | $.cssHooks["column" + prop ] = { 30 | get: function( elem, computed, extra ) { 31 | return $.css(elem, getCssProperty( prefix, prop ) ); 32 | }, 33 | set: function( elem, value ) { 34 | elem.style[ getCssProperty( prefix, prop ) ] = value; 35 | } 36 | }; 37 | 38 | }); 39 | } 40 | 41 | div = divStyle = null; 42 | 43 | })(jQuery); -------------------------------------------------------------------------------- /tests/unit/borderradius.js: -------------------------------------------------------------------------------- 1 | module("borderRadius"); 2 | 3 | test("borderRadius", 3, function() { 4 | equals( jQuery("#test").css("borderRadius"), "5px 5px 5px 5px", "returns values in the correct order" ); 5 | equals( jQuery("#test").css("borderRadius", "3px").css("borderRadius"), "3px 3px 3px 3px", "sets the values properly with 1 value" ); 6 | equals( jQuery("#test").css("borderRadius", "3px 0 0 3px").css("borderRadius"), "3px 0px 0px 3px", "sets the values properly with multiple values" ); 7 | }); 8 | 9 | test("borderRadiusTopLeft", 2, function() { 10 | equals( jQuery("#test").css("borderRadiusTopLeft"), "5px", "returns values in the correct order" ); 11 | equals( jQuery("#test").css("borderRadiusTopLeft", "3px").css("borderRadiusTopLeft"), "3px", "sets the values properly" ); 12 | }); 13 | 14 | test("borderRadiusTopRight", 2, function() { 15 | equals( jQuery("#test").css("borderRadiusTopRight"), "5px", "returns values in the correct order" ); 16 | equals( jQuery("#test").css("borderRadiusTopRight", "3px").css("borderRadiusTopRight"), "3px", "sets the values properly" ); 17 | }); 18 | 19 | test("borderRadiusBottomRight", 2, function() { 20 | equals( jQuery("#test").css("borderRadiusBottomRight"), "5px", "returns values in the correct order" ); 21 | equals( jQuery("#test").css("borderRadiusBottomRight", "3px").css("borderRadiusBottomRight"), "3px", "sets the values properly" ); 22 | }); 23 | 24 | test("borderRadiusBottomLeft", 2, function() { 25 | equals( jQuery("#test").css("borderRadiusBottomLeft"), "5px", "returns values in the correct order" ); 26 | equals( jQuery("#test").css("borderRadiusBottomLeft", "3px").css("borderRadiusBottomLeft"), "3px", "sets the values properly" ); 27 | }); -------------------------------------------------------------------------------- /tests/unit/userinterface.js: -------------------------------------------------------------------------------- 1 | module("User Interface"); 2 | 3 | test("userSelect", 6, function() { 4 | equals( jQuery("#test").css("userSelect"), "none", "returns correct value" ); 5 | equals( jQuery("#test").css("userSelect", "text").css("userSelect"), "text", "sets 1st new value, and reads new value properly" ); 6 | equals( jQuery("#test").css("userSelect", "toggle").css("userSelect"), "toggle", "sets 2nd new value, and reads new value properly" ); 7 | equals( jQuery("#test").css("userSelect", "element").css("userSelect"), "element", "sets 3rd new value, and reads new value properly" ); 8 | equals( jQuery("#test").css("userSelect", "elements").css("userSelect"), "elements", "sets 4th new value, and reads new value properly" ); 9 | equals( jQuery("#test").css("userSelect", "all").css("userSelect"), "all", "sets 5th new value, and reads new value properly" ); 10 | }); 11 | 12 | test("userInput", 2, function() { 13 | equals( jQuery("#test").css("userInput"), "disabled", "returns correct value" ); 14 | equals( jQuery("#test").css("userInput", "enabled").css("userInput"), "enabled", "sets 1st new value, and reads new value properly" ); 15 | }); 16 | 17 | test("userFocus", 2, function() { 18 | equals( jQuery("#test").css("userFocus"), "ignore", "returns correct value" ); 19 | equals( jQuery("#test").css("userFocus", "normal").css("userFocus"), "normal", "sets 1st new value, and reads new value properly" ); 20 | }); 21 | 22 | test("userModify", 2, function() { 23 | equals( jQuery("#test").css("userModify"), "read-only", "returns correct value" ); 24 | equals( jQuery("#test").css("userModify", "read-write").css("userModify"), "read-write", "sets 1st new value, and reads new value properly" ); 25 | }); 26 | -------------------------------------------------------------------------------- /transition.js: -------------------------------------------------------------------------------- 1 | /*! Copyright (c) 2010 Burin Asavesna (http://helloburin.com) 2 | * Licensed under the MIT License (LICENSE.txt). 3 | */ 4 | (function($) { 5 | var div = document.createElement('div'), 6 | divStyle = div.style, 7 | support = $.support, 8 | props = "Property Duration TimingFunction".split(" "); 9 | 10 | support.transition = 11 | divStyle.MozTransition === ''? 'MozTransition' : 12 | (divStyle.MsTransition === ''? 'MsTransition' : 13 | (divStyle.WebkitTransition === ''? 'WebkitTransition' : 14 | (divStyle.OTransition === ''? 'OTransition' : 15 | (divStyle.transition === ''? 'Transition' : 16 | false)))); 17 | 18 | div = null; 19 | 20 | if ( support.transition && support.transition !== "Transition" ) { 21 | $.cssHooks.transition = { 22 | get: function( elem, computed, extra ) { 23 | return $.map(props, function( prop, i ) { 24 | return $.css(elem, support.transition + prop); 25 | }).join(" "); 26 | }, 27 | set: function( elem, value ) { 28 | elem.style[ support.transition ] = value; 29 | } 30 | }; 31 | 32 | $.each(props, function( i, prop ) { 33 | $.cssHooks[ "transition" + prop ] = { 34 | get: function( elem, computed, extra ) { 35 | return $.css(elem, support.transition + prop); 36 | }, 37 | set: function( elem, value ) { 38 | elem.style[ support.transition + prop ] = value; 39 | } 40 | }; 41 | }); 42 | 43 | } 44 | 45 | })(jQuery); 46 | -------------------------------------------------------------------------------- /userinterface.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk) 3 | * User Interface cssHook for jQuery 4 | * Limitations: 5 | - Works with jQuery 1.4.3 and higher 6 | - Works in Firefox 2+, Safari/Chrome (Partial support) only 7 | * Licensed under the MIT License (LICENSE.txt). 8 | */ 9 | (function($) { 10 | 11 | var div = document.createElement( "div" ), 12 | divStyle = div.style, 13 | propertyName = 'user', 14 | suffix = 'User', 15 | props = [ 16 | 'Input', 17 | 'Modify', 18 | 'Select', 19 | 'Focus' 20 | ], 21 | testProperties = [ 22 | propertyName, 23 | 'Moz' + suffix, 24 | 'Webkit' + suffix, 25 | 'O' + suffix, 26 | 'ms' + suffix 27 | ], 28 | supportProperty, 29 | j = props.length; 30 | i = testProperties.length; 31 | 32 | o:for( var a = 0; a < j; a++ ){ 33 | 34 | for( var b = 0; b < i; b++ ){ 35 | if( ( testProperties[b] + props[a] ) in divStyle ){ 36 | $.support[propertyName + props[a]] = ( testProperties[b] + props[a] ); 37 | //If property is found continue to next item in outer loop 38 | continue o; 39 | } 40 | } 41 | } 42 | 43 | $.each( props, function( i, prop ){ 44 | 45 | $.cssProps[propertyName+prop] = $.support[propertyName+prop]; 46 | 47 | if ( $.support[propertyName+prop] && $.support[propertyName+prop] !== propertyName+prop ){ 48 | 49 | $.cssHooks[propertyName+prop] = { 50 | 51 | get: function( elem, computed ) { 52 | return ( computed ? $.css( elem, $.support[propertyName+prop] ) : elem.style[$.support[propertyName+prop]] ); 53 | }, 54 | set: function( elem, value ) { 55 | elem.style[$.support[propertyName+prop]] = value; 56 | } 57 | }; 58 | } 59 | 60 | }); 61 | 62 | div = divStyle = null; 63 | 64 | })(jQuery); -------------------------------------------------------------------------------- /tests/unit/borderradiusalt.js: -------------------------------------------------------------------------------- 1 | module("borderRadiusAlt"); 2 | 3 | /* 4 | See why this doesn't work?? (Because of shorthand?) 5 | test("borderRadius", 3, function() { 6 | equals( jQuery("#test").css("borderRadius"), "5px 5px 5px 5px", "returns values in the correct order" ); 7 | equals( jQuery("#test").css("borderRadius", "3px").css("borderRadius"), "3px 3px 3px 3px", "sets the values properly with 1 value" ); 8 | equals( jQuery("#test").css("borderRadius", "3px 0 0 3px").css("borderRadius"), "3px 0px 0px 3px", "sets the values properly with multiple values" ); 9 | }); 10 | */ 11 | 12 | test("borderTopLeftRadius", 2, function() { 13 | equals( jQuery("#test").css("borderTopLeftRadius"), "5px", "returns values in the correct order" ); 14 | equals( jQuery("#test").css("borderTopLeftRadius", "3px").css("borderTopLeftRadius"), "3px", "sets the values properly" ); 15 | }); 16 | 17 | test("borderTopRightRadius", 2, function() { 18 | equals( jQuery("#test").css("borderTopRightRadius"), "5px", "returns values in the correct order" ); 19 | equals( jQuery("#test").css("borderTopRightRadius", "3px").css("borderTopRightRadius"), "3px", "sets the values properly" ); 20 | }); 21 | 22 | test("borderBottomRightRadius", 2, function() { 23 | equals( jQuery("#test").css("borderBottomRightRadius"), "5px", "returns values in the correct order" ); 24 | equals( jQuery("#test").css("borderBottomRightRadius", "3px").css("borderBottomRightRadius"), "3px", "sets the values properly" ); 25 | }); 26 | 27 | test("borderBottomLeftRadius", 2, function() { 28 | equals( jQuery("#test").css("borderBottomLeftRadius"), "5px", "returns values in the correct order" ); 29 | equals( jQuery("#test").css("borderBottomLeftRadius", "3px").css("borderBottomLeftRadius"), "3px", "sets the values properly" ); 30 | }); -------------------------------------------------------------------------------- /textshadow.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var propStr = 'textShadow', 3 | colorStr = 'Color', 4 | props = (colorStr + " X Y Blur").split(' '), 5 | support = $.support, 6 | rWhitespace = /\s/, 7 | div = document.createElement('div'), 8 | divStyle = div.style; 9 | 10 | support.textShadow = (divStyle.textShadow === ''); 11 | div = divStyle = null; 12 | 13 | if ($.cssHooks && support.textShadow) { 14 | $.each(props, function(i, suffix) { 15 | var hook = propStr + suffix; 16 | 17 | $.cssHooks[hook] = { 18 | get: function(elem, computed, extra) { 19 | return (function(elem, pos, prop) { 20 | var shadow = $.css(elem, propStr), 21 | color = $.color.normalize(shadow), 22 | ret; 23 | 24 | if (prop === colorStr) { 25 | ret = 'rgb' 26 | + (color.alpha ? 'a' : '') + '(' 27 | + color.r + ', ' 28 | + color.g + ', ' 29 | + color.b 30 | + (color.alpha ? ', ' + color.alpha : '') 31 | + ')'; 32 | } 33 | else { 34 | ret = $.trim(shadow.replace(color.source, '')).split(rWhitespace)[pos - 1]; 35 | } 36 | 37 | return ret; 38 | })(elem, i, suffix); 39 | }, 40 | set: function(elem, value) { 41 | elem.style.textShadow = (function(string, value, index) { 42 | var color_part = $.style(elem, propStr + colorStr), 43 | parts = string.replace(color_part, '').split(rWhitespace), 44 | ret; 45 | 46 | if (index === 0) { 47 | color_part = value; 48 | } else { 49 | parts[index] = value; 50 | } 51 | 52 | return color_part + parts.join(' '); 53 | })($.css(elem, propStr), value, i); 54 | } 55 | }; 56 | 57 | if (suffix !== colorStr) { 58 | $.fx.step[hook] = function(fx) { 59 | $.cssHooks[hook].set(fx.elem, fx.now + fx.unit); 60 | }; 61 | } 62 | }); 63 | } 64 | })(jQuery); 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cssHooks 2 | 3 | A collection of cssHooks that work with jQuery 1.4.3+. 4 | 5 | Current Hooks: 6 | 7 | * margin and padding 8 | * backgroundPosition, backgroundPositionX, backgroundPositionY 9 | * borderRadius, borderRadiusTopLeft, borderRadiusTopRight, borderRadiusBottomRight, borderRadiusBottomLeft 10 | * boxShadow, boxShadowColor, boxShadowBlur, boxShadowSpread, boxShadowX, boxShadowY 11 | * borderImage 12 | * Alternative Border Radius Plugin with support for IE 6, 7, and 8 13 | * boxReflect 14 | * boxSizing 15 | * textShadow, and textShadowColor, textShadowX, textShadowY, and textShadowBlur 16 | * color animations for backgroundColor, borderBottomColor, borderLeftColor, borderRightColor, borderTopColor, borderColor, boxShadowColor, color, outlineColor, and textShadowColor 17 | * columnCount, columnSpan, columnGap, columnWidth, columnRuleColor, columnRuleStyle, columnRuleWidth 18 | * 2D transforms 19 | * linear and radial gradients 20 | 21 | # Usage 22 | 23 | Super simple. Just request the margin, padding, backgroundPosition, boxShadow, etc like you would other CSS properties. 24 | 25 | // #myElement { margin: 1px 2px 3px 4px; } 26 | $('#myElement').css('margin'); // "1px 2px 3px 4px" 27 | 28 | What about setting properties? 29 | 30 | // #myElement { box-shadow: #000 1px 1px 3px; } 31 | $('#myElement').css('boxShadow', '#ccc 5px 5px'); 32 | $('#myElement').css('boxShadowColor', '#ff5e99'); 33 | $('#myElement').css('boxShadowBlur', '0px'); 34 | $('#myElement').css('borderImage', 'url(image.jpg) 27 27 27 27 round round'); 35 | 36 | And even animating?! 37 | 38 | $('#myElement').animate({ backgroundPositionY: 100 }, 500); 39 | 40 | # What are cssHooks? 41 | 42 | jQuery 1.4.3 introduced the concept of cssHooks. They allow you to hook directly into jQuery and override how certain css properties are retrieved or set. This allows for browser normalization or even the creation of your own unique css properties. 43 | 44 | ## License 45 | 46 | The cssHooks plugin is licensed under the MIT License (LICENSE.txt). 47 | 48 | Copyright (c) 2013 [Brandon Aaron](http://brandonaaron.net), [Burin Asavesna](http://helloburin.com), [Tom Ellis](http://www.webmuse.co.uk), [Phil Dokas](http://jetless.org) and [Louis-Rémi Babé](http://twitter.com/louis_remi). 49 | -------------------------------------------------------------------------------- /bgpos.js: -------------------------------------------------------------------------------- 1 | /*! Copyright (c) 2010 Brandon Aaron (http://brandonaaron.net) 2 | * Licensed under the MIT License (LICENSE.txt). 3 | */ 4 | (function($) { 5 | // backgroundPosition[X,Y] get hooks 6 | var $div = $('
'); 7 | $.support.backgroundPosition = $div.css('backgroundPosition') === "3px 5px" ? true : false; 8 | $.support.backgroundPositionXY = $div.css('backgroundPositionX') === "3px" ? true : false; 9 | $div = null; 10 | 11 | var xy = ["X","Y"]; 12 | 13 | // helper function to parse out the X and Y values from backgroundPosition 14 | function parseBgPos(bgPos) { 15 | var parts = bgPos.split(/\s/), 16 | values = { 17 | "X": parts[0], 18 | "Y": parts[1] 19 | }; 20 | return values; 21 | } 22 | 23 | if (!$.support.backgroundPosition && $.support.backgroundPositionXY) { 24 | $.cssHooks.backgroundPosition = { 25 | get: function( elem, computed, extra ) { 26 | return $.map(xy, function( l, i ) { 27 | return $.css(elem, "backgroundPosition" + l); 28 | }).join(" "); 29 | }, 30 | set: function( elem, value ) { 31 | $.each(xy, function( i, l ) { 32 | var values = parseBgPos(value); 33 | elem.style[ "backgroundPosition" + l ] = values[ l ]; 34 | }); 35 | } 36 | }; 37 | } 38 | 39 | if ($.support.backgroundPosition && !$.support.backgroundPositionXY) { 40 | $.each(xy, function( i, l ) { 41 | $.cssHooks[ "backgroundPosition" + l ] = { 42 | get: function( elem, computed, extra ) { 43 | var values = parseBgPos( $.css(elem, "backgroundPosition") ); 44 | return values[ l ]; 45 | }, 46 | set: function( elem, value ) { 47 | var values = parseBgPos( $.css(elem, "backgroundPosition") ), 48 | isX = l === "X"; 49 | elem.style.backgroundPosition = (isX ? value : values[ "X" ]) + " " + 50 | (isX ? values[ "Y" ] : value); 51 | } 52 | }; 53 | $.fx.step[ "backgroundPosition" + l ] = function( fx ) { 54 | $.cssHooks[ "backgroundPosition" + l ].set( fx.elem, fx.now + fx.unit ); 55 | }; 56 | }); 57 | } 58 | })(jQuery); 59 | -------------------------------------------------------------------------------- /tests/unit/boxshadow.js: -------------------------------------------------------------------------------- 1 | module("boxShadow"); 2 | 3 | test("boxShadow", 2, function() { 4 | equals( jQuery("#test").css("boxShadow"), "rgb(0, 0, 0) 1px 2px 10px 0px", "returns values: color, x offset, y offset, blur, ???" ); 5 | equals( jQuery("#test").css("boxShadow", "#ccc 5px 5px 5px").css("boxShadow"), "rgb(204, 204, 204) 5px 5px 5px 0px", "sets the value properly" ); 6 | }); 7 | 8 | test("boxShadowColor", 2, function() { 9 | equals( jQuery("#test").css("boxShadowColor"), "rgb(0, 0, 0)", "returns just the color" ); 10 | equals( jQuery("#test").css("boxShadowColor", "#ccc").css("boxShadow"), "rgb(204, 204, 204) 1px 2px 10px 0px", "sets the color properly" ); 11 | }); 12 | 13 | test("boxShadowBlur", 3, function() { 14 | equals( jQuery("#test").css("boxShadowBlur"), "10px", "returns just the blur" ); 15 | equals( jQuery("#test").css("boxShadowBlur", "42px").css("boxShadow"), "rgb(0, 0, 0) 1px 2px 42px 0px", "sets the blur properly" ); 16 | stop(); 17 | jQuery("#test").animate({ boxShadowBlur: 20 }, 100, function() { 18 | equals( jQuery("#test").css("boxShadowBlur"), "20px", "animates the value properly" ); 19 | start(); 20 | }); 21 | }); 22 | 23 | test("boxShadowSpread", 3, function() { 24 | equals( jQuery("#test").css("boxShadowSpread"), "0px", "returns just the spread" ); 25 | equals( jQuery("#test").css("boxShadowSpread", "42px").css("boxShadow"), "rgb(0, 0, 0) 1px 2px 10px 42px", "sets the spread properly" ); 26 | stop(); 27 | jQuery("#test").animate({ boxShadowSpread: 20 }, 100, function() { 28 | equals( jQuery("#test").css("boxShadowSpread"), "20px", "animates the value properly" ); 29 | start(); 30 | }); 31 | }); 32 | 33 | test("boxShadowX", 3, function() { 34 | equals( jQuery("#test").css("boxShadowX"), "1px", "returns just the x offset" ); 35 | equals( jQuery("#test").css("boxShadowX", "42px").css("boxShadow"), "rgb(0, 0, 0) 42px 2px 10px 0px", "sets the x offset properly" ); 36 | stop(); 37 | jQuery("#test").animate({ boxShadowX: 20 }, 100, function() { 38 | equals( jQuery("#test").css("boxShadowX"), "20px", "animates the value properly" ); 39 | start(); 40 | }); 41 | }); 42 | 43 | test("boxShadowY", 3, function() { 44 | equals( jQuery("#test").css("boxShadowY"), "2px", "returns just y offset" ); 45 | equals( jQuery("#test").css("boxShadowY", "42px").css("boxShadow"), "rgb(0, 0, 0) 1px 42px 10px 0px", "sets the x offset properly" ); 46 | stop(); 47 | jQuery("#test").animate({ boxShadowY: 20 }, 100, function() { 48 | equals( jQuery("#test").css("boxShadowY"), "20px", "animates the value properly" ); 49 | start(); 50 | }); 51 | }); 52 | -------------------------------------------------------------------------------- /tests/unit/textshadow.js: -------------------------------------------------------------------------------- 1 | module("textShadow"); 2 | 3 | test("textShadowColor", 3, function() { 4 | equals( jQuery("#test").css("textShadowColor"), "rgb(0, 0, 0)", "returns just the color" ); 5 | equals( jQuery("#test").css("textShadowColor", "rgb(100, 150, 200)").css("textShadowColor"), "rgb(100, 150, 200)", "sets the color properly" ); 6 | stop(); 7 | jQuery("#test").animate({ textShadowColor: 'rgb(255, 255, 255)' }, 100, function() { 8 | equals( jQuery("#test").css("textShadowColor"), "rgb(255, 255, 255)", "animates the color properly" ); 9 | start(); 10 | }); 11 | }); 12 | 13 | test("textShadowX", 3, function() { 14 | equals( jQuery("#test").css("textShadowX"), "1px", "returns just the X offset" ); 15 | equals( jQuery("#test").css("textShadowX", "23px").css("textShadowX"), "23px", "sets the X offset properly" ); 16 | stop(); 17 | jQuery("#test").animate({ textShadowX: 88 }, 100, function() { 18 | equals( jQuery("#test").css("textShadowX"), "88px", "animates the X offset properly" ); 19 | start(); 20 | }); 21 | }); 22 | 23 | test("textShadowY", 3, function() { 24 | equals( jQuery("#test").css("textShadowY"), "1px", "returns just the Y offset" ); 25 | equals( jQuery("#test").css("textShadowY", "23px").css("textShadowY"), "23px", "sets the Y offset properly" ); 26 | stop(); 27 | jQuery("#test").animate({ textShadowY: 88 }, 100, function() { 28 | equals( jQuery("#test").css("textShadowY"), "88px", "animates the Y offset properly" ); 29 | start(); 30 | }); 31 | }); 32 | 33 | test("textShadowBlur", 3, function() { 34 | equals( jQuery("#test").css("textShadowBlur"), "1px", "returns just the blur" ); 35 | equals( jQuery("#test").css("textShadowBlur", "23px").css("textShadowBlur"), "23px", "sets the blur properly" ); 36 | stop(); 37 | jQuery("#test").animate({ textShadowBlur: 88 }, 100, function() { 38 | equals( jQuery("#test").css("textShadowBlur"), "88px", "animates the blur properly" ); 39 | start(); 40 | }); 41 | }); 42 | 43 | test("Alt syntax", 8, function() { 44 | equals( jQuery("#test").css("text-shadow-color"), "rgb(0, 0, 0)", "returns just the color" ); 45 | equals( jQuery("#test").css("text-shadow-color", "rgb(100, 150, 200)").css("text-shadow-color"), "rgb(100, 150, 200)", "sets the color properly" ); 46 | equals( jQuery("#test").css("text-shadow-x"), "1px", "returns just the X offset" ); 47 | equals( jQuery("#test").css("text-shadow-x", "23px").css("text-shadow-x"), "23px", "sets the X offset properly" ); 48 | equals( jQuery("#test").css("text-shadow-y"), "1px", "returns just the Y offset" ); 49 | equals( jQuery("#test").css("text-shadow-y", "23px").css("text-shadow-y"), "23px", "sets the Y offset properly" ); 50 | equals( jQuery("#test").css("text-shadow-blur"), "1px", "returns just the blur" ); 51 | equals( jQuery("#test").css("text-shadow-blur", "23px").css("text-shadow-blur"), "23px", "sets the blur properly" ); 52 | }); 53 | -------------------------------------------------------------------------------- /borderradius.js: -------------------------------------------------------------------------------- 1 | /*! Copyright (c) 2010 Burin Asavesna (http://helloburin.com) 2 | * Licensed under the MIT License (LICENSE.txt). 3 | */ 4 | (function($) { 5 | // borderRadius get hooks 6 | var div = document.createElement('div'), 7 | divStyle = div.style, 8 | support = $.support, 9 | dirs = "TopLeft TopRight BottomRight BottomLeft".split(" "); 10 | 11 | // WebKit supports "borderRadius" as well as "WebKitBorderRadius", weird 12 | support.borderRadius = 13 | divStyle.MozBorderRadius === ''? 'MozBorderRadius' : 14 | (divStyle.MsBorderRadius === ''? 'MsBorderRadius' : 15 | (divStyle.WebkitBorderRadius === ''? 'WebkitBorderRadius' : 16 | (divStyle.OBorderRadius === ''? 'OBorderRadius' : 17 | (divStyle.borderRadius === ''? 'BorderRadius' : 18 | false)))); 19 | 20 | div = null; 21 | 22 | function borderCornerRadius(direction, prefix) { 23 | prefix = prefix === undefined || prefix === '' ? 'border' : prefix + 'Border'; 24 | if ( support.borderRadius && support.borderRadius == "MozBorderRadius" ) { 25 | // e.g. MozBorderRadiusTopleft 26 | return prefix + "Radius" + direction.charAt(0).toUpperCase()+direction.substr(1).toLowerCase(); 27 | } else { 28 | // e.g. WebKitBorderTopLeftRadius, borderTopLeftRadius, etc 29 | return prefix + direction + "Radius"; 30 | } 31 | } 32 | 33 | if ( support.borderRadius && support.borderRadius !== "BorderRadius" ) { 34 | var vendor_prefix = support.borderRadius.replace('BorderRadius',''); 35 | $.cssHooks.borderRadius = { 36 | get: function( elem, computed, extra ) { 37 | // return each of the directions, topleft, topright, bottomright, bottomleft 38 | return $.map(dirs, function( dir ) { 39 | return $.css(elem, borderCornerRadius( dir, vendor_prefix )); 40 | }).join(" "); 41 | }, 42 | set: function( elem, value ) { 43 | // takes in a single value or shorthand (just letting the browser handle this) 44 | // e.g. 5px to set all, or 5px 0 0 5px to set left corners 45 | elem.style[ borderCornerRadius( '', vendor_prefix ) ] = value; 46 | } 47 | }; 48 | 49 | $.each(dirs, function( i, dir ) { 50 | $.cssHooks[ "borderRadius" + dir ] = { 51 | get: function( elem, computed, extra ) { 52 | return $.css(elem, borderCornerRadius( dir, vendor_prefix )); 53 | }, 54 | set: function( elem, value ) { 55 | elem.style[ borderCornerRadius( dir, vendor_prefix ) ] = value; 56 | } 57 | }; 58 | }); 59 | 60 | } 61 | 62 | })(jQuery); 63 | -------------------------------------------------------------------------------- /gradients.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk) 3 | * Linear and Radial Gradient cssHook for jQuery 4 | * Limitations: 5 | - Works with jQuery 1.4.3 and higher 6 | - Works in Firefox 3.6+, Safari 5.1+, Chrome 13+, Opera 11.10+, IE9+ 7 | - Radial Gradients DO NOT work in Opera yet (Doesn't make sense I Know!) 8 | - Only works for background and background image CSS properties 9 | * Licensed under the MIT License (LICENSE.txt). 10 | */ 11 | (function($) { 12 | 13 | var div = document.createElement( "div" ), 14 | divStyle = div.style, 15 | rLinear = /^(.*?)linear-gradient(.*?)$/i, 16 | rRadial = /^(.*?)radial-gradient(.*?)$/i, 17 | rLinearSettings = /^(.*?)(:?linear-gradient)(\()(.*)(\))(.*?)$/i, 18 | rRadialSettings = /^(.*?)(:?radial-gradient)(\()(.*?)(\))(.*?)$/i, 19 | rSupportLinearW3C = /(^|\s)linear-gradient/, 20 | rSupportLinearMoz = /(^|\s)-moz-linear-gradient/, 21 | rSupportLinearWebkit = /(^|\s)-webkit-linear-gradient/, 22 | rSupportLinearOpera = /(^|\s)-o-linear-gradient/, 23 | rSupportRadialW3C = /(^|\s)radial-gradient/, 24 | rSupportRadialMoz = /(^|\s)-moz-radial-gradient/, 25 | rSupportRadialWebkit = /(^|\s)-webkit-radial-gradient/, 26 | rSupportRadialOpera = /(^|\s)-o-radial-gradient/, 27 | rWhitespace = /\s/, 28 | rWhiteGlobal = /\s/g, 29 | cssProps = "background backgroundImage", //listStyleImage not supported yet 30 | cssLinear = "background-image: -moz-linear-gradient(red, blue);background-image: -webkit-linear-gradient(red, blue);background-image: -o-linear-gradient(red, blue);background-image: linear-gradient(red, blue);", 31 | cssRadial = "background-image: -moz-radial-gradient(circle, orange, red);background-image: -webkit-radial-gradient(circle, orange, red);background-image: -o-radial-gradient(circle,red, blue);background-image: radial-gradient(circle, orange, red);", 32 | cssPropsArray = cssProps.split( rWhitespace ); 33 | divStyle.cssText = cssLinear, 34 | linearSettings = function ( value ) { 35 | var parts = rLinearSettings.exec( value ); 36 | value = value.replace( new RegExp(parts[2], 'g') , $.support.linearGradient ); 37 | return value; 38 | }, 39 | radialSettings = function ( value ) { 40 | var parts = rRadialSettings.exec( value ); 41 | value = value.replace( new RegExp(parts[2], 'g') , $.support.radialGradient ); 42 | return value; 43 | }; 44 | 45 | $.support.linearGradient = 46 | rSupportLinearW3C.test( divStyle.backgroundImage ) ? "linear-gradient" : 47 | (rSupportLinearMoz.test( divStyle.backgroundImage ) ? "-moz-linear-gradient" : 48 | (rSupportLinearWebkit.test( divStyle.backgroundImage ) ? "-webkit-linear-gradient" : 49 | (rSupportLinearOpera.test( divStyle.backgroundImage ) ? "-o-linear-gradient" : 50 | false))); 51 | 52 | divStyle.cssText = cssRadial; 53 | 54 | $.support.radialGradient = 55 | rSupportRadialW3C.test( divStyle.backgroundImage ) ? "radial-gradient" : 56 | (rSupportRadialMoz.test( divStyle.backgroundImage ) ? "-moz-radial-gradient" : 57 | (rSupportRadialWebkit.test( divStyle.backgroundImage ) ? "-webkit-radial-gradient" : 58 | (rSupportRadialOpera.test( divStyle.backgroundImage ) ? "-o-radial-gradient" : 59 | false))); 60 | 61 | if ( $.support.linearGradient && $.support.linearGradient !== "linear-gradient" ) { 62 | 63 | $.each( cssPropsArray, function( i, prop ) { 64 | 65 | $.cssHooks[ prop ] = { 66 | 67 | set: function( elem, value ) { 68 | 69 | if( rLinear.test( value ) ){ 70 | elem.style[ prop ] = linearSettings( value ); 71 | } else if ( rRadial.test( value ) ) { 72 | elem.style[ prop ] = radialSettings( value ); 73 | } else { 74 | elem.style[ prop ] = value; 75 | } 76 | } 77 | }; 78 | 79 | }); 80 | 81 | } 82 | 83 | div = divStyle = null; 84 | })(jQuery); 85 | -------------------------------------------------------------------------------- /boxshadow.js: -------------------------------------------------------------------------------- 1 | /*! Copyright (c) 2010 Burin Asavesna (http://helloburin.com) 2 | * Licensed under the MIT License (LICENSE.txt). 3 | */ 4 | (function($) { 5 | // boxShadow get hooks 6 | var div = document.createElement('div'), 7 | divStyle = div.style, 8 | support = $.support, 9 | rWhitespace = /\s/, 10 | rParenWhitespace = /\)\s/; 11 | 12 | support.boxShadow = 13 | divStyle.MozBoxShadow === ''? 'MozBoxShadow' : 14 | (divStyle.MsBoxShadow === ''? 'MsBoxShadow' : 15 | (divStyle.WebkitBoxShadow === ''? 'WebkitBoxShadow' : 16 | (divStyle.OBoxShadow === ''? 'OBoxShadow' : 17 | (divStyle.boxShadow === ''? 'BoxShadow' : 18 | false)))); 19 | 20 | div = null; 21 | 22 | // helper function to inject a value into an existing string 23 | // is there a better way to do this? it seems like a common pattern 24 | function insert_into(string, value, index) { 25 | var parts = string.split(rWhitespace); 26 | parts[index] = value; 27 | return parts.join(" "); 28 | } 29 | 30 | if ( support.boxShadow && support.boxShadow !== "BoxShadow" ) { 31 | $.cssHooks.boxShadow = { 32 | get: function( elem, computed, extra ) { 33 | return $.css(elem, support.boxShadow); 34 | }, 35 | set: function( elem, value ) { 36 | elem.style[ support.boxShadow ] = value; 37 | } 38 | }; 39 | 40 | $.cssHooks.boxShadowColor = { 41 | get: function ( elem, computed, extra ) { 42 | return $.css(elem, support.boxShadow).split(rParenWhitespace)[0] + ')'; 43 | }, 44 | set: function( elem, value ) { 45 | elem.style[ support.boxShadow ] = value + " " + $.css(elem, support.boxShadow).split(rParenWhitespace)[1]; 46 | } 47 | }; 48 | 49 | $.cssHooks.boxShadowBlur = { 50 | get: function ( elem, computed, extra ) { 51 | return $.css(elem, support.boxShadow).split(rWhitespace)[5]; 52 | }, 53 | set: function( elem, value ) { 54 | elem.style[ support.boxShadow ] = insert_into($.css(elem, support.boxShadow), value, 5); 55 | } 56 | }; 57 | 58 | $.cssHooks.boxShadowSpread = { 59 | get: function ( elem, computed, extra ) { 60 | return $.css(elem, support.boxShadow).split(rWhitespace)[6]; 61 | }, 62 | set: function( elem, value ) { 63 | elem.style[ support.boxShadow ] = insert_into($.css(elem, support.boxShadow), value, 6); 64 | } 65 | }; 66 | 67 | $.cssHooks.boxShadowX = { 68 | get: function ( elem, computed, extra ) { 69 | return $.css(elem, support.boxShadow).split(rWhitespace)[3]; 70 | }, 71 | set: function( elem, value ) { 72 | elem.style[ support.boxShadow ] = insert_into($.css(elem, support.boxShadow), value, 3); 73 | } 74 | }; 75 | 76 | $.cssHooks.boxShadowY = { 77 | get: function ( elem, computed, extra ) { 78 | return $.css(elem, support.boxShadow).split(rWhitespace)[4]; 79 | }, 80 | set: function( elem, value ) { 81 | elem.style[ support.boxShadow ] = insert_into($.css(elem, support.boxShadow), value, 4); 82 | } 83 | }; 84 | 85 | // setup fx hooks 86 | var fxHooks = "Blur Spread X Y".split(" "); 87 | $.each(fxHooks, function( i, suffix ) { 88 | var hook = "boxShadow" + suffix; 89 | $.fx.step[ hook ] = function( fx ) { 90 | $.cssHooks[ hook ].set( fx.elem, fx.now + fx.unit ); 91 | }; 92 | }); 93 | } 94 | 95 | })(jQuery); 96 | -------------------------------------------------------------------------------- /tests/qunit/qunit.css: -------------------------------------------------------------------------------- 1 | /** Font Family and Sizes */ 2 | 3 | #qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { 4 | font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial; 5 | } 6 | 7 | #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } 8 | #qunit-tests { font-size: smaller; } 9 | 10 | 11 | /** Resets */ 12 | 13 | #qunit-tests, #qunit-tests li ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { 14 | margin: 0; 15 | padding: 0; 16 | } 17 | 18 | 19 | /** Header */ 20 | 21 | #qunit-header { 22 | padding: 0.5em 0 0.5em 1em; 23 | 24 | color: #fff; 25 | text-shadow: rgba(0, 0, 0, 0.5) 4px 4px 1px; 26 | background-color: #0d3349; 27 | 28 | border-radius: 15px 15px 0 0; 29 | -moz-border-radius: 15px 15px 0 0; 30 | -webkit-border-top-right-radius: 15px; 31 | -webkit-border-top-left-radius: 15px; 32 | } 33 | 34 | #qunit-banner { 35 | height: 5px; 36 | } 37 | 38 | #qunit-testrunner-toolbar { 39 | padding: 0em 0 0.5em 2em; 40 | } 41 | 42 | #qunit-userAgent { 43 | padding: 0.5em 0 0.5em 2.5em; 44 | background-color: #2b81af; 45 | color: #fff; 46 | text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; 47 | } 48 | 49 | 50 | /** Tests: Pass/Fail */ 51 | 52 | #qunit-tests { 53 | list-style-position: inside; 54 | } 55 | 56 | #qunit-tests li { 57 | padding: 0.4em 0.5em 0.4em 2.5em; 58 | border-bottom: 1px solid #fff; 59 | list-style-position: inside; 60 | } 61 | 62 | #qunit-tests li strong { 63 | cursor: pointer; 64 | } 65 | 66 | #qunit-tests li ol { 67 | margin-top: 0.5em; 68 | padding: 0.5em; 69 | 70 | background-color: #fff; 71 | 72 | border-radius: 15px; 73 | -moz-border-radius: 15px; 74 | -webkit-border-radius: 15px; 75 | 76 | box-shadow: inset 0px 2px 13px #999; 77 | -moz-box-shadow: inset 0px 2px 13px #999; 78 | -webkit-box-shadow: inset 0px 2px 13px #999; 79 | } 80 | 81 | #qunit-tests li li { 82 | margin: 0.5em; 83 | padding: 0.4em 0.5em 0.4em 0.5em; 84 | background-color: #fff; 85 | border-bottom: none; 86 | list-style-position: inside; 87 | } 88 | 89 | /*** Passing Styles */ 90 | 91 | #qunit-tests li li.pass { 92 | color: #5E740B; 93 | background-color: #fff; 94 | border-left: 26px solid #C6E746; 95 | } 96 | 97 | #qunit-tests li.pass { color: #528CE0; background-color: #D2E0E6; } 98 | #qunit-tests li.pass span.test-name { color: #366097; } 99 | 100 | #qunit-tests li li.pass span.test-actual, 101 | #qunit-tests li li.pass span.test-expected { color: #999999; } 102 | 103 | strong b.pass { color: #5E740B; } 104 | 105 | #qunit-banner.qunit-pass { background-color: #C6E746; } 106 | 107 | /*** Failing Styles */ 108 | 109 | #qunit-tests li li.fail { 110 | color: #710909; 111 | background-color: #fff; 112 | border-left: 26px solid #EE5757; 113 | } 114 | 115 | #qunit-tests li.fail { color: #000000; background-color: #EE5757; } 116 | #qunit-tests li.fail span.test-name, 117 | #qunit-tests li.fail span.module-name { color: #000000; } 118 | 119 | #qunit-tests li li.fail span.test-actual { color: #EE5757; } 120 | #qunit-tests li li.fail span.test-expected { color: green; } 121 | 122 | strong b.fail { color: #710909; } 123 | 124 | #qunit-banner.qunit-fail, 125 | #qunit-testrunner-toolbar { background-color: #EE5757; } 126 | 127 | 128 | /** Footer */ 129 | 130 | #qunit-testresult { 131 | padding: 0.5em 0.5em 0.5em 2.5em; 132 | 133 | color: #2b81af; 134 | background-color: #D2E0E6; 135 | 136 | border-radius: 0 0 15px 15px; 137 | -moz-border-radius: 0 0 15px 15px; 138 | -webkit-border-bottom-right-radius: 15px; 139 | -webkit-border-bottom-left-radius: 15px; 140 | } 141 | 142 | /** Fixture */ 143 | 144 | #qunit-fixture { 145 | position: absolute; 146 | top: -10000px; 147 | left: -10000px; 148 | } 149 | -------------------------------------------------------------------------------- /tests/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | jQuery-cssHooks Test Suite 5 | 6 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 |

jQuery-cssHooks Test Suite

78 |

79 |
80 |

81 |
    82 |
    83 |
    Hello World
    84 |
    85 |
    86 | 87 | 88 | -------------------------------------------------------------------------------- /skeleton.js: -------------------------------------------------------------------------------- 1 | /* 2 | * : A jQuery cssHooks adding a cross browser property to $.fn.css() and $.fn.animate() 3 | * 4 | * limitations: 5 | * - requires jQuery 1.4.3+ 6 | * - compatible with Firefox , Chrome , Safari , Opera , Internet Explorer 7 | * - 8 | * 9 | * Copyright 10 | * License 11 | */ 12 | (function( $ ) { 13 | 14 | var div = document.createElement("div"), 15 | divStyle = div.style, 16 | propertyName = "", 17 | // with leading upper-case 18 | suffix = "", 19 | testProperties = [ 20 | "O" + suffix, 21 | // "ms", not "Ms" 22 | "ms" + suffix, 23 | "Webkit" + suffix, 24 | "Moz" + suffix, 25 | // prefix-less property 26 | propertyName 27 | ], 28 | i = testProperties.length, 29 | // use local variables instead of jQuery.support and jQuery.cssHooks 30 | // throughout the plugin to reduce file size once minified 31 | supportProperty, 32 | supportMsAlternative, 33 | propertyHook; 34 | 35 | // test different vendor prefixes of this property 36 | while ( i-- ) { 37 | if ( testProperties[i] in divStyle ) { 38 | $.support[propertyName] = supportProperty = testProperties[i]; 39 | continue; 40 | } 41 | } 42 | // If a proprietary alternative exists for IE678, include another test for it 43 | if ( !supportProperty ) { 44 | $.support.MsAlternative = supportMsAlternative = divStyle[""] === ""; 45 | } 46 | 47 | // the following line should be removed if "px" is the default unit for this property 48 | $.cssNumber[propertyName] = true; 49 | 50 | // prefix-less property will likely not need a hook 51 | if ( supportProperty && supportProperty != propertyName ) { 52 | // Modern browsers can use jQuery.cssProps as a basic hook 53 | $.cssProps[propertyName] = supportProperty; 54 | 55 | // Real cssHooks might be used to normalize implementations inconsistencies in some browsers 56 | // for example 57 | if ( supportProperty == "Moz" + suffix ) { 58 | propertyHook = { 59 | set: function( elem, value ) { 60 | elem.style[ supportProperty ] = normalizeFirefoxSet( value ); 61 | } 62 | }; 63 | /* Fix two jQuery bugs present before jQuery 1.6 64 | * - rupper is incompatible with IE9, see http://jqbug.com/8346 65 | * - jQuery.css is not really jQuery.cssProps aware, see http://jqbug.com/8402 66 | */ 67 | } else if ( /^1\.[0-5](?:\.|$)/.test($.fn.jquery) ) { 68 | propertyHook = { 69 | get: function( elem, computed ) { 70 | return (computed ? 71 | $.css( elem, supportProperty.replace(/^ms/, "Ms") ): 72 | elem.style[supportProperty] 73 | ) 74 | } 75 | } 76 | } 77 | // If a proprietary alternative exists for IE678, implement a complete hook for it 78 | } else if ( supportMsAlternative ) { 79 | propertyHook = { 80 | get: function( elem, computed, extra ) { 81 | // Handle crazy conversion from the proprietary alternative 82 | }, 83 | set: function( elem, value ) { 84 | // Handle crazy conversion to the proprietary alternative 85 | } 86 | } 87 | } 88 | // populate jQuery.cssHooks with the appropriate hook if necessary 89 | if ( propertyHook ) { 90 | $.cssHooks[propertyName] = propertyHook; 91 | } 92 | // uncomment following line if the animation logic uses the getter 93 | //var propertyGet = propertyHook && propertyHook.get || $.css;*/ 94 | 95 | // animation for simple values 96 | $.fx.step[propertyName] = function( fx ) { 97 | var value = fx.now + fx.unit; 98 | propertyHook && propertyHook.set? 99 | // Use a setter hook if it exists 100 | propertyHook.set( elem, transform ): 101 | // Otherwise modify raw DOM for maximum performances 102 | elem.style[supportProperty] = transform; 103 | } 104 | // The following code can be used as a base to animate more complex values 105 | /*$.fx.step[propertyName] = function( fx ) { 106 | // fx.start and fx.end will probably be parsed on the first step to be computable 107 | if ( !fx.start || typeof fx.start === "string" ) { 108 | // fix fx.start value 109 | if ( !fx.start ) { 110 | fx.start = propertyGet( fx.elem, supportProperty ); 111 | } 112 | fx.start = parse(fx.start); 113 | fx.end = parse(fx.end); 114 | } 115 | 116 | // the code that calculates the value or components of it, is specific to the property 117 | // but it is likely to look like the following 118 | var value = fx.start + ( fx.end - fx.start ) * fx.pos; 119 | 120 | // set the value once it has been calculated 121 | propertyHook.set? 122 | propertyHook.set( elem, transform ): 123 | elem.style[supportProperty] = transform; 124 | }*/ 125 | 126 | })( jQuery ); -------------------------------------------------------------------------------- /border-radius.htc: -------------------------------------------------------------------------------- 1 | --Do not remove this if you are using-- 2 | Original Author: Remiz Rahnas 3 | Original Author URL: http://www.htmlremix.com 4 | Published date: 2008/09/24 5 | 6 | Changes by Nick Fetchak: 7 | - IE8 standards mode compatibility 8 | - VML elements now positioned behind original box rather than inside of it - should be less prone to breakage 9 | Published date : 2009/11/18 10 | 11 | 12 | 13 | 143 | 144 | -------------------------------------------------------------------------------- /borderradiusalt.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Copyright (c) 2011 Tom Ellis (http://www.webmuse.co.uk) 3 | * Border Radius cssHook for jQuery 4 | * Limitations: 5 | - Works with jQuery 1.4.3 and higher 6 | - Can't animate border radius in IE 7 | * Licensed under the MIT License (LICENSE.txt). 8 | */ 9 | (function($) { 10 | 11 | var div = document.createElement("div"), 12 | divStyle = div.style, 13 | rWhiteSpace = /\s/, 14 | dirs = "TopLeft TopRight BottomRight BottomLeft".split(rWhiteSpace), 15 | getRadii = function( n ){ 16 | if( !n ) { 17 | return [0]; 18 | } else if(typeof n == 'number') { 19 | return [n]; 20 | } else { 21 | r = n.match(/(\-\d+|\d+)/g) || [0]; 22 | for(var i in r) { 23 | r[i] = parseInt(r[i]); 24 | } 25 | } 26 | return r; 27 | }; 28 | 29 | $.support.borderRadius = 30 | divStyle.borderRadius === '' ? 'borderRadius' : 31 | (divStyle.MozBorderRadius === '' ? 'MozBorderRadius' : 32 | (divStyle.WebkitBorderRadius === '' ? 'WebkitBorderRadius' : false)); 33 | 34 | //Browsers support border radius corners differently (For now) 35 | 36 | $.support.TopLeft = false; 37 | $.support.TopRight = false; 38 | $.support.BottomLeft = false; 39 | $.support.BottomRight = false; 40 | 41 | if( $.support.borderRadius === 'borderRadius' ) { 42 | 43 | $.support.TopLeft = 'borderTopLeftRadius'; 44 | $.support.TopRight = 'borderTopLeftRadius'; 45 | $.support.BottomLeft = 'borderTopLeftRadius'; 46 | $.support.BottomRight = 'borderTopLeftRadius'; 47 | 48 | } else if( $.support.borderRadius === 'MozBorderRadius' ) { 49 | 50 | $.support.TopLeft = 'borderTopLeftRadius'; 51 | $.support.TopRight = 'borderTopLeftRadius'; 52 | $.support.BottomLeft = 'borderTopLeftRadius'; 53 | $.support.BottomRight = 'borderTopLeftRadius'; 54 | 55 | } else if( $.support.borderRadius === 'WebkitBorderRadius' ) { 56 | 57 | $.support.TopLeft = 'borderTopLeftRadius'; 58 | $.support.TopRight = 'borderTopLeftRadius'; 59 | $.support.BottomLeft = 'borderTopLeftRadius'; 60 | $.support.BottomRight = 'borderTopLeftRadius'; 61 | } 62 | 63 | if ( $.support.borderRadius && $.support.borderRadius !== "borderRadius" ){ 64 | //alert('here'); 65 | //BorderRadius 66 | $.cssHooks.borderRadius = { 67 | get: function( elem, computed, extra ) { 68 | 69 | return $.map(dirs, function( dir ) { 70 | return $.css( elem, $.support[dir], computed ); 71 | }).join(" "); 72 | 73 | }, 74 | set: function( elem, value ) { 75 | 76 | var parts = value.split(rWhiteSpace), 77 | values = { 78 | "TopLeft": parts[0], 79 | "TopRight": parts[1] || parts[0], 80 | "BottomLeft": parts[2] || parts[0], 81 | "BottomRight": parts[3] || parts[1] || parts[0] 82 | }; 83 | 84 | elem.style[ $.support.borderRadius ] = value; 85 | } 86 | }; 87 | 88 | $.each( dirs, function( i, dir ) { 89 | 90 | $.cssHooks[ "border" + dir + "Radius"] = { 91 | get: function( elem, computed, extra ) { 92 | 93 | return $.css( elem, $.support[dir] ); 94 | }, 95 | set: function( elem, value ){ 96 | 97 | elem.style[ $.support[dir] ] = value; 98 | } 99 | }; 100 | 101 | $.fx.step[ "border" + dir + "Radius" ] = function( fx ) { 102 | 103 | /* 104 | 105 | function ii( n ){ 106 | if( !n ) { 107 | return [0]; 108 | } else if(typeof n == 'number') { 109 | return [n]; 110 | } else { 111 | r = n.match(/(\-\d+|\d+)/g) || [0]; 112 | for(var i in r) { 113 | r[i] = parseInt(r[i]); 114 | } 115 | } 116 | return r; 117 | } 118 | 119 | if(!fx.endx) { 120 | 121 | var i = ii($(fx.elem).css( $.support[dir] ) ); 122 | 123 | fx.startx = i[0]; 124 | fx.starty = i[1]||i[0]; 125 | fx.f = ii(fx.end); 126 | fx.endx = fx.f[0]; 127 | fx.endy = fx.f[1]||fx.f[0]; 128 | 129 | if((fx.endy - fx.starty) < (fx.endx - fx.startx)) { 130 | fx.which = true; 131 | fx.end = fx.endx; 132 | fx.start = fx.startx; 133 | fx.now = fx.start; 134 | fx.now2 = fx.starty; 135 | } else { 136 | fx.which = false; 137 | fx.end = fx.endy; 138 | fx.start = fx.starty; 139 | fx.now = fx.start; 140 | fx.now2 = fx.startx; 141 | } 142 | } 143 | fx.now2 = (fx.which)? 144 | fx.starty + ((fx.endy - fx.starty) * fx.pos) 145 | : 146 | fx.startx + ((fx.endx - fx.startx) * fx.pos); 147 | var set = (fx.which)? 148 | (fx.now + fx.unit+" "+fx.now2 + fx.unit) 149 | : 150 | (fx.now2 + fx.unit+" "+fx.now + fx.unit); 151 | 152 | $.cssHooks[ "border" + dir + "Radius" ].set( fx.elem, fx.now + fx.unit+" "+fx.now2 + fx.unit ); 153 | */ 154 | 155 | //$.cssHooks[ "border" + dir + "Radius" ].set( fx.elem, set ); 156 | //console.log( fx.now + fx.unit+" "+fx.now2 + fx.unit ); 157 | 158 | //$.cssHooks[ "border" + dir + "Radius" ].set( fx.elem, fx.now + fx.unit+" "+fx.now2 + fx.unit ); 159 | 160 | $.cssHooks[ "border" + dir + "Radius" ].set( fx.elem, fx.now + fx.unit ); 161 | }; 162 | 163 | 164 | }); 165 | 166 | // setup fx hooks 167 | $.fx.step.borderRadius = function( fx ) { 168 | $.cssHooks.borderRadius.set( fx.elem, fx.now + fx.unit ); 169 | }; 170 | 171 | } else if ( !$.support.borderRadius && "createStyleSheet" in document ) { 172 | 173 | //BorderRadius Plugin 174 | $.cssHooks.borderRadius = { 175 | get: function( elem, computed, extra ) { 176 | 177 | return $.data(elem, "borderRadiusIE"); 178 | }, 179 | set: function( elem, value ) { 180 | 181 | var css, 182 | parts = value.split(rWhiteSpace), 183 | one = parts[0], 184 | two = parts[1] || parts[0], 185 | three = parts[2] || parts[0], 186 | four = parts[3] || parts[1] || parts[0], 187 | values = [ 188 | one, 189 | two, 190 | three, 191 | four 192 | ]; 193 | 194 | css = ($.data( elem, "borderRadiusIECSS")) ? 195 | $.data( elem, "borderRadiusIECSS") : document.createStyleSheet("ie_style.css") 196 | css.cssText = ""; 197 | css.addRule( "#results", "border-radius:" + values.join(" ") ); 198 | //Needs to be the directory from root of index.html 199 | //or page that uses this js file to the border radius htc file 200 | elem.style.behavior = "url(js/border-radius.htc)"; 201 | 202 | $.data(elem, "borderRadiusIE", values.join(" ")); 203 | $.data( elem, "borderRadiusIECSS", css); 204 | 205 | } 206 | }; 207 | 208 | } 209 | 210 | div = divStyle = null; 211 | 212 | })(jQuery); -------------------------------------------------------------------------------- /color.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | var colornames = { 3 | aliceblue: { r:240, g:248, b:255 }, 4 | antiquewhite: { r:250, g:235, b:215 }, 5 | aqua: { r:0, g:255, b:255 }, 6 | aquamarine: { r:127, g:255, b:212 }, 7 | azure: { r:240, g:255, b:255 }, 8 | beige: { r:245, g:245, b:220 }, 9 | bisque: { r:255, g:228, b:196 }, 10 | black: { r:0, g:0, b:0 }, 11 | blanchedalmond: { r:255, g:235, b:205 }, 12 | blue: { r:0, g:0, b:255 }, 13 | blueviolet: { r:138, g:43, b:226 }, 14 | brown: { r:165, g:42, b:42 }, 15 | burlywood: { r:222, g:184, b:135 }, 16 | cadetblue: { r:95, g:158, b:160 }, 17 | chartreuse: { r:127, g:255, b:0 }, 18 | chocolate: { r:210, g:105, b:30 }, 19 | coral: { r:255, g:127, b:80 }, 20 | cornflowerblue: { r:100, g:149, b:237 }, 21 | cornsilk: { r:255, g:248, b:220 }, 22 | crimson: { r:220, g:20, b:60 }, 23 | cyan: { r:0, g:255, b:255 }, 24 | darkblue: { r:0, g:0, b:139 }, 25 | darkcyan: { r:0, g:139, b:139 }, 26 | darkgoldenrod: { r:184, g:134, b:11 }, 27 | darkgray: { r:169, g:169, b:169 }, 28 | darkgreen: { r:0, g:100, b:0 }, 29 | darkgrey: { r:169, g:169, b:169 }, 30 | darkkhaki: { r:189, g:183, b:107 }, 31 | darkmagenta: { r:139, g:0, b:139 }, 32 | darkolivegreen: { r:85, g:107, b:47 }, 33 | darkorange: { r:255, g:140, b:0 }, 34 | darkorchid: { r:153, g:50, b:204 }, 35 | darkred: { r:139, g:0, b:0 }, 36 | darksalmon: { r:233, g:150, b:122 }, 37 | darkseagreen: { r:143, g:188, b:143 }, 38 | darkslateblue: { r:72, g:61, b:139 }, 39 | darkslategray: { r:47, g:79, b:79 }, 40 | darkslategrey: { r:47, g:79, b:79 }, 41 | darkturquoise: { r:0, g:206, b:209 }, 42 | darkviolet: { r:148, g:0, b:211 }, 43 | deeppink: { r:255, g:20, b:147 }, 44 | deepskyblue: { r:0, g:191, b:255 }, 45 | dimgray: { r:105, g:105, b:105 }, 46 | dimgrey: { r:105, g:105, b:105 }, 47 | dodgerblue: { r:30, g:144, b:255 }, 48 | firebrick: { r:178, g:34, b:34 }, 49 | floralwhite: { r:255, g:250, b:240 }, 50 | forestgreen: { r:34, g:139, b:34 }, 51 | fuchsia: { r:255, g:0, b:255 }, 52 | gainsboro: { r:220, g:220, b:220 }, 53 | ghostwhite: { r:248, g:248, b:255 }, 54 | gold: { r:255, g:215, b:0 }, 55 | goldenrod: { r:218, g:165, b:32 }, 56 | gray: { r:128, g:128, b:128 }, 57 | green: { r:0, g:128, b:0 }, 58 | greenyellow: { r:173, g:255, b:47 }, 59 | grey: { r:128, g:128, b:128 }, 60 | honeydew: { r:240, g:255, b:240 }, 61 | hotpink: { r:255, g:105, b:180 }, 62 | indianred: { r:205, g:92, b:92 }, 63 | indigo: { r:75, g:0, b:130 }, 64 | ivory: { r:255, g:255, b:240 }, 65 | khaki: { r:240, g:230, b:140 }, 66 | lavender: { r:230, g:230, b:250 }, 67 | lavenderblush: { r:255, g:240, b:245 }, 68 | lawngreen: { r:124, g:252, b:0 }, 69 | lemonchiffon: { r:255, g:250, b:205 }, 70 | lightblue: { r:173, g:216, b:230 }, 71 | lightcoral: { r:240, g:128, b:128 }, 72 | lightcyan: { r:224, g:255, b:255 }, 73 | lightgoldenrodyellow: { r:250, g:250, b:210 }, 74 | lightgray: { r:211, g:211, b:211 }, 75 | lightgreen: { r:144, g:238, b:144 }, 76 | lightgrey: { r:211, g:211, b:211 }, 77 | lightpink: { r:255, g:182, b:193 }, 78 | lightsalmon: { r:255, g:160, b:122 }, 79 | lightseagreen: { r:32, g:178, b:170 }, 80 | lightskyblue: { r:135, g:206, b:250 }, 81 | lightslategray: { r:119, g:136, b:153 }, 82 | lightslategrey: { r:119, g:136, b:153 }, 83 | lightsteelblue: { r:176, g:196, b:222 }, 84 | lightyellow: { r:255, g:255, b:224 }, 85 | lime: { r:0, g:255, b:0 }, 86 | limegreen: { r:50, g:205, b:50 }, 87 | linen: { r:250, g:240, b:230 }, 88 | magenta: { r:255, g:0, b:255 }, 89 | maroon: { r:128, g:0, b:0 }, 90 | mediumaquamarine: { r:102, g:205, b:170 }, 91 | mediumblue: { r:0, g:0, b:205 }, 92 | mediumorchid: { r:186, g:85, b:211 }, 93 | mediumpurple: { r:147, g:112, b:219 }, 94 | mediumseagreen: { r:60, g:179, b:113 }, 95 | mediumslateblue: { r:123, g:104, b:238 }, 96 | mediumspringgreen: { r:0, g:250, b:154 }, 97 | mediumturquoise: { r:72, g:209, b:204 }, 98 | mediumvioletred: { r:199, g:21, b:133 }, 99 | midnightblue: { r:25, g:25, b:112 }, 100 | mintcream: { r:245, g:255, b:250 }, 101 | mistyrose: { r:255, g:228, b:225 }, 102 | moccasin: { r:255, g:228, b:181 }, 103 | navajowhite: { r:255, g:222, b:173 }, 104 | navy: { r:0, g:0, b:128 }, 105 | oldlace: { r:253, g:245, b:230 }, 106 | olive: { r:128, g:128, b:0 }, 107 | olivedrab: { r:107, g:142, b:35 }, 108 | orange: { r:255, g:165, b:0 }, 109 | orangered: { r:255, g:69, b:0 }, 110 | orchid: { r:218, g:112, b:214 }, 111 | palegoldenrod: { r:238, g:232, b:170 }, 112 | palegreen: { r:152, g:251, b:152 }, 113 | paleturquoise: { r:175, g:238, b:238 }, 114 | palevioletred: { r:219, g:112, b:147 }, 115 | papayawhip: { r:255, g:239, b:213 }, 116 | peachpuff: { r:255, g:218, b:185 }, 117 | peru: { r:205, g:133, b:63 }, 118 | pink: { r:255, g:192, b:203 }, 119 | plum: { r:221, g:160, b:221 }, 120 | powderblue: { r:176, g:224, b:230 }, 121 | purple: { r:128, g:0, b:128 }, 122 | red: { r:255, g:0, b:0 }, 123 | rosybrown: { r:188, g:143, b:143 }, 124 | royalblue: { r:65, g:105, b:225 }, 125 | saddlebrown: { r:139, g:69, b:19 }, 126 | salmon: { r:250, g:128, b:114 }, 127 | sandybrown: { r:244, g:164, b:96 }, 128 | seagreen: { r:46, g:139, b:87 }, 129 | seashell: { r:255, g:245, b:238 }, 130 | sienna: { r:160, g:82, b:45 }, 131 | silver: { r:192, g:192, b:192 }, 132 | skyblue: { r:135, g:206, b:235 }, 133 | slateblue: { r:106, g:90, b:205 }, 134 | slategray: { r:112, g:128, b:144 }, 135 | slategrey: { r:112, g:128, b:144 }, 136 | snow: { r:255, g:250, b:250 }, 137 | springgreen: { r:0, g:255, b:127 }, 138 | steelblue: { r:70, g:130, b:180 }, 139 | tan: { r:210, g:180, b:140 }, 140 | teal: { r:0, g:128, b:128 }, 141 | thistle: { r:216, g:191, b:216 }, 142 | tomato: { r:255, g:99, b:71 }, 143 | turquoise: { r:64, g:224, b:208 }, 144 | violet: { r:238, g:130, b:238 }, 145 | wheat: { r:245, g:222, b:179 }, 146 | white: { r:255, g:255, b:255 }, 147 | whitesmoke: { r:245, g:245, b:245 }, 148 | yellow: { r:255, g:255, b:0 }, 149 | yellowgreen: { r:154, g:205, b:50 }, 150 | transparent: { r:-1, g:-1, b:-1 } 151 | }, 152 | // Not a complete list yet... 153 | props = 'backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor borderColor boxShadowColor color outlineColor textShadowColor'.split(' '); 154 | 155 | $.color = { 156 | normalize: function(input) { 157 | var color, alpha, 158 | result, name, i, l, 159 | rhex = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/, 160 | rhexshort = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/, 161 | rrgb = /rgb(?:a)?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(0*\.?\d+)\s*)?\)/, 162 | rrgbpercent = /rgb(?:a)?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(0*\.?\d+)\s*)?\)/, 163 | rhsl = /hsl(?:a)?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(0*\.?\d+)\s*)?\)/; 164 | 165 | // Handle color: #rrggbb 166 | if (result = rhex.exec(input)) { 167 | color = { 168 | r: parseInt(result[1], 16), 169 | g: parseInt(result[2], 16), 170 | b: parseInt(result[3], 16), 171 | source: result[0] 172 | }; 173 | } 174 | // Handle color: #rgb 175 | else if (result = rhexshort.exec(input)) { 176 | color = { 177 | r: parseInt(result[1]+result[1], 16), 178 | g: parseInt(result[2]+result[2], 16), 179 | b: parseInt(result[3]+result[3], 16), 180 | source: result[0] 181 | }; 182 | } 183 | // Handle color: rgb[a](r, g, b [, a]) 184 | else if (result = rrgb.exec(input)) { 185 | color = { 186 | r: parseInt(result[1], 10), 187 | g: parseInt(result[2], 10), 188 | b: parseInt(result[3], 10), 189 | alpha: parseFloat(result[4], 10), 190 | source: result[0] 191 | }; 192 | } 193 | // Handle color: rgb[a](r%, g%, b% [, a]) 194 | else if (result = rrgbpercent.exec(input)) { 195 | color = { 196 | r: parseInt(result[1] * 2.55, 10), 197 | g: parseInt(result[2] * 2.55, 10), 198 | b: parseInt(result[3] * 2.55, 10), 199 | alpha: parseFloat(result[4], 10), 200 | source: result[0] 201 | }; 202 | } 203 | // Handle color: hsl[a](h%, s%, l% [, a]) 204 | else if (result = rhsl.exec(input)) { 205 | color = $.color.hsl_to_rgb( 206 | parseFloat(result[1], 10) / 100, 207 | parseFloat(result[2], 10) / 100, 208 | parseFloat(result[3], 10) / 100 209 | ); 210 | color.alpha = parseFloat(result[4], 10); 211 | color.source = result[0]; 212 | } 213 | // Handle color: name 214 | else { 215 | result = input.split(' '); 216 | for (i = 0, l = result.length; i < l; i++) { 217 | name = result[i]; 218 | 219 | if (colornames[name]) { 220 | break; 221 | } 222 | } 223 | 224 | if (!colornames[name]) { 225 | name = 'transparent'; 226 | } 227 | 228 | color = colornames[name]; 229 | color.source = name; 230 | } 231 | 232 | if (!color.alpha && color.alpha !== 0) { 233 | delete color.alpha; 234 | } 235 | 236 | return color; 237 | }, 238 | 239 | hsl_to_rgb: function(h, s, l, a) { 240 | var r, g, b, m1, m2; 241 | 242 | if (s === 0) { 243 | r = g = b = l; 244 | } else { 245 | if (l <= 0.5) { 246 | m2 = l * (s + 1); 247 | } else { 248 | m2 = (l + s) - (l * s); 249 | } 250 | 251 | m1 = (l * 2) - m2; 252 | r = parseInt(255 * $.color.hue_to_rgb(m1, m2, h + (1/3)), 10); 253 | g = parseInt(255 * $.color.hue_to_rgb(m1, m2, h), 10); 254 | b = parseInt(255 * $.color.hue_to_rgb(m1, m2, h - (1/3)), 10); 255 | } 256 | 257 | return { r:r, g:g, b:b, alpha:a }; 258 | }, 259 | 260 | hue_to_rgb: function(m1, m2, h) { 261 | if (h < 0) { h++; } 262 | if (h > 1) { h--; } 263 | 264 | if ((h * 6) < 1) { return m1 + ((m2 - m1) * h * 6); } 265 | else if ((h * 2) < 1) { return m2; } 266 | else if ((h * 3) < 2) { return m1 + ((m2 - m1) * ((2/3) - h) * 6); } 267 | else { return m1; } 268 | } 269 | }; 270 | 271 | if ($.cssHooks) { 272 | $.each(props, function(i, hook) { 273 | $.cssHooks[hook] = { 274 | set: function(elem, value) { 275 | value = $.color.normalize(value); 276 | 277 | if (!value.alpha) { 278 | value.alpha = 1; 279 | } 280 | 281 | elem.style[hook] = 'rgba(' + value.r + ',' + value.g + ',' + value.b + ',' + value.alpha + ')'; 282 | } 283 | }; 284 | 285 | $.fx.step[hook] = function(fx) { 286 | var val; 287 | 288 | if ( !fx.start || typeof fx.start === 'string' ) { 289 | if ( !fx.start ) { 290 | fx.start = $.css(fx.elem, hook); 291 | } 292 | 293 | fx.start = $.color.normalize(fx.start); 294 | fx.end = $.color.normalize(fx.end); 295 | 296 | if (!fx.start.alpha) { 297 | fx.start.alpha = 1; 298 | } 299 | 300 | if (!fx.end.alpha) { 301 | fx.end.alpha = 1; 302 | } 303 | } 304 | 305 | $.style(fx.elem, hook, 'rgba(' 306 | + parseInt(fx.start.r + (fx.pos * (fx.end.r - fx.start.r)), 10) + ',' 307 | + parseInt(fx.start.g + (fx.pos * (fx.end.g - fx.start.g)), 10) + ',' 308 | + parseInt(fx.start.b + (fx.pos * (fx.end.b - fx.start.b)), 10) + ',' 309 | + parseFloat(fx.start.alpha + (fx.pos * (fx.end.alpha - fx.start.alpha))) + ')' 310 | ); 311 | }; 312 | }); 313 | } 314 | })(jQuery); 315 | -------------------------------------------------------------------------------- /transform.js: -------------------------------------------------------------------------------- 1 | /* 2 | * transform: A jQuery cssHooks adding cross-browser 2d transform capabilities to $.fn.css() and $.fn.animate() 3 | * 4 | * limitations: 5 | * - requires jQuery 1.4.3+ 6 | * - Should you use the *translate* property, then your elements need to be absolutely positionned in a relatively positionned wrapper **or it will fail in IE678**. 7 | * - transformOrigin is not accessible 8 | * 9 | * latest version and complete README available on Github: 10 | * https://github.com/louisremi/jquery.transform.js 11 | * 12 | * Copyright 2011 @louis_remi 13 | * Licensed under the MIT license. 14 | * 15 | * This saved you an hour of work? 16 | * Send me music http://www.amazon.co.uk/wishlist/HNTU0468LQON 17 | * 18 | */ 19 | (function( $ ) { 20 | 21 | /* 22 | * Feature tests and global variables 23 | */ 24 | var div = document.createElement('div'), 25 | divStyle = div.style, 26 | propertyName = 'transform', 27 | suffix = 'Transform', 28 | testProperties = [ 29 | 'O' + suffix, 30 | 'ms' + suffix, 31 | 'Webkit' + suffix, 32 | 'Moz' + suffix, 33 | // prefix-less property 34 | propertyName 35 | ], 36 | i = testProperties.length, 37 | supportProperty, 38 | supportMatrixFilter, 39 | propertyHook, 40 | propertyGet, 41 | rMatrix = /Matrix([^)]*)/; 42 | 43 | // test different vendor prefixes of this property 44 | while ( i-- ) { 45 | if ( testProperties[i] in divStyle ) { 46 | $.support[propertyName] = supportProperty = testProperties[i]; 47 | continue; 48 | } 49 | } 50 | // IE678 alternative 51 | if ( !supportProperty ) { 52 | $.support.matrixFilter = supportMatrixFilter = divStyle.filter === ''; 53 | } 54 | // prevent IE memory leak 55 | div = divStyle = null; 56 | 57 | // px isn't the default unit of this property 58 | $.cssNumber[propertyName] = true; 59 | 60 | /* 61 | * fn.css() hooks 62 | */ 63 | if ( supportProperty && supportProperty != propertyName ) { 64 | // Modern browsers can use jQuery.cssProps as a basic hook 65 | $.cssProps[propertyName] = supportProperty; 66 | 67 | // Firefox needs a complete hook because it stuffs matrix with 'px' 68 | if ( supportProperty == 'Moz' + suffix ) { 69 | propertyHook = { 70 | get: function( elem, computed ) { 71 | return (computed ? 72 | // remove 'px' from the computed matrix 73 | $.css( elem, supportProperty ).split('px').join(''): 74 | elem.style[supportProperty] 75 | ) 76 | }, 77 | set: function( elem, value ) { 78 | // remove 'px' from matrices 79 | elem.style[supportProperty] = /matrix[^)p]*\)/.test(value) ? 80 | value.replace(/matrix((?:[^,]*,){4})([^,]*),([^)]*)/, 'matrix$1$2px,$3px'): 81 | value; 82 | } 83 | } 84 | /* Fix two jQuery bugs still present in 1.5.1 85 | * - rupper is incompatible with IE9, see http://jqbug.com/8346 86 | * - jQuery.css is not really jQuery.cssProps aware, see http://jqbug.com/8402 87 | */ 88 | } else if ( /^1\.[0-5](?:\.|$)/.test($.fn.jquery) ) { 89 | propertyHook = { 90 | get: function( elem, computed ) { 91 | return (computed ? 92 | $.css( elem, supportProperty.replace(/^ms/, 'Ms') ): 93 | elem.style[supportProperty] 94 | ) 95 | } 96 | } 97 | } 98 | /* TODO: leverage hardware acceleration of 3d transform in Webkit only 99 | else if ( supportProperty == 'Webkit' + suffix && support3dTransform ) { 100 | propertyHook = { 101 | set: function( elem, value ) { 102 | elem.style[supportProperty] = 103 | value.replace(); 104 | } 105 | } 106 | }*/ 107 | 108 | } else if ( supportMatrixFilter ) { 109 | propertyHook = { 110 | get: function( elem, computed ) { 111 | var elemStyle = ( computed && elem.currentStyle ? elem.currentStyle : elem.style ), 112 | matrix; 113 | 114 | if ( elemStyle && rMatrix.test( elemStyle.filter ) ) { 115 | matrix = RegExp.$1.split(','); 116 | matrix = [ 117 | matrix[0].split('=')[1], 118 | matrix[2].split('=')[1], 119 | matrix[1].split('=')[1], 120 | matrix[3].split('=')[1] 121 | ]; 122 | } else { 123 | matrix = [1,0,0,1]; 124 | } 125 | matrix[4] = elemStyle ? elemStyle.left : 0; 126 | matrix[5] = elemStyle ? elemStyle.top : 0; 127 | return "matrix(" + matrix + ")"; 128 | }, 129 | set: function( elem, value, animate ) { 130 | var elemStyle = elem.style, 131 | currentStyle, 132 | Matrix, 133 | filter; 134 | 135 | if ( !animate ) { 136 | elemStyle.zoom = 1; 137 | } 138 | 139 | value = matrix(value); 140 | 141 | // rotate, scale and skew 142 | if ( !animate || animate.M ) { 143 | Matrix = [ 144 | "Matrix("+ 145 | "M11="+value[0], 146 | "M12="+value[2], 147 | "M21="+value[1], 148 | "M22="+value[3], 149 | "SizingMethod='auto expand'" 150 | ].join(); 151 | filter = ( currentStyle = elem.currentStyle ) && currentStyle.filter || elemStyle.filter || ""; 152 | 153 | elemStyle.filter = rMatrix.test(filter) ? 154 | filter.replace(rMatrix, Matrix) : 155 | filter + " progid:DXImageTransform.Microsoft." + Matrix + ")"; 156 | 157 | // center the transform origin, from pbakaus's Transformie http://github.com/pbakaus/transformie 158 | if ( (centerOrigin = $.transform.centerOrigin) ) { 159 | elemStyle[centerOrigin == 'margin' ? 'marginLeft' : 'left'] = -(elem.offsetWidth/2) + (elem.clientWidth/2) + 'px'; 160 | elemStyle[centerOrigin == 'margin' ? 'marginTop' : 'top'] = -(elem.offsetHeight/2) + (elem.clientHeight/2) + 'px'; 161 | } 162 | } 163 | 164 | // translate 165 | if ( !animate || animate.T ) { 166 | // We assume that the elements are absolute positionned inside a relative positionned wrapper 167 | elemStyle.left = value[4] + 'px'; 168 | elemStyle.top = value[5] + 'px'; 169 | } 170 | } 171 | } 172 | } 173 | // populate jQuery.cssHooks with the appropriate hook if necessary 174 | if ( propertyHook ) { 175 | $.cssHooks[propertyName] = propertyHook; 176 | } 177 | // we need a unique setter for the animation logic 178 | propertyGet = propertyHook && propertyHook.get || $.css; 179 | 180 | /* 181 | * fn.animate() hooks 182 | */ 183 | $.fx.step.transform = function( fx ) { 184 | var elem = fx.elem, 185 | start = fx.start, 186 | end = fx.end, 187 | split, 188 | pos = fx.pos, 189 | transform, 190 | translate, 191 | rotate, 192 | scale, 193 | skew, 194 | T = false, 195 | M = false, 196 | prop; 197 | translate = rotate = scale = skew = ''; 198 | 199 | // fx.end and fx.start need to be converted to their translate/rotate/scale/skew components 200 | // so that we can interpolate them 201 | if ( !start || typeof start === "string" ) { 202 | // the following block can be commented out with jQuery 1.5.1+, see #7912 203 | if (!start) { 204 | start = propertyGet( elem, supportProperty ); 205 | } 206 | 207 | // force layout only once per animation 208 | if ( supportMatrixFilter ) { 209 | elem.style.zoom = 1; 210 | } 211 | 212 | // if the start computed matrix is in end, we are doing a relative animation 213 | split = end.split(start); 214 | if ( split.length == 2 ) { 215 | // remove the start computed matrix to make animations more accurate 216 | end = split.join(''); 217 | fx.origin = start; 218 | start = 'none'; 219 | } 220 | 221 | // start is either 'none' or a matrix(...) that has to be parsed 222 | fx.start = start = start == 'none'? 223 | { 224 | translate: [0,0], 225 | rotate: 0, 226 | scale: [1,1], 227 | skew: [0,0] 228 | }: 229 | unmatrix( toArray(start) ); 230 | 231 | // fx.end has to be parsed and decomposed 232 | fx.end = end = ~end.indexOf('matrix')? 233 | // bullet-proof parser 234 | unmatrix(matrix(end)): 235 | // faster and more precise parser 236 | components(end); 237 | 238 | // get rid of properties that do not change 239 | for ( prop in start) { 240 | if ( prop == 'rotate' ? 241 | start[prop] == end[prop]: 242 | start[prop][0] == end[prop][0] && start[prop][1] == end[prop][1] 243 | ) { 244 | delete start[prop]; 245 | } 246 | } 247 | } 248 | 249 | /* 250 | * We want a fast interpolation algorithm. 251 | * This implies avoiding function calls and sacrifying DRY principle: 252 | * - avoid $.each(function(){}) 253 | * - round values using bitewise hacks, see http://jsperf.com/math-round-vs-hack/3 254 | */ 255 | if ( start.translate ) { 256 | // round translate to the closest pixel 257 | translate = ' translate('+ 258 | ((start.translate[0] + (end.translate[0] - start.translate[0]) * pos + .5) | 0) +'px,'+ 259 | ((start.translate[1] + (end.translate[1] - start.translate[1]) * pos + .5) | 0) +'px'+ 260 | ')'; 261 | T = true; 262 | } 263 | if ( start.rotate != undefined ) { 264 | rotate = ' rotate('+ (start.rotate + (end.rotate - start.rotate) * pos) +'rad)'; 265 | M = true; 266 | } 267 | if ( start.scale ) { 268 | scale = ' scale('+ 269 | (start.scale[0] + (end.scale[0] - start.scale[0]) * pos) +','+ 270 | (start.scale[1] + (end.scale[1] - start.scale[1]) * pos) + 271 | ')'; 272 | M = true; 273 | } 274 | if ( start.skew ) { 275 | skew = ' skew('+ 276 | (start.skew[0] + (end.skew[0] - start.skew[0]) * pos) +'rad,'+ 277 | (start.skew[1] + (end.skew[1] - start.skew[1]) * pos) +'rad'+ 278 | ')'; 279 | M = true; 280 | } 281 | 282 | // In case of relative animation, restore the origin computed matrix here. 283 | transform = fx.origin ? 284 | fx.origin + translate + skew + scale + rotate: 285 | translate + rotate + scale + skew; 286 | 287 | propertyHook && propertyHook.set ? 288 | propertyHook.set( elem, transform, {M: M, T: T} ): 289 | elem.style[supportProperty] = transform; 290 | }; 291 | 292 | /* 293 | * Utility functions 294 | */ 295 | 296 | // turns a transform string into its 'matrix(A,B,C,D,X,Y)' form (as an array, though) 297 | function matrix( transform ) { 298 | transform = transform.split(')'); 299 | var 300 | trim = $.trim 301 | // last element of the array is an empty string, get rid of it 302 | , i = transform.length -1 303 | , split, prop, val 304 | , A = 1 305 | , B = 0 306 | , C = 0 307 | , D = 1 308 | , A_, B_, C_, D_ 309 | , tmp1, tmp2 310 | , X = 0 311 | , Y = 0 312 | ; 313 | // Loop through the transform properties, parse and multiply them 314 | while (i--) { 315 | split = transform[i].split('('); 316 | prop = trim(split[0]); 317 | val = split[1]; 318 | A_ = B_ = C_ = D_ = 0; 319 | 320 | switch (prop) { 321 | case 'translateX': 322 | X += parseInt(val, 10); 323 | continue; 324 | 325 | case 'translateY': 326 | Y += parseInt(val, 10); 327 | continue; 328 | 329 | case 'translate': 330 | val = val.split(','); 331 | X += parseInt(val[0], 10); 332 | Y += parseInt(val[1] || 0, 10); 333 | continue; 334 | 335 | case 'rotate': 336 | val = toRadian(val); 337 | A_ = Math.cos(val); 338 | B_ = Math.sin(val); 339 | C_ = -Math.sin(val); 340 | D_ = Math.cos(val); 341 | break; 342 | 343 | case 'scaleX': 344 | A_ = val; 345 | D_ = 1; 346 | break; 347 | 348 | case 'scaleY': 349 | A_ = 1; 350 | D_ = val; 351 | break; 352 | 353 | case 'scale': 354 | val = val.split(','); 355 | A_ = val[0]; 356 | D_ = val.length>1 ? val[1] : val[0]; 357 | break; 358 | 359 | case 'skewX': 360 | A_ = D_ = 1; 361 | C_ = Math.tan(toRadian(val)); 362 | break; 363 | 364 | case 'skewY': 365 | A_ = D_ = 1; 366 | B_ = Math.tan(toRadian(val)); 367 | break; 368 | 369 | case 'skew': 370 | A_ = D_ = 1; 371 | val = val.split(','); 372 | C_ = Math.tan(toRadian(val[0])); 373 | B_ = Math.tan(toRadian(val[1] || 0)); 374 | break; 375 | 376 | case 'matrix': 377 | val = val.split(','); 378 | A_ = +val[0]; 379 | B_ = +val[1]; 380 | C_ = +val[2]; 381 | D_ = +val[3]; 382 | X += parseInt(val[4], 10); 383 | Y += parseInt(val[5], 10); 384 | } 385 | // Matrix product 386 | tmp1 = A * A_ + B * C_; 387 | B = A * B_ + B * D_; 388 | tmp2 = C * A_ + D * C_; 389 | D = C * B_ + D * D_; 390 | A = tmp1; 391 | C = tmp2; 392 | } 393 | return [A,B,C,D,X,Y]; 394 | } 395 | 396 | // turns a matrix into its rotate, scale and skew components 397 | // algorithm from http://hg.mozilla.org/mozilla-central/file/7cb3e9795d04/layout/style/nsStyleAnimation.cpp 398 | function unmatrix(matrix) { 399 | var 400 | scaleX 401 | , scaleY 402 | , skew 403 | , A = matrix[0] 404 | , B = matrix[1] 405 | , C = matrix[2] 406 | , D = matrix[3] 407 | ; 408 | 409 | // Make sure matrix is not singular 410 | if ( A * D - B * C ) { 411 | // step (3) 412 | scaleX = Math.sqrt( A * A + B * B ); 413 | A /= scaleX; 414 | B /= scaleX; 415 | // step (4) 416 | skew = A * C + B * D; 417 | C -= A * skew; 418 | D -= B * skew; 419 | // step (5) 420 | scaleY = Math.sqrt( C * C + D * D ); 421 | C /= scaleY; 422 | D /= scaleY; 423 | skew /= scaleY; 424 | // step (6) 425 | if ( A * D < B * C ) { 426 | //scaleY = -scaleY; 427 | //skew = -skew; 428 | A = -A; 429 | B = -B; 430 | skew = -skew; 431 | scaleX = -scaleX; 432 | } 433 | 434 | // matrix is singular and cannot be interpolated 435 | } else { 436 | rotate = scaleX = scaleY = skew = 0; 437 | } 438 | 439 | return { 440 | translate: [+matrix[4], +matrix[5]], 441 | rotate: Math.atan2(B, A), 442 | scale: [scaleX, scaleY], 443 | skew: [skew, 0] 444 | } 445 | } 446 | 447 | // parse tranform components of a transform string not containing 'matrix(...)' 448 | function components( transform ) { 449 | // split the != transforms 450 | transform = transform.split(')'); 451 | 452 | var translate = [0,0], 453 | rotate = 0, 454 | scale = [1,1], 455 | skew = [0,0], 456 | i = transform.length -1, 457 | trim = $.trim, 458 | split, name, value; 459 | 460 | // add components 461 | while ( i-- ) { 462 | split = transform[i].split('('); 463 | name = trim(split[0]); 464 | value = split[1]; 465 | 466 | if (name == 'translateX') { 467 | translate[0] += parseInt(value, 10); 468 | 469 | } else if (name == 'translateY') { 470 | translate[1] += parseInt(value, 10); 471 | 472 | } else if (name == 'translate') { 473 | value = value.split(','); 474 | translate[0] += parseInt(value[0], 10); 475 | translate[1] += parseInt(value[1] || 0, 10); 476 | 477 | } else if (name == 'rotate') { 478 | rotate += toRadian(value); 479 | 480 | } else if (name == 'scaleX') { 481 | scale[0] *= value; 482 | 483 | } else if (name == 'scaleY') { 484 | scale[1] *= value; 485 | 486 | } else if (name == 'scale') { 487 | value = value.split(','); 488 | scale[0] *= value[0]; 489 | scale[1] *= (value.length>1? value[1] : value[0]); 490 | 491 | } else if (name == 'skewX') { 492 | skew[0] += toRadian(value); 493 | 494 | } else if (name == 'skewY') { 495 | skew[1] += toRadian(value); 496 | 497 | } else if (name == 'skew') { 498 | value = value.split(','); 499 | skew[0] += toRadian(value[0]); 500 | skew[1] += toRadian(value[1] || '0'); 501 | } 502 | } 503 | 504 | return { 505 | translate: translate, 506 | rotate: rotate, 507 | scale: scale, 508 | skew: skew 509 | }; 510 | } 511 | 512 | // converts an angle string in any unit to a radian Float 513 | function toRadian(value) { 514 | return ~value.indexOf('deg') ? 515 | parseInt(value,10) * (Math.PI * 2 / 360): 516 | ~value.indexOf('grad') ? 517 | parseInt(value,10) * (Math.PI/200): 518 | parseFloat(value); 519 | } 520 | 521 | // Converts 'matrix(A,B,C,D,X,Y)' to [A,B,C,D,X,Y] 522 | function toArray(matrix) { 523 | // Fremove the unit of X and Y for Firefox 524 | matrix = /\(([^,]*),([^,]*),([^,]*),([^,]*),([^,p]*)(?:px)?,([^)p]*)(?:px)?/.exec(matrix); 525 | return [matrix[1], matrix[2], matrix[3], matrix[4], matrix[5], matrix[6]]; 526 | } 527 | 528 | $.transform = { 529 | centerOrigin: 'margin' 530 | }; 531 | 532 | })( jQuery ); -------------------------------------------------------------------------------- /tests/qunit/qunit.js: -------------------------------------------------------------------------------- 1 | /* 2 | * QUnit - A JavaScript Unit Testing Framework 3 | * 4 | * http://docs.jquery.com/QUnit 5 | * 6 | * Copyright (c) 2009 John Resig, Jörn Zaefferer 7 | * Dual licensed under the MIT (MIT-LICENSE.txt) 8 | * and GPL (GPL-LICENSE.txt) licenses. 9 | */ 10 | 11 | (function(window) { 12 | 13 | var QUnit = { 14 | 15 | // call on start of module test to prepend name to all tests 16 | module: function(name, testEnvironment) { 17 | config.currentModule = name; 18 | 19 | synchronize(function() { 20 | if ( config.currentModule ) { 21 | QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all ); 22 | } 23 | 24 | config.currentModule = name; 25 | config.moduleTestEnvironment = testEnvironment; 26 | config.moduleStats = { all: 0, bad: 0 }; 27 | 28 | QUnit.moduleStart( name, testEnvironment ); 29 | }); 30 | }, 31 | 32 | asyncTest: function(testName, expected, callback) { 33 | if ( arguments.length === 2 ) { 34 | callback = expected; 35 | expected = 0; 36 | } 37 | 38 | QUnit.test(testName, expected, callback, true); 39 | }, 40 | 41 | test: function(testName, expected, callback, async) { 42 | var name = '' + testName + '', testEnvironment, testEnvironmentArg; 43 | 44 | if ( arguments.length === 2 ) { 45 | callback = expected; 46 | expected = null; 47 | } 48 | // is 2nd argument a testEnvironment? 49 | if ( expected && typeof expected === 'object') { 50 | testEnvironmentArg = expected; 51 | expected = null; 52 | } 53 | 54 | if ( config.currentModule ) { 55 | name = '' + config.currentModule + ": " + name; 56 | } 57 | 58 | if ( !validTest(config.currentModule + ": " + testName) ) { 59 | return; 60 | } 61 | 62 | synchronize(function() { 63 | 64 | testEnvironment = extend({ 65 | setup: function() {}, 66 | teardown: function() {} 67 | }, config.moduleTestEnvironment); 68 | if (testEnvironmentArg) { 69 | extend(testEnvironment,testEnvironmentArg); 70 | } 71 | 72 | QUnit.testStart( testName, testEnvironment ); 73 | 74 | // allow utility functions to access the current test environment 75 | QUnit.current_testEnvironment = testEnvironment; 76 | 77 | config.assertions = []; 78 | config.expected = expected; 79 | 80 | var tests = id("qunit-tests"); 81 | if (tests) { 82 | var b = document.createElement("strong"); 83 | b.innerHTML = "Running " + name; 84 | var li = document.createElement("li"); 85 | li.appendChild( b ); 86 | li.id = "current-test-output"; 87 | tests.appendChild( li ) 88 | } 89 | 90 | try { 91 | if ( !config.pollution ) { 92 | saveGlobal(); 93 | } 94 | 95 | testEnvironment.setup.call(testEnvironment); 96 | } catch(e) { 97 | QUnit.ok( false, "Setup failed on " + name + ": " + e.message ); 98 | } 99 | }); 100 | 101 | synchronize(function() { 102 | if ( async ) { 103 | QUnit.stop(); 104 | } 105 | 106 | try { 107 | callback.call(testEnvironment); 108 | } catch(e) { 109 | fail("Test " + name + " died, exception and test follows", e, callback); 110 | QUnit.ok( false, "Died on test #" + (config.assertions.length + 1) + ": " + e.message ); 111 | // else next test will carry the responsibility 112 | saveGlobal(); 113 | 114 | // Restart the tests if they're blocking 115 | if ( config.blocking ) { 116 | start(); 117 | } 118 | } 119 | }); 120 | 121 | synchronize(function() { 122 | try { 123 | checkPollution(); 124 | testEnvironment.teardown.call(testEnvironment); 125 | } catch(e) { 126 | QUnit.ok( false, "Teardown failed on " + name + ": " + e.message ); 127 | } 128 | }); 129 | 130 | synchronize(function() { 131 | try { 132 | QUnit.reset(); 133 | } catch(e) { 134 | fail("reset() failed, following Test " + name + ", exception and reset fn follows", e, reset); 135 | } 136 | 137 | if ( config.expected && config.expected != config.assertions.length ) { 138 | QUnit.ok( false, "Expected " + config.expected + " assertions, but " + config.assertions.length + " were run" ); 139 | } 140 | 141 | var good = 0, bad = 0, 142 | tests = id("qunit-tests"); 143 | 144 | config.stats.all += config.assertions.length; 145 | config.moduleStats.all += config.assertions.length; 146 | 147 | if ( tests ) { 148 | var ol = document.createElement("ol"); 149 | 150 | for ( var i = 0; i < config.assertions.length; i++ ) { 151 | var assertion = config.assertions[i]; 152 | 153 | var li = document.createElement("li"); 154 | li.className = assertion.result ? "pass" : "fail"; 155 | li.innerHTML = assertion.message || "(no message)"; 156 | ol.appendChild( li ); 157 | 158 | if ( assertion.result ) { 159 | good++; 160 | } else { 161 | bad++; 162 | config.stats.bad++; 163 | config.moduleStats.bad++; 164 | } 165 | } 166 | if (bad == 0) { 167 | ol.style.display = "none"; 168 | } 169 | 170 | var b = document.createElement("strong"); 171 | b.innerHTML = name + " (" + bad + ", " + good + ", " + config.assertions.length + ")"; 172 | 173 | addEvent(b, "click", function() { 174 | var next = b.nextSibling, display = next.style.display; 175 | next.style.display = display === "none" ? "block" : "none"; 176 | }); 177 | 178 | addEvent(b, "dblclick", function(e) { 179 | var target = e && e.target ? e.target : window.event.srcElement; 180 | if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { 181 | target = target.parentNode; 182 | } 183 | if ( window.location && target.nodeName.toLowerCase() === "strong" ) { 184 | window.location.search = "?" + encodeURIComponent(getText([target]).replace(/\(.+\)$/, "").replace(/(^\s*|\s*$)/g, "")); 185 | } 186 | }); 187 | 188 | var li = id("current-test-output"); 189 | li.id = ""; 190 | li.className = bad ? "fail" : "pass"; 191 | li.removeChild( li.firstChild ); 192 | li.appendChild( b ); 193 | li.appendChild( ol ); 194 | 195 | if ( bad ) { 196 | var toolbar = id("qunit-testrunner-toolbar"); 197 | if ( toolbar ) { 198 | toolbar.style.display = "block"; 199 | id("qunit-filter-pass").disabled = null; 200 | id("qunit-filter-missing").disabled = null; 201 | } 202 | } 203 | 204 | } else { 205 | for ( var i = 0; i < config.assertions.length; i++ ) { 206 | if ( !config.assertions[i].result ) { 207 | bad++; 208 | config.stats.bad++; 209 | config.moduleStats.bad++; 210 | } 211 | } 212 | } 213 | 214 | QUnit.testDone( testName, bad, config.assertions.length ); 215 | 216 | if ( !window.setTimeout && !config.queue.length ) { 217 | done(); 218 | } 219 | }); 220 | 221 | if ( window.setTimeout && !config.doneTimer ) { 222 | config.doneTimer = window.setTimeout(function(){ 223 | if ( !config.queue.length ) { 224 | done(); 225 | } else { 226 | synchronize( done ); 227 | } 228 | }, 13); 229 | } 230 | }, 231 | 232 | /** 233 | * Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. 234 | */ 235 | expect: function(asserts) { 236 | config.expected = asserts; 237 | }, 238 | 239 | /** 240 | * Asserts true. 241 | * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); 242 | */ 243 | ok: function(a, msg) { 244 | msg = escapeHtml(msg); 245 | QUnit.log(a, msg); 246 | 247 | config.assertions.push({ 248 | result: !!a, 249 | message: msg 250 | }); 251 | }, 252 | 253 | /** 254 | * Checks that the first two arguments are equal, with an optional message. 255 | * Prints out both actual and expected values. 256 | * 257 | * Prefered to ok( actual == expected, message ) 258 | * 259 | * @example equal( format("Received {0} bytes.", 2), "Received 2 bytes." ); 260 | * 261 | * @param Object actual 262 | * @param Object expected 263 | * @param String message (optional) 264 | */ 265 | equal: function(actual, expected, message) { 266 | push(expected == actual, actual, expected, message); 267 | }, 268 | 269 | notEqual: function(actual, expected, message) { 270 | push(expected != actual, actual, expected, message); 271 | }, 272 | 273 | deepEqual: function(actual, expected, message) { 274 | push(QUnit.equiv(actual, expected), actual, expected, message); 275 | }, 276 | 277 | notDeepEqual: function(actual, expected, message) { 278 | push(!QUnit.equiv(actual, expected), actual, expected, message); 279 | }, 280 | 281 | strictEqual: function(actual, expected, message) { 282 | push(expected === actual, actual, expected, message); 283 | }, 284 | 285 | notStrictEqual: function(actual, expected, message) { 286 | push(expected !== actual, actual, expected, message); 287 | }, 288 | 289 | raises: function(fn, message) { 290 | try { 291 | fn(); 292 | ok( false, message ); 293 | } 294 | catch (e) { 295 | ok( true, message ); 296 | } 297 | }, 298 | 299 | start: function() { 300 | // A slight delay, to avoid any current callbacks 301 | if ( window.setTimeout ) { 302 | window.setTimeout(function() { 303 | if ( config.timeout ) { 304 | clearTimeout(config.timeout); 305 | } 306 | 307 | config.blocking = false; 308 | process(); 309 | }, 13); 310 | } else { 311 | config.blocking = false; 312 | process(); 313 | } 314 | }, 315 | 316 | stop: function(timeout) { 317 | config.blocking = true; 318 | 319 | if ( timeout && window.setTimeout ) { 320 | config.timeout = window.setTimeout(function() { 321 | QUnit.ok( false, "Test timed out" ); 322 | QUnit.start(); 323 | }, timeout); 324 | } 325 | } 326 | 327 | }; 328 | 329 | // Backwards compatibility, deprecated 330 | QUnit.equals = QUnit.equal; 331 | QUnit.same = QUnit.deepEqual; 332 | 333 | // Maintain internal state 334 | var config = { 335 | // The queue of tests to run 336 | queue: [], 337 | 338 | // block until document ready 339 | blocking: true 340 | }; 341 | 342 | // Load paramaters 343 | (function() { 344 | var location = window.location || { search: "", protocol: "file:" }, 345 | GETParams = location.search.slice(1).split('&'); 346 | 347 | for ( var i = 0; i < GETParams.length; i++ ) { 348 | GETParams[i] = decodeURIComponent( GETParams[i] ); 349 | if ( GETParams[i] === "noglobals" ) { 350 | GETParams.splice( i, 1 ); 351 | i--; 352 | config.noglobals = true; 353 | } else if ( GETParams[i].search('=') > -1 ) { 354 | GETParams.splice( i, 1 ); 355 | i--; 356 | } 357 | } 358 | 359 | // restrict modules/tests by get parameters 360 | config.filters = GETParams; 361 | 362 | // Figure out if we're running the tests from a server or not 363 | QUnit.isLocal = !!(location.protocol === 'file:'); 364 | })(); 365 | 366 | // Expose the API as global variables, unless an 'exports' 367 | // object exists, in that case we assume we're in CommonJS 368 | if ( typeof exports === "undefined" || typeof require === "undefined" ) { 369 | extend(window, QUnit); 370 | window.QUnit = QUnit; 371 | } else { 372 | extend(exports, QUnit); 373 | exports.QUnit = QUnit; 374 | } 375 | 376 | // define these after exposing globals to keep them in these QUnit namespace only 377 | extend(QUnit, { 378 | config: config, 379 | 380 | // Initialize the configuration options 381 | init: function() { 382 | extend(config, { 383 | stats: { all: 0, bad: 0 }, 384 | moduleStats: { all: 0, bad: 0 }, 385 | started: +new Date, 386 | updateRate: 1000, 387 | blocking: false, 388 | autostart: true, 389 | autorun: false, 390 | assertions: [], 391 | filters: [], 392 | queue: [] 393 | }); 394 | 395 | var tests = id("qunit-tests"), 396 | banner = id("qunit-banner"), 397 | result = id("qunit-testresult"); 398 | 399 | if ( tests ) { 400 | tests.innerHTML = ""; 401 | } 402 | 403 | if ( banner ) { 404 | banner.className = ""; 405 | } 406 | 407 | if ( result ) { 408 | result.parentNode.removeChild( result ); 409 | } 410 | }, 411 | 412 | /** 413 | * Resets the test setup. Useful for tests that modify the DOM. 414 | */ 415 | reset: function() { 416 | if ( window.jQuery ) { 417 | jQuery("#main, #qunit-fixture").html( config.fixture ); 418 | } 419 | }, 420 | 421 | /** 422 | * Trigger an event on an element. 423 | * 424 | * @example triggerEvent( document.body, "click" ); 425 | * 426 | * @param DOMElement elem 427 | * @param String type 428 | */ 429 | triggerEvent: function( elem, type, event ) { 430 | if ( document.createEvent ) { 431 | event = document.createEvent("MouseEvents"); 432 | event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, 433 | 0, 0, 0, 0, 0, false, false, false, false, 0, null); 434 | elem.dispatchEvent( event ); 435 | 436 | } else if ( elem.fireEvent ) { 437 | elem.fireEvent("on"+type); 438 | } 439 | }, 440 | 441 | // Safe object type checking 442 | is: function( type, obj ) { 443 | return QUnit.objectType( obj ) == type; 444 | }, 445 | 446 | objectType: function( obj ) { 447 | if (typeof obj === "undefined") { 448 | return "undefined"; 449 | 450 | // consider: typeof null === object 451 | } 452 | if (obj === null) { 453 | return "null"; 454 | } 455 | 456 | var type = Object.prototype.toString.call( obj ) 457 | .match(/^\[object\s(.*)\]$/)[1] || ''; 458 | 459 | switch (type) { 460 | case 'Number': 461 | if (isNaN(obj)) { 462 | return "nan"; 463 | } else { 464 | return "number"; 465 | } 466 | case 'String': 467 | case 'Boolean': 468 | case 'Array': 469 | case 'Date': 470 | case 'RegExp': 471 | case 'Function': 472 | return type.toLowerCase(); 473 | } 474 | if (typeof obj === "object") { 475 | return "object"; 476 | } 477 | return undefined; 478 | }, 479 | 480 | // Logging callbacks 481 | begin: function() {}, 482 | done: function(failures, total) {}, 483 | log: function(result, message) {}, 484 | testStart: function(name, testEnvironment) {}, 485 | testDone: function(name, failures, total) {}, 486 | moduleStart: function(name, testEnvironment) {}, 487 | moduleDone: function(name, failures, total) {} 488 | }); 489 | 490 | if ( typeof document === "undefined" || document.readyState === "complete" ) { 491 | config.autorun = true; 492 | } 493 | 494 | addEvent(window, "load", function() { 495 | QUnit.begin(); 496 | 497 | // Initialize the config, saving the execution queue 498 | var oldconfig = extend({}, config); 499 | QUnit.init(); 500 | extend(config, oldconfig); 501 | 502 | config.blocking = false; 503 | 504 | var userAgent = id("qunit-userAgent"); 505 | if ( userAgent ) { 506 | userAgent.innerHTML = navigator.userAgent; 507 | } 508 | 509 | var toolbar = id("qunit-testrunner-toolbar"); 510 | if ( toolbar ) { 511 | toolbar.style.display = "none"; 512 | 513 | var filter = document.createElement("input"); 514 | filter.type = "checkbox"; 515 | filter.id = "qunit-filter-pass"; 516 | filter.disabled = true; 517 | addEvent( filter, "click", function() { 518 | var li = document.getElementsByTagName("li"); 519 | for ( var i = 0; i < li.length; i++ ) { 520 | if ( li[i].className.indexOf("pass") > -1 ) { 521 | li[i].style.display = filter.checked ? "none" : ""; 522 | } 523 | } 524 | }); 525 | toolbar.appendChild( filter ); 526 | 527 | var label = document.createElement("label"); 528 | label.setAttribute("for", "qunit-filter-pass"); 529 | label.innerHTML = "Hide passed tests"; 530 | toolbar.appendChild( label ); 531 | 532 | var missing = document.createElement("input"); 533 | missing.type = "checkbox"; 534 | missing.id = "qunit-filter-missing"; 535 | missing.disabled = true; 536 | addEvent( missing, "click", function() { 537 | var li = document.getElementsByTagName("li"); 538 | for ( var i = 0; i < li.length; i++ ) { 539 | if ( li[i].className.indexOf("fail") > -1 && li[i].innerHTML.indexOf('missing test - untested code is broken code') > - 1 ) { 540 | li[i].parentNode.parentNode.style.display = missing.checked ? "none" : "block"; 541 | } 542 | } 543 | }); 544 | toolbar.appendChild( missing ); 545 | 546 | label = document.createElement("label"); 547 | label.setAttribute("for", "qunit-filter-missing"); 548 | label.innerHTML = "Hide missing tests (untested code is broken code)"; 549 | toolbar.appendChild( label ); 550 | } 551 | 552 | var main = id('main') || id('qunit-fixture'); 553 | if ( main ) { 554 | config.fixture = main.innerHTML; 555 | } 556 | 557 | if (config.autostart) { 558 | QUnit.start(); 559 | } 560 | }); 561 | 562 | function done() { 563 | if ( config.doneTimer && window.clearTimeout ) { 564 | window.clearTimeout( config.doneTimer ); 565 | config.doneTimer = null; 566 | } 567 | 568 | if ( config.queue.length ) { 569 | config.doneTimer = window.setTimeout(function(){ 570 | if ( !config.queue.length ) { 571 | done(); 572 | } else { 573 | synchronize( done ); 574 | } 575 | }, 13); 576 | 577 | return; 578 | } 579 | 580 | config.autorun = true; 581 | 582 | // Log the last module results 583 | if ( config.currentModule ) { 584 | QUnit.moduleDone( config.currentModule, config.moduleStats.bad, config.moduleStats.all ); 585 | } 586 | 587 | var banner = id("qunit-banner"), 588 | tests = id("qunit-tests"), 589 | html = ['Tests completed in ', 590 | +new Date - config.started, ' milliseconds.
    ', 591 | '', config.stats.all - config.stats.bad, ' tests of ', config.stats.all, ' passed, ', config.stats.bad,' failed.'].join(''); 592 | 593 | if ( banner ) { 594 | banner.className = (config.stats.bad ? "qunit-fail" : "qunit-pass"); 595 | } 596 | 597 | if ( tests ) { 598 | var result = id("qunit-testresult"); 599 | 600 | if ( !result ) { 601 | result = document.createElement("p"); 602 | result.id = "qunit-testresult"; 603 | result.className = "result"; 604 | tests.parentNode.insertBefore( result, tests.nextSibling ); 605 | } 606 | 607 | result.innerHTML = html; 608 | } 609 | 610 | QUnit.done( config.stats.bad, config.stats.all ); 611 | } 612 | 613 | function validTest( name ) { 614 | var i = config.filters.length, 615 | run = false; 616 | 617 | if ( !i ) { 618 | return true; 619 | } 620 | 621 | while ( i-- ) { 622 | var filter = config.filters[i], 623 | not = filter.charAt(0) == '!'; 624 | 625 | if ( not ) { 626 | filter = filter.slice(1); 627 | } 628 | 629 | if ( name.indexOf(filter) !== -1 ) { 630 | return !not; 631 | } 632 | 633 | if ( not ) { 634 | run = true; 635 | } 636 | } 637 | 638 | return run; 639 | } 640 | 641 | function escapeHtml(s) { 642 | s = s === null ? "" : s + ""; 643 | return s.replace(/[\&"<>\\]/g, function(s) { 644 | switch(s) { 645 | case "&": return "&"; 646 | case "\\": return "\\\\"; 647 | case '"': return '\"'; 648 | case "<": return "<"; 649 | case ">": return ">"; 650 | default: return s; 651 | } 652 | }); 653 | } 654 | 655 | function push(result, actual, expected, message) { 656 | message = escapeHtml(message) || (result ? "okay" : "failed"); 657 | message = '' + message + ""; 658 | expected = escapeHtml(QUnit.jsDump.parse(expected)); 659 | actual = escapeHtml(QUnit.jsDump.parse(actual)); 660 | var output = message + ', expected: ' + expected + ''; 661 | if (actual != expected) { 662 | output += ' result: ' + actual + ', diff: ' + QUnit.diff(expected, actual); 663 | } 664 | 665 | // can't use ok, as that would double-escape messages 666 | QUnit.log(result, output); 667 | config.assertions.push({ 668 | result: !!result, 669 | message: output 670 | }); 671 | } 672 | 673 | function synchronize( callback ) { 674 | config.queue.push( callback ); 675 | 676 | if ( config.autorun && !config.blocking ) { 677 | process(); 678 | } 679 | } 680 | 681 | function process() { 682 | var start = (new Date()).getTime(); 683 | 684 | while ( config.queue.length && !config.blocking ) { 685 | if ( config.updateRate <= 0 || (((new Date()).getTime() - start) < config.updateRate) ) { 686 | config.queue.shift()(); 687 | 688 | } else { 689 | setTimeout( process, 13 ); 690 | break; 691 | } 692 | } 693 | } 694 | 695 | function saveGlobal() { 696 | config.pollution = []; 697 | 698 | if ( config.noglobals ) { 699 | for ( var key in window ) { 700 | config.pollution.push( key ); 701 | } 702 | } 703 | } 704 | 705 | function checkPollution( name ) { 706 | var old = config.pollution; 707 | saveGlobal(); 708 | 709 | var newGlobals = diff( old, config.pollution ); 710 | if ( newGlobals.length > 0 ) { 711 | ok( false, "Introduced global variable(s): " + newGlobals.join(", ") ); 712 | config.expected++; 713 | } 714 | 715 | var deletedGlobals = diff( config.pollution, old ); 716 | if ( deletedGlobals.length > 0 ) { 717 | ok( false, "Deleted global variable(s): " + deletedGlobals.join(", ") ); 718 | config.expected++; 719 | } 720 | } 721 | 722 | // returns a new Array with the elements that are in a but not in b 723 | function diff( a, b ) { 724 | var result = a.slice(); 725 | for ( var i = 0; i < result.length; i++ ) { 726 | for ( var j = 0; j < b.length; j++ ) { 727 | if ( result[i] === b[j] ) { 728 | result.splice(i, 1); 729 | i--; 730 | break; 731 | } 732 | } 733 | } 734 | return result; 735 | } 736 | 737 | function fail(message, exception, callback) { 738 | if ( typeof console !== "undefined" && console.error && console.warn ) { 739 | console.error(message); 740 | console.error(exception); 741 | console.warn(callback.toString()); 742 | 743 | } else if ( window.opera && opera.postError ) { 744 | opera.postError(message, exception, callback.toString); 745 | } 746 | } 747 | 748 | function extend(a, b) { 749 | for ( var prop in b ) { 750 | a[prop] = b[prop]; 751 | } 752 | 753 | return a; 754 | } 755 | 756 | function addEvent(elem, type, fn) { 757 | if ( elem.addEventListener ) { 758 | elem.addEventListener( type, fn, false ); 759 | } else if ( elem.attachEvent ) { 760 | elem.attachEvent( "on" + type, fn ); 761 | } else { 762 | fn(); 763 | } 764 | } 765 | 766 | function id(name) { 767 | return !!(typeof document !== "undefined" && document && document.getElementById) && 768 | document.getElementById( name ); 769 | } 770 | 771 | // Test for equality any JavaScript type. 772 | // Discussions and reference: http://philrathe.com/articles/equiv 773 | // Test suites: http://philrathe.com/tests/equiv 774 | // Author: Philippe Rathé 775 | QUnit.equiv = function () { 776 | 777 | var innerEquiv; // the real equiv function 778 | var callers = []; // stack to decide between skip/abort functions 779 | var parents = []; // stack to avoiding loops from circular referencing 780 | 781 | // Call the o related callback with the given arguments. 782 | function bindCallbacks(o, callbacks, args) { 783 | var prop = QUnit.objectType(o); 784 | if (prop) { 785 | if (QUnit.objectType(callbacks[prop]) === "function") { 786 | return callbacks[prop].apply(callbacks, args); 787 | } else { 788 | return callbacks[prop]; // or undefined 789 | } 790 | } 791 | } 792 | 793 | var callbacks = function () { 794 | 795 | // for string, boolean, number and null 796 | function useStrictEquality(b, a) { 797 | if (b instanceof a.constructor || a instanceof b.constructor) { 798 | // to catch short annotaion VS 'new' annotation of a declaration 799 | // e.g. var i = 1; 800 | // var j = new Number(1); 801 | return a == b; 802 | } else { 803 | return a === b; 804 | } 805 | } 806 | 807 | return { 808 | "string": useStrictEquality, 809 | "boolean": useStrictEquality, 810 | "number": useStrictEquality, 811 | "null": useStrictEquality, 812 | "undefined": useStrictEquality, 813 | 814 | "nan": function (b) { 815 | return isNaN(b); 816 | }, 817 | 818 | "date": function (b, a) { 819 | return QUnit.objectType(b) === "date" && a.valueOf() === b.valueOf(); 820 | }, 821 | 822 | "regexp": function (b, a) { 823 | return QUnit.objectType(b) === "regexp" && 824 | a.source === b.source && // the regex itself 825 | a.global === b.global && // and its modifers (gmi) ... 826 | a.ignoreCase === b.ignoreCase && 827 | a.multiline === b.multiline; 828 | }, 829 | 830 | // - skip when the property is a method of an instance (OOP) 831 | // - abort otherwise, 832 | // initial === would have catch identical references anyway 833 | "function": function () { 834 | var caller = callers[callers.length - 1]; 835 | return caller !== Object && 836 | typeof caller !== "undefined"; 837 | }, 838 | 839 | "array": function (b, a) { 840 | var i, j, loop; 841 | var len; 842 | 843 | // b could be an object literal here 844 | if ( ! (QUnit.objectType(b) === "array")) { 845 | return false; 846 | } 847 | 848 | len = a.length; 849 | if (len !== b.length) { // safe and faster 850 | return false; 851 | } 852 | 853 | //track reference to avoid circular references 854 | parents.push(a); 855 | for (i = 0; i < len; i++) { 856 | loop = false; 857 | for(j=0;j= 0) { 1002 | type = "array"; 1003 | } else { 1004 | type = typeof obj; 1005 | } 1006 | return type; 1007 | }, 1008 | separator:function() { 1009 | return this.multiline ? this.HTML ? '
    ' : '\n' : this.HTML ? ' ' : ' '; 1010 | }, 1011 | indent:function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing 1012 | if ( !this.multiline ) 1013 | return ''; 1014 | var chr = this.indentChar; 1015 | if ( this.HTML ) 1016 | chr = chr.replace(/\t/g,' ').replace(/ /g,' '); 1017 | return Array( this._depth_ + (extra||0) ).join(chr); 1018 | }, 1019 | up:function( a ) { 1020 | this._depth_ += a || 1; 1021 | }, 1022 | down:function( a ) { 1023 | this._depth_ -= a || 1; 1024 | }, 1025 | setParser:function( name, parser ) { 1026 | this.parsers[name] = parser; 1027 | }, 1028 | // The next 3 are exposed so you can use them 1029 | quote:quote, 1030 | literal:literal, 1031 | join:join, 1032 | // 1033 | _depth_: 1, 1034 | // This is the list of parsers, to modify them, use jsDump.setParser 1035 | parsers:{ 1036 | window: '[Window]', 1037 | document: '[Document]', 1038 | error:'[ERROR]', //when no parser is found, shouldn't happen 1039 | unknown: '[Unknown]', 1040 | 'null':'null', 1041 | undefined:'undefined', 1042 | 'function':function( fn ) { 1043 | var ret = 'function', 1044 | name = 'name' in fn ? fn.name : (reName.exec(fn)||[])[1];//functions never have name in IE 1045 | if ( name ) 1046 | ret += ' ' + name; 1047 | ret += '('; 1048 | 1049 | ret = [ ret, this.parse( fn, 'functionArgs' ), '){'].join(''); 1050 | return join( ret, this.parse(fn,'functionCode'), '}' ); 1051 | }, 1052 | array: array, 1053 | nodelist: array, 1054 | arguments: array, 1055 | object:function( map ) { 1056 | var ret = [ ]; 1057 | this.up(); 1058 | for ( var key in map ) 1059 | ret.push( this.parse(key,'key') + ': ' + this.parse(map[key]) ); 1060 | this.down(); 1061 | return join( '{', ret, '}' ); 1062 | }, 1063 | node:function( node ) { 1064 | var open = this.HTML ? '<' : '<', 1065 | close = this.HTML ? '>' : '>'; 1066 | 1067 | var tag = node.nodeName.toLowerCase(), 1068 | ret = open + tag; 1069 | 1070 | for ( var a in this.DOMAttrs ) { 1071 | var val = node[this.DOMAttrs[a]]; 1072 | if ( val ) 1073 | ret += ' ' + a + '=' + this.parse( val, 'attribute' ); 1074 | } 1075 | return ret + close + open + '/' + tag + close; 1076 | }, 1077 | functionArgs:function( fn ) {//function calls it internally, it's the arguments part of the function 1078 | var l = fn.length; 1079 | if ( !l ) return ''; 1080 | 1081 | var args = Array(l); 1082 | while ( l-- ) 1083 | args[l] = String.fromCharCode(97+l);//97 is 'a' 1084 | return ' ' + args.join(', ') + ' '; 1085 | }, 1086 | key:quote, //object calls it internally, the key part of an item in a map 1087 | functionCode:'[code]', //function calls it internally, it's the content of the function 1088 | attribute:quote, //node calls it internally, it's an html attribute value 1089 | string:quote, 1090 | date:quote, 1091 | regexp:literal, //regex 1092 | number:literal, 1093 | 'boolean':literal 1094 | }, 1095 | DOMAttrs:{//attributes to dump from nodes, name=>realName 1096 | id:'id', 1097 | name:'name', 1098 | 'class':'className' 1099 | }, 1100 | HTML:false,//if true, entities are escaped ( <, >, \t, space and \n ) 1101 | indentChar:' ',//indentation unit 1102 | multiline:false //if true, items in a collection, are separated by a \n, else just a space. 1103 | }; 1104 | 1105 | return jsDump; 1106 | })(); 1107 | 1108 | // from Sizzle.js 1109 | function getText( elems ) { 1110 | var ret = "", elem; 1111 | 1112 | for ( var i = 0; elems[i]; i++ ) { 1113 | elem = elems[i]; 1114 | 1115 | // Get the text from text nodes and CDATA nodes 1116 | if ( elem.nodeType === 3 || elem.nodeType === 4 ) { 1117 | ret += elem.nodeValue; 1118 | 1119 | // Traverse everything else, except comment nodes 1120 | } else if ( elem.nodeType !== 8 ) { 1121 | ret += getText( elem.childNodes ); 1122 | } 1123 | } 1124 | 1125 | return ret; 1126 | }; 1127 | 1128 | /* 1129 | * Javascript Diff Algorithm 1130 | * By John Resig (http://ejohn.org/) 1131 | * Modified by Chu Alan "sprite" 1132 | * 1133 | * Released under the MIT license. 1134 | * 1135 | * More Info: 1136 | * http://ejohn.org/projects/javascript-diff-algorithm/ 1137 | * 1138 | * Usage: QUnit.diff(expected, actual) 1139 | * 1140 | * QUnit.diff("the quick brown fox jumped over", "the quick fox jumps over") == "the quick brown fox jumped jumps over" 1141 | */ 1142 | QUnit.diff = (function() { 1143 | function diff(o, n){ 1144 | var ns = new Object(); 1145 | var os = new Object(); 1146 | 1147 | for (var i = 0; i < n.length; i++) { 1148 | if (ns[n[i]] == null) 1149 | ns[n[i]] = { 1150 | rows: new Array(), 1151 | o: null 1152 | }; 1153 | ns[n[i]].rows.push(i); 1154 | } 1155 | 1156 | for (var i = 0; i < o.length; i++) { 1157 | if (os[o[i]] == null) 1158 | os[o[i]] = { 1159 | rows: new Array(), 1160 | n: null 1161 | }; 1162 | os[o[i]].rows.push(i); 1163 | } 1164 | 1165 | for (var i in ns) { 1166 | if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { 1167 | n[ns[i].rows[0]] = { 1168 | text: n[ns[i].rows[0]], 1169 | row: os[i].rows[0] 1170 | }; 1171 | o[os[i].rows[0]] = { 1172 | text: o[os[i].rows[0]], 1173 | row: ns[i].rows[0] 1174 | }; 1175 | } 1176 | } 1177 | 1178 | for (var i = 0; i < n.length - 1; i++) { 1179 | if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && 1180 | n[i + 1] == o[n[i].row + 1]) { 1181 | n[i + 1] = { 1182 | text: n[i + 1], 1183 | row: n[i].row + 1 1184 | }; 1185 | o[n[i].row + 1] = { 1186 | text: o[n[i].row + 1], 1187 | row: i + 1 1188 | }; 1189 | } 1190 | } 1191 | 1192 | for (var i = n.length - 1; i > 0; i--) { 1193 | if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && 1194 | n[i - 1] == o[n[i].row - 1]) { 1195 | n[i - 1] = { 1196 | text: n[i - 1], 1197 | row: n[i].row - 1 1198 | }; 1199 | o[n[i].row - 1] = { 1200 | text: o[n[i].row - 1], 1201 | row: i - 1 1202 | }; 1203 | } 1204 | } 1205 | 1206 | return { 1207 | o: o, 1208 | n: n 1209 | }; 1210 | } 1211 | 1212 | return function(o, n){ 1213 | o = o.replace(/\s+$/, ''); 1214 | n = n.replace(/\s+$/, ''); 1215 | var out = diff(o == "" ? [] : o.split(/\s+/), n == "" ? [] : n.split(/\s+/)); 1216 | 1217 | var str = ""; 1218 | 1219 | var oSpace = o.match(/\s+/g); 1220 | if (oSpace == null) { 1221 | oSpace = [" "]; 1222 | } 1223 | else { 1224 | oSpace.push(" "); 1225 | } 1226 | var nSpace = n.match(/\s+/g); 1227 | if (nSpace == null) { 1228 | nSpace = [" "]; 1229 | } 1230 | else { 1231 | nSpace.push(" "); 1232 | } 1233 | 1234 | if (out.n.length == 0) { 1235 | for (var i = 0; i < out.o.length; i++) { 1236 | str += '' + out.o[i] + oSpace[i] + ""; 1237 | } 1238 | } 1239 | else { 1240 | if (out.n[0].text == null) { 1241 | for (n = 0; n < out.o.length && out.o[n].text == null; n++) { 1242 | str += '' + out.o[n] + oSpace[n] + ""; 1243 | } 1244 | } 1245 | 1246 | for (var i = 0; i < out.n.length; i++) { 1247 | if (out.n[i].text == null) { 1248 | str += '' + out.n[i] + nSpace[i] + ""; 1249 | } 1250 | else { 1251 | var pre = ""; 1252 | 1253 | for (n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++) { 1254 | pre += '' + out.o[n] + oSpace[n] + ""; 1255 | } 1256 | str += " " + out.n[i].text + nSpace[i] + pre; 1257 | } 1258 | } 1259 | } 1260 | 1261 | return str; 1262 | } 1263 | })(); 1264 | 1265 | })(this); 1266 | --------------------------------------------------------------------------------