Skip to content
This repository
Browse code

testing the build

  • Loading branch information...
commit e9d926dfa339f1937f920abd678b0579700aaa18 1 parent 38fdd2b
Grady Kuhnline authored October 06, 2010
12  Rakefile
@@ -18,6 +18,7 @@ version    = File.read( File.join( prefix, 'version.txt' ) ).strip
18 18
 # jQuery files/dirs
19 19
 jq         = File.join( dist_dir, "jquery.transform-#{version}.js" )
20 20
 jq_min     = File.join( dist_dir, "jquery.transform-#{version}.min.js" )
  21
+jq_test    = File.join( dist_dir, "jquery.transform.js" )
21 22
 
22 23
 
23 24
 # Build tools
@@ -31,12 +32,12 @@ verbose(false)
31 32
 task :default => "all"
32 33
 
33 34
 desc "Builds jQuery; Tests with JSLint; Minifies jQuery"
34  
-task :all => [:jquery, :lint, :min] do
  35
+task :all => [:dist, :jquery, :lint, :min] do
35 36
   puts "jQuery build complete."
36 37
 end
37 38
 
38 39
 desc "Builds jQuery Transform: jquery.transform.js (Default task)"
39  
-task :jquery => [jq]
  40
+task :jquery => [jq, jq_test]
40 41
 
41 42
 desc "Builds a minified version of jQuery Transform: jquery.transform.min.js"
42 43
 task :min => jq_min
@@ -46,7 +47,7 @@ task :init => [] do
46 47
 end
47 48
 
48 49
 desc "Removes dist folder"
49  
-task :clean do
  50
+task :dist do
50 51
   puts "Removing Distribution directory: #{dist_dir}..." 
51 52
   rm_rf dist_dir
52 53
 end
@@ -74,6 +75,11 @@ file jq_min => jq do
74 75
   sh "#{minfier} -o \"#{jq_min}\" \"#{jq}\""
75 76
 end
76 77
 
  78
+file jq_test => jq do
  79
+  puts "Building a test version of Transform 3d..."
  80
+  cp jq, jq_test
  81
+end
  82
+
77 83
 def cat( files )
78 84
   files.map do |file|
79 85
     File.read(file)
1,772  dist/jquery.transform-0.9.0pre.js
... ...
@@ -0,0 +1,1772 @@
  1
+/*!
  2
+ * jQuery 2d Transform v0.9.0pre
  3
+ * http://wiki.github.com/heygrady/transform/
  4
+ *
  5
+ * Copyright 2010, Grady Kuhnline
  6
+ * Dual licensed under the MIT or GPL Version 2 licenses.
  7
+ * http://jquery.org/license
  8
+ * 
  9
+ * Date: Wed Oct 6 23:16:32 2010 -0700
  10
+ */
  11
+///////////////////////////////////////////////////////
  12
+// Transform
  13
+///////////////////////////////////////////////////////
  14
+(function($, window, document, undefined) {
  15
+	/**
  16
+	 * @var Regex identify the matrix filter in IE
  17
+	 */
  18
+	var rmatrix = /progid:DXImageTransform\.Microsoft\.Matrix\(.*?\)/;
  19
+	
  20
+	// Steal some code from Modernizr
  21
+	var m = document.createElement( 'modernizr' ),
  22
+		m_style = m.style;
  23
+		
  24
+	function stripUnits(arg) {
  25
+		return parseFloat(arg);
  26
+	}
  27
+	
  28
+	/**
  29
+	 * Find the prefix that this browser uses
  30
+	 */	
  31
+	function getVendorPrefix() {
  32
+		var property = {
  33
+			transformProperty : '',
  34
+			MozTransform : '-moz-',
  35
+			WebkitTransform : '-webkit-',
  36
+			OTransform : '-o-',
  37
+			msTransform : '-ms-'
  38
+		};
  39
+		for (var p in property) {
  40
+			if (typeof m_style[p] != 'undefined') {
  41
+				return property[p];
  42
+			}
  43
+		}
  44
+		return null;
  45
+	}
  46
+	
  47
+	function supportCssTransforms() {
  48
+		if (typeof(window.Modernizr) !== 'undefined') {
  49
+			return Modernizr.csstransforms;
  50
+		}
  51
+		
  52
+		var props = [ 'transformProperty', 'WebkitTransform', 'MozTransform', 'OTransform', 'msTransform' ];
  53
+		for ( var i in props ) {
  54
+			if ( m_style[ props[i] ] !== undefined  ) {
  55
+				return true;
  56
+			}
  57
+		}
  58
+	}
  59
+		
  60
+	// Capture some basic properties
  61
+	var vendorPrefix			= getVendorPrefix(),
  62
+		transformProperty		= vendorPrefix !== null ? vendorPrefix + 'transform' : false,
  63
+		transformOriginProperty	= vendorPrefix !== null ? vendorPrefix + 'transform-origin' : false;
  64
+	
  65
+	// store support in the jQuery Support object
  66
+	$.support.csstransforms = supportCssTransforms();
  67
+	
  68
+	/**
  69
+	 * Class for creating cross-browser transformations
  70
+	 * @constructor
  71
+	 */
  72
+	$.extend({
  73
+		transform: function(elem) {
  74
+			// Cache the transform object on the element itself
  75
+			elem.transform = this;
  76
+			
  77
+			/**
  78
+			 * The element we're working with
  79
+			 * @var jQueryCollection
  80
+			 */
  81
+			this.$elem = $(elem);
  82
+						
  83
+			/**
  84
+			 * Remember the matrix we're applying to help the safeOuterLength func
  85
+			 */
  86
+			this.applyingMatrix = false;
  87
+			this.matrix = null;
  88
+			
  89
+			/**
  90
+			 * Remember the css height and width to save time
  91
+			 * This is only really used in IE
  92
+			 * @var Number
  93
+			 */
  94
+			this.height = null;
  95
+			this.width = null;
  96
+			this.outerHeight = null;
  97
+			this.outerWidth = null;
  98
+			
  99
+			/**
  100
+			 * We need to know the box-sizing in IE for building the outerHeight and outerWidth
  101
+			 * @var string
  102
+			 */
  103
+			this.boxSizingValue = null;
  104
+			this.boxSizingProperty = null;
  105
+			
  106
+			this.attr = null;
  107
+			this.transformProperty = transformProperty;
  108
+			this.transformOriginProperty = transformOriginProperty;
  109
+		}
  110
+	});
  111
+	
  112
+	$.extend($.transform, {
  113
+		/**
  114
+		 * @var Array list of all valid transform functions
  115
+		 */
  116
+		funcs: ['matrix', 'origin', 'reflect', 'reflectX', 'reflectXY', 'reflectY', 'rotate', 'scale', 'scaleX', 'scaleY', 'skew', 'skewX', 'skewY', 'translate', 'translateX', 'translateY'],
  117
+		
  118
+		rfunc: {
  119
+			/**
  120
+			 * @var Regex identifies functions that require an angle unit
  121
+			 */
  122
+			angle: /^rotate|skew[X|Y]?$/,
  123
+			
  124
+			/**
  125
+			 * @var Regex identifies functions that require a length unit
  126
+			 */
  127
+			length: /^origin|translate[X|Y]?$/,
  128
+			
  129
+			/**
  130
+			 * @var Regex identifies functions that do not require a unit
  131
+			 */
  132
+			scale: /^scale[X|Y]?$/,
  133
+			
  134
+			/**
  135
+			 * @var Regex reflection functions
  136
+			 */
  137
+			reflect: /^reflect(XY|X|Y)?$/
  138
+		}
  139
+	});
  140
+	
  141
+	/**
  142
+	 * Create Transform as a jQuery plugin
  143
+	 * @param Object funcs
  144
+	 * @param Object options
  145
+	 */
  146
+	$.fn.transform = function(funcs, options) {
  147
+		return this.each(function() {
  148
+			var t = this.transform || new $.transform(this);
  149
+			if (funcs) {
  150
+				t.exec(funcs, options);
  151
+			}
  152
+		});
  153
+	};	
  154
+	
  155
+	$.transform.prototype = {
  156
+		/**
  157
+		 * Applies all of the transformations
  158
+		 * @param Object funcs
  159
+		 * @param Object options
  160
+		 * forceMatrix - uses the matrix in all browsers
  161
+		 * preserve - tries to preserve the values from previous runs
  162
+		 */
  163
+		exec: function(funcs, options) {
  164
+			// extend options
  165
+			options = $.extend(true, {
  166
+				forceMatrix: false,
  167
+				preserve: false
  168
+			}, options);
  169
+	
  170
+			// preserve the funcs from the previous run
  171
+			this.attr = null;
  172
+			if (options.preserve) {
  173
+				funcs = $.extend(true, this.getAttrs(true, true), funcs);
  174
+			} else {
  175
+				funcs = $.extend(true, {}, funcs); // copy the object to prevent weirdness
  176
+			}
  177
+			
  178
+			// Record the custom attributes on the element itself (helps out
  179
+			//	the animator)
  180
+			this.setAttrs(funcs);
  181
+			
  182
+			// apply the funcs
  183
+			if ($.support.csstransforms && !options.forceMatrix) {
  184
+				// CSS3 is supported
  185
+				return this.execFuncs(funcs);
  186
+			} else if ($.browser.msie || ($.support.csstransforms && options.forceMatrix)) {
  187
+				// Internet Explorer or Forced matrix
  188
+				return this.execMatrix(funcs);
  189
+			}
  190
+			return false;
  191
+		},
  192
+		
  193
+		/**
  194
+		 * Applies all of the transformations as functions
  195
+		 * @param Object funcs
  196
+		 */
  197
+		execFuncs: function(funcs) {
  198
+			var values = [];
  199
+			
  200
+			// construct a CSS string
  201
+			for (var func in funcs) {
  202
+				// handle origin separately
  203
+				if (func == 'origin') {
  204
+					this[func].apply(this, $.isArray(funcs[func]) ? funcs[func] : [funcs[func]]);
  205
+				} else if ($.inArray(func, $.transform.funcs) != -1) {
  206
+					values.push(this.createTransformFunc(func, funcs[func]));
  207
+				}
  208
+			}
  209
+			this.$elem.css(transformProperty, values.join(' '));
  210
+			return true;
  211
+		},
  212
+		
  213
+		/**
  214
+		 * Applies all of the transformations as a matrix
  215
+		 * @param Object funcs
  216
+		 */
  217
+		execMatrix: function(funcs) {
  218
+			var matrix,
  219
+				tempMatrix,
  220
+				args;
  221
+			
  222
+			for (var func in funcs) {
  223
+				if ($.matrix[func]) {
  224
+					args = $.isArray(funcs[func]) ? funcs[func] : [funcs[func]];
  225
+					
  226
+					// strip the units
  227
+					// TODO: should probably convert the units properly instead of just stripping them
  228
+					args = $.map(args, stripUnits);
  229
+					
  230
+					// TODO: translation and origin should be applied last
  231
+					// TODO: should hold translations until the extreme end
  232
+					tempMatrix = $.matrix[func].apply(this, args);
  233
+					matrix = matrix ? matrix.x(tempMatrix) : tempMatrix;
  234
+				} else if (func == 'origin') {
  235
+					//TODO: this is a dumb way to handle the origin for a matrix
  236
+					args = $.isArray(funcs[func]) ? funcs[func] : [funcs[func]];
  237
+					this[func].apply(this, args);
  238
+				}
  239
+			}
  240
+			
  241
+			// check that we have a matrix
  242
+			// TODO: This will result in a filter being needlessly set in IE
  243
+			matrix = matrix || $.matrix.identity();
  244
+
  245
+			// pull out the relevant values
  246
+			var a = parseFloat(matrix.e(1,1).toFixed(6)),
  247
+				b = parseFloat(matrix.e(2,1).toFixed(6)),
  248
+				c = parseFloat(matrix.e(1,2).toFixed(6)),
  249
+				d = parseFloat(matrix.e(2,2).toFixed(6)),
  250
+				tx = matrix.rows === 3 ? parseFloat(matrix.e(1,3).toFixed(6)) : 0,
  251
+				ty = matrix.rows === 3 ? parseFloat(matrix.e(2,3).toFixed(6)) : 0;
  252
+			
  253
+			//apply the transform to the element
  254
+			if ($.support.csstransforms && vendorPrefix === '-moz-') {
  255
+				// -moz-
  256
+				this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + 'px, ' + ty + 'px)');
  257
+			} else if ($.support.csstransforms) {
  258
+				// -webkit, -o-, w3c
  259
+				// NOTE: WebKit and Opera don't allow units on the translate variables
  260
+				this.$elem.css(transformProperty, 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', ' + tx + ', ' + ty + ')');
  261
+			} else if ($.browser.msie) {
  262
+				// IE requires the special transform Filter
  263
+				
  264
+				//TODO: Use Nearest Neighbor during animation FilterType=\'nearest neighbor\'
  265
+				var filterType = ', FilterType=\'nearest neighbor\''; //bilinear
  266
+				var style = this.$elem[0].style;
  267
+				var matrixFilter = 'progid:DXImageTransform.Microsoft.Matrix(' +
  268
+						'M11=' + a + ', M12=' + c + ', M21=' + b + ', M22=' + d +
  269
+						', sizingMethod=\'auto expand\'' + filterType + ')';
  270
+				var filter = style.filter || jQuery.curCSS( this.$elem[0], "filter" ) || "";
  271
+				style.filter = rmatrix.test(filter) ? filter.replace(rmatrix, matrixFilter) : filter ? filter + ' ' + matrixFilter : matrixFilter;
  272
+				
  273
+				// Let's know that we're applying post matrix fixes and the height/width will be static for a bit
  274
+				this.applyingMatrix = true;
  275
+				this.matrix = matrix;
  276
+				
  277
+				// IE can't set the origin or translate directly
  278
+				this.fixPosition(matrix, tx, ty);
  279
+				
  280
+				this.applyingMatrix = false;
  281
+				this.matrix = null;
  282
+			}
  283
+			return true;
  284
+		},
  285
+		
  286
+		/**
  287
+		 * Sets the transform-origin
  288
+		 * This really needs to be percentages
  289
+		 * @param Number x length
  290
+		 * @param Number y length
  291
+		 */
  292
+		origin: function(x, y) {
  293
+			// use CSS in supported browsers
  294
+			if ($.support.csstransforms) {
  295
+				if (typeof y === 'undefined') {
  296
+					this.$elem.css(transformOriginProperty, x);
  297
+				} else {
  298
+					this.$elem.css(transformOriginProperty, x + ' ' + y);
  299
+				}
  300
+				return true;
  301
+			}
  302
+			
  303
+			// correct for keyword lengths
  304
+			switch (x) {
  305
+				case 'left': x = '0'; break;
  306
+				case 'right': x = '100%'; break;
  307
+				case 'center': // no break
  308
+				case undefined: x = '50%';
  309
+			}
  310
+			switch (y) {
  311
+				case 'top': y = '0'; break;
  312
+				case 'bottom': y = '100%'; break;
  313
+				case 'center': // no break
  314
+				case undefined: y = '50%'; //TODO: does this work?
  315
+			}
  316
+			
  317
+			// store percentages directly
  318
+			if (/%/.test(x) && /%/.test(y)) {
  319
+				this.setAttr('origin', [x, y]);
  320
+				return true;
  321
+			}
  322
+			
  323
+			// store mixed values with units, assumed pixels
  324
+			this.setAttr('origin', [
  325
+				/%/.test(x) ? x : parseFloat(x) + 'px',
  326
+				/%/.test(y) ? y : parseFloat(y) + 'px'
  327
+			]);
  328
+			return true;
  329
+		},
  330
+		
  331
+		/**
  332
+		 * Create a function suitable for a CSS value
  333
+		 * @param string func
  334
+		 * @param Mixed value
  335
+		 */
  336
+		createTransformFunc: function(func, value) {
  337
+			if ($.transform.rfunc.reflect.test(func)) {
  338
+				// let's fake reflection
  339
+				// TODO: why would value be false?
  340
+				var matrix = value ? $.matrix[func]() : $.matrix.identity(),
  341
+					a = matrix.e(1,1),
  342
+					b = matrix.e(2,1),
  343
+					c = matrix.e(1,2),
  344
+					d = matrix.e(2,2);
  345
+				return 'matrix(' + a + ', ' + b + ', ' + c + ', ' + d + ', 0, 0)';
  346
+			}
  347
+			
  348
+			value = _correctUnits(func, value);
  349
+			
  350
+			if  (!$.isArray(value)) {
  351
+				return func + '(' + value + ')';
  352
+			} else if (func == 'matrix') {
  353
+				if (vendorPrefix === '-moz-' && value[4]) {
  354
+					value[4] = value[4] +'px';
  355
+				}
  356
+				if (vendorPrefix === '-moz-' && value[5]) {
  357
+					value[5] = value[5] +'px';
  358
+				}
  359
+				return 'matrix(' + value[0] + ', ' + value[1] + ', ' + value[2] + ', ' + value[3] + ', ' + (value[4] || 0) + ', ' + (value[5] || 0) + ')';
  360
+			} else {
  361
+				return func + '(' + value[0] + ', ' + value[1] + ')';
  362
+			}
  363
+		},
  364
+		
  365
+		/**
  366
+		 * @param Matrix matrix
  367
+		 * @param Number tx
  368
+		 * @param Number ty
  369
+		 * @param Number height
  370
+		 * @param Number width
  371
+		 */
  372
+		fixPosition: function(matrix, tx, ty, height, width) {
  373
+			// now we need to fix it!
  374
+			var	calc = new $.matrix.calc(matrix, this.safeOuterHeight(), this.safeOuterWidth()),
  375
+				origin = this.getAttr('origin'); // mixed percentages and px
  376
+				
  377
+			// translate a 0, 0 origin to the current origin
  378
+			var offset = calc.originOffset(new $.matrix.V2(
  379
+				/%/.test(origin[0]) ? parseFloat(origin[0])/100*calc.outerWidth : parseFloat(origin[0]),
  380
+				/%/.test(origin[1]) ? parseFloat(origin[1])/100*calc.outerHeight : parseFloat(origin[1])
  381
+			));
  382
+			
  383
+			// IE glues the top-most and left-most pixels of the transformed object to top/left of the original object
  384
+			//TODO: This seems wrong in the calculations
  385
+			var sides = calc.sides();
  386
+
  387
+			// Protect against an item that is already positioned
  388
+			var cssPosition = this.$elem.css('position');
  389
+			if (cssPosition == 'static') {
  390
+				cssPosition = 'relative';
  391
+			}
  392
+			
  393
+			//TODO: if the element is already positioned, we should attempt to respect it (somehow)
  394
+			//NOTE: we could preserve our offset top and left in an attr on the elem
  395
+			var pos = {top: 0, left: 0};
  396
+			
  397
+			// Approximates transform-origin, tx, and ty
  398
+			var css = {
  399
+				'position': cssPosition,
  400
+				'top': (offset.top + ty + sides.top + pos.top) + 'px',
  401
+				'left': (offset.left + tx + sides.left + pos.left) + 'px',
  402
+				'zoom': 1
  403
+			};
  404
+
  405
+			this.$elem.css(css);
  406
+		}
  407
+	};
  408
+	
  409
+	/**
  410
+	 * Ensure that values have the appropriate units on them
  411
+	 * @param string func
  412
+	 * @param Mixed value
  413
+	 */
  414
+	var rfxnum = /^([\+\-]=)?([\d+.\-]+)(.*)$/;
  415
+	function _correctUnits(func, value) {
  416
+		var result = !$.isArray(value)? [value] : value,
  417
+			rangle = $.transform.rfunc.angle,
  418
+			rlength = $.transform.rfunc.length;
  419
+		
  420
+		for (var i = 0, len = result.length; i < len; i++) {
  421
+			var parts = rfxnum.exec(result[i]),
  422
+				unit = '';
  423
+			
  424
+			// Use an appropriate unit
  425
+			if (rangle.test(func)) {
  426
+				unit = 'deg';
  427
+				
  428
+				// remove nonsense units
  429
+				if (parts[3] && !$.angle.runit.test(parts[3])) {
  430
+					parts[3] = null;
  431
+				}
  432
+			} else if (rlength.test(func)) {
  433
+				unit = 'px';
  434
+			}
  435
+			
  436
+			// ensure a value and appropriate unit
  437
+			if (!parts) {
  438
+				result[i] = 0 + unit;
  439
+			} else if(!parts[3]) {
  440
+				result[i] += unit;
  441
+			}
  442
+			
  443
+		}
  444
+		return len == 1 ? result[0] : result;
  445
+	}
  446
+})(jQuery, this, this.document);
  447
+
  448
+
  449
+///////////////////////////////////////////////////////
  450
+// Safe Outer Length
  451
+///////////////////////////////////////////////////////
  452
+(function($, window, document, undefined) {
  453
+	$.extend($.transform.prototype, {
  454
+		/**
  455
+		 * @param void
  456
+		 * @return Number
  457
+		 */
  458
+		safeOuterHeight: function() {
  459
+			return this.safeOuterLength('height');
  460
+		},
  461
+		
  462
+		/**
  463
+		 * @param void
  464
+		 * @return Number
  465
+		 */
  466
+		safeOuterWidth: function() {
  467
+			return this.safeOuterLength('width');
  468
+		},
  469
+		
  470
+		/**
  471
+		 * Returns reliable outer dimensions for an object that may have been transformed.
  472
+		 * Only use this if the matrix isn't handy
  473
+		 * @param String dim height or width
  474
+		 * @return Number
  475
+		 */
  476
+		safeOuterLength: function(dim) {
  477
+			var funcName = 'outer' + (dim == 'width' ? 'Width' : 'Height');
  478
+			
  479
+			if ($.browser.msie) {
  480
+				// make the variables more generic
  481
+				dim = dim == 'width' ? 'width' : 'height';
  482
+				
  483
+				// if we're transforming and have a matrix; we can shortcut.
  484
+				// the true outerHeight is the transformed outerHeight divided by the ratio.
  485
+				// the ratio is equal to the height of a 1px by 1px box that has been transformed by the same matrix.
  486
+				if (this.applyingMatrix && !this[funcName] && this.matrix) {
  487
+					// calculate and return the correct size
  488
+					var calc = new $.matrix.calc(this.matrix, 1, 1),
  489
+						ratio = calc.offset(),
  490
+						length = this.$elem[funcName]() / ratio[dim];
  491
+					this[funcName] = length;
  492
+					
  493
+					return length;
  494
+				} else if (this.applyingMatrix && this[funcName]) {
  495
+					// return the cached calculation
  496
+					return this[funcName];
  497
+				}
  498
+				
  499
+				// map dimensions to box sides			
  500
+				var side = {
  501
+					height: ['top', 'bottom'],
  502
+					width: ['left', 'right']
  503
+				};
  504
+				
  505
+				// setup some variables
  506
+				var elem = this.$elem[0],
  507
+					outerLen = parseFloat($.curCSS(elem, dim, true)), //TODO: this can be cached on animations that do not animate height/width
  508
+					boxSizingProp = this.boxSizingProperty,
  509
+					boxSizingValue = this.boxSizingValue;
  510
+				
  511
+				// IE6 && IE7 will never have a box-sizing property, so fake it
  512
+				if (!this.boxSizingProperty) {
  513
+					boxSizingProp = this.boxSizingProperty = _findBoxSizingProperty() || 'box-sizing';
  514
+					boxSizingValue = this.boxSizingValue = this.$elem.css(boxSizingProp) || 'content-box';
  515
+				}
  516
+				
  517
+				// return it immediately if we already know it
  518
+				if (this[funcName] && this[dim] == outerLen) {
  519
+					return this[funcName];
  520
+				} else {
  521
+					this[dim] = outerLen;
  522
+				}
  523
+				
  524
+				// add in the padding and border
  525
+				if (boxSizingProp && (boxSizingValue == 'padding-box' || boxSizingValue == 'content-box')) {
  526
+					outerLen += parseFloat($.curCSS(elem, 'padding-' + side[dim][0], true)) || 0 +
  527
+								  parseFloat($.curCSS(elem, 'padding-' + side[dim][1], true)) || 0;
  528
+				}
  529
+				if (boxSizingProp && boxSizingValue == 'content-box') {
  530
+					outerLen += parseFloat($.curCSS(elem, 'border-' + side[dim][0] + '-width', true)) || 0 +
  531
+								  parseFloat($.curCSS(elem, 'border-' + side[dim][1] + '-width', true)) || 0;
  532
+				}
  533
+				
  534
+				// remember and return the outerHeight
  535
+				this[funcName] = outerLen;
  536
+				return outerLen;
  537
+			}
  538
+			return this.$elem[funcName]();
  539
+		}
  540
+	});
  541
+	
  542
+	/**
  543
+	 * Determine the correct property for checking the box-sizing property
  544
+	 * @param void
  545
+	 * @return string
  546
+	 */
  547
+	var _boxSizingProperty = null;
  548
+	function _findBoxSizingProperty () {
  549
+		if (_boxSizingProperty) {
  550
+			return _boxSizingProperty;
  551
+		} 
  552
+		
  553
+		var property = {
  554
+				boxSizing : 'box-sizing',
  555
+				MozBoxSizing : '-moz-box-sizing',
  556
+				WebkitBoxSizing : '-webkit-box-sizing',
  557
+				OBoxSizing : '-o-box-sizing'
  558
+			},
  559
+			elem = document.body;
  560
+		
  561
+		for (var p in property) {
  562
+			if (typeof elem.style[p] != 'undefined') {
  563
+				_boxSizingProperty = property[p];
  564
+				return _boxSizingProperty;
  565
+			}
  566
+		}
  567
+		return null;
  568
+	}
  569
+})(jQuery, this, this.document);
  570
+
  571
+
  572
+///////////////////////////////////////////////////////
  573
+// Attr
  574
+///////////////////////////////////////////////////////
  575
+(function($, window, document, undefined) {
  576
+	var rfuncvalue = /([\w\-]*?)\((.*?)\)/g, // with values
  577
+		attr = 'data-transform',
  578
+		rspace = /\s/,
  579
+		rcspace = /,\s/;
  580
+	
  581
+	$.extend($.transform.prototype, {		
  582
+		/**
  583
+		 * This overrides all of the attributes
  584
+		 * @param Object funcs a list of transform functions to store on this element
  585
+		 * @return void
  586
+		 */
  587
+		setAttrs: function(funcs) {
  588
+			var string = '',
  589
+				value;
  590
+			for (var func in funcs) {
  591
+				value = funcs[func];
  592
+				if ($.isArray(value)) {
  593
+					value = value.join(', ');
  594
+				}
  595
+				string += ' ' + func + '(' + value + ')'; 
  596
+			}
  597
+			this.attr = $.trim(string);
  598
+			this.$elem.attr(attr, this.attr);
  599
+		},
  600
+		
  601
+		/**
  602
+		 * This sets only a specific atribute
  603
+		 * @param string func name of a transform function
  604
+		 * @param mixed value with proper units
  605
+		 * @return void
  606
+		 */
  607
+		setAttr: function(func, value) {
  608
+			// stringify the value
  609
+			if ($.isArray(value)) {
  610
+				value = value.join(', ');
  611
+			}
  612
+			value = $.trim(value+'');
  613
+			
  614
+			// pull from a local variable to look it up
  615
+			var transform = this.attr || this.$elem.attr(attr);
  616
+			
  617
+			if (!transform || transform.indexOf(func) > -1) {
  618
+				// We don't have any existing values, save it
  619
+				// we don't have this function yet, save it
  620
+				this.attr = $.trim(transform + ' ' + func + '(' + value + ')');
  621
+				this.$elem.attr(attr, this.attr);
  622
+			} else {
  623
+				// replace the existing value
  624
+				var funcs = [],	parts;
  625
+				
  626
+				// regex split
  627
+				rfuncvalue.lastIndex = 0; // reset the regex pointer
  628
+				while ((result = rfuncvalue.exec(transform)) !== null) {
  629
+					if (func == parts[1]) {
  630
+						funcs.push(func + '(' + value + ')');
  631
+					} else {
  632
+						funcs.push(parts[0]);
  633
+					}
  634
+				}
  635
+				this.attr = funcs.join(' ');
  636
+				this.$elem.attr(attr, this.attr);
  637
+			}
  638
+		},
  639
+		
  640
+		/**
  641
+		 * @return Object
  642
+		 */
  643
+		getAttrs: function() {
  644
+			var transform = this.attr || this.$elem.attr(attr);
  645
+			if (!transform) {
  646
+				// We don't have any existing values, return empty object
  647
+				return {};
  648
+			}
  649
+			
  650
+			// replace the existing value
  651
+			var attrs = {}, parts, value;
  652
+			
  653
+			rfuncvalue.lastIndex = 0; // reset the regex pointer
  654
+			while ((parts = rfuncvalue.exec(transform)) !== null) {
  655
+				if (parts) {
  656
+					value = parts[2].split(rcspace);
  657
+					attrs[parts[1]] = value.length == 1 ? value[0] : value;
  658
+				}
  659
+			}
  660
+			return attrs;
  661
+		},
  662
+		
  663
+		/**
  664
+		 * @param String func 
  665
+		 * @return mixed
  666
+		 */
  667
+		getAttr: function(func) {
  668
+			var attrs = this.getAttrs();
  669
+			
  670
+			if (typeof attrs[func] !== 'undefined') {
  671
+				return attrs[func];
  672
+			}
  673
+			
  674
+			// animate needs sensible defaults for some props
  675
+			switch (func) {
  676
+				case 'scale': return [1, 1];
  677
+				case 'scaleX': // no break;
  678
+				case 'scaleY': return 1;
  679
+				case 'matrix': return [1, 0, 0, 1, 0, 0];
  680
+				case 'origin':
  681
+					if ($.support.csstransforms) {
  682
+						// supported browsers return percentages always
  683
+						return this.$elem.css(this.transformOriginProperty).split(rspace);
  684
+					} else {
  685
+						// just force IE to also return a percentage
  686
+						return ['50%', '50%'];
  687
+					}
  688
+			}
  689
+			return null;
  690
+		}
  691
+	});
  692
+})(jQuery, this, this.document);
  693
+///////////////////////////////////////////////////////
  694
+// Animation
  695
+///////////////////////////////////////////////////////
  696
+(function($, window, document, undefined) {
  697
+	// Extend the jQuery animation to handle transform functions
  698
+	/**
  699
+	 * @var Regex looks for units on a string
  700
+	 */
  701
+	var rfxnum = /^([+\-]=)?([\d+.\-]+)(.*)$/;
  702
+	
  703
+	/**
  704
+	 * @var Regex identify if additional values are hidden in the unit 
  705
+	 */
  706
+	var rfxmultinum = /^(.*?)\s+([+\-]=)?([\d+.\-]+)(.*)$/;
  707
+	
  708
+	/**
  709
+	 * Doctors prop values in the event that they contain spaces
  710
+	 * @param Object prop
  711
+	 * @param String speed
  712
+	 * @param String easing
  713
+	 * @param Function callback
  714
+	 * @return bool
  715
+	 */
  716
+	var _animate = $.fn.animate;
  717
+	$.fn.animate = function( prop, speed, easing, callback ) {
  718
+		//NOTE: The $.fn.animate() function is a big jerk and requires
  719
+		//		you to attempt to convert the values passed into pixels.
  720
+		//		So we have to doctor the values passed in here to make
  721
+		//		sure $.fn.animate() won't think there's units an ruin
  722
+		//		our fun.
  723
+		if (prop && !jQuery.isEmptyObject(prop)) {
  724
+			var $elem = this;
  725
+			jQuery.each( prop, function( name, val ) {
  726
+				// Clean up the numbers for space-sperated prop values
  727
+				if ($.inArray(name, $.transform.funcs) != -1) {
  728
+					// allow for reflection animation
  729
+					if ($.transform.rfunc.reflect.test(name)) {
  730
+						var m = val ? $.matrix[name]() : $.matrix.identity(), 
  731
+							e = m.elements;
  732
+						val = [e[0], e[1], e[2], e[3]]; 
  733
+					}
  734
+				
  735
+					var parts = rfxnum.exec(val);
  736
+					
  737
+					if ((parts && parts[3]) || $.isArray(val)) {
  738
+						// Either a unit was found or an array was passed
  739
+						var end, unit, values = [];
  740
+						
  741
+						if ($.isArray(val)) {
  742
+							// An array was passed
  743
+							$.each(val, function(i) {
  744
+								parts = rfxnum.exec(this);
  745
+								end = parseFloat(parts[2]);
  746
+								unit = parts[3] || "px";
  747
+										
  748
+								// Remember value
  749
+								values.push({
  750
+									end: (parts[1] ? parts[1] : '') + end,
  751
+									unit: unit
  752
+								});
  753
+							});
  754
+						} else {
  755
+							// A unit was found
  756
+							end = parseFloat( parts[2] );
  757
+							unit = parts[3] || "px";
  758
+								
  759
+							// Remember the first value
  760
+							values.push({
  761
+								end: (parts[1] ? parts[1] : '') + end,
  762
+								unit: unit
  763
+							});
  764
+							
  765
+							// Detect additional values hidden in the unit
  766
+							var i = 0;
  767
+							while (parts = rfxmultinum.exec(unit)) {
  768
+								// Fix the previous unit
  769
+								values[i].unit = parts[1];
  770
+								
  771
+								// Remember this value
  772
+								values.push({
  773
+									end: (parts[2] ? parts[2] : '') + parseFloat(parts[3]),
  774
+									unit: parts[4]
  775
+								});
  776
+								unit = parts[4];
  777
+								i++;
  778
+							}
  779
+						}
  780
+					
  781
+						// Save the values and truncate the value to make it safe to animate
  782
+						$elem.data('data-animate-' + name, values);
  783
+						prop[name] = values[0].end; // NOTE: this propegates into the arguments object
  784
+					}
  785
+				}
  786
+			});
  787
+		}
  788
+		//NOTE: we edit prop above
  789
+		return _animate.apply(this, arguments);
  790
+	};
  791
+	
  792
+	/**
  793
+	 * Returns appropriate start value for transform props
  794
+	 * @param Boolean force
  795
+	 * @return Number
  796
+	 */
  797
+	var _cur = $.fx.prototype.cur;
  798
+	$.fx.prototype.cur = function(force) {
  799
+		//NOTE: The cur function tries to look things up on the element
  800
+		//		itself as a native property first instead of as a style
  801
+		//		property. However, the animate function is a big jerk
  802
+		//		and it's extremely easy to poison the element.style 
  803
+		//		with a random property and ruin all of the fun. So, it's
  804
+		//		easier to just look it up ourselves.
  805
+		if ($.inArray(this.prop, $.transform.funcs) != -1) {
  806
+			this.transform = this.transform || this.elem.transform || new $.transform(this.elem);
  807
+			var r = $.transform.rfunc;
  808
+			
  809
+			// return a single unitless number and animation will play nice
  810
+			var value = this.transform.getAttr(this.prop),
  811
+				parts = rfxnum.exec($.isArray(value) ? value[0] : value);
  812
+			if (value === null || parts === null) {
  813
+				value = r.scale.test(this.prop) || r.reflect.test(this.prop)  ? 1 : 0;
  814
+				parts = [null, null, value];
  815
+			}
  816
+			return parseFloat(parts[2]);
  817
+		}
  818
+		return _cur.apply(this, arguments);
  819
+	};
  820
+	
  821
+	/**
  822
+	 * Detects the existence of a space separated value
  823
+	 * @param Object fx
  824
+	 * @return null
  825
+	 */
  826
+	$.fx.multivalueInit = function(fx) {
  827
+		var $elem = $(fx.elem),
  828
+			values = fx.transform.getAttr(fx.prop), // existing values
  829
+			initValues = $elem.data('data-animate-' + fx.prop); // new values passed into animate
  830
+		
  831
+		if (initValues) {
  832
+			$elem.removeData('data-animate-' + fx.prop); // unremember the saved property
  833
+		}
  834
+		
  835
+		if ($.transform.rfunc.reflect.test(fx.prop)) {
  836
+			values = fx.transform.getAttr('matrix');
  837
+		}
  838
+		
  839
+		fx.values = [];
  840
+		
  841
+		// If we found a previous array but we're only setting one value, we need to set both
  842
+		if ($.isArray(values) && !$.isArray(initValues)) {
  843
+			initValues = [
  844
+				{
  845
+					end: parseFloat(fx.end),
  846
+					unit: fx.unit
  847
+				},
  848
+				{
  849
+					end: $.transform.rfunc.scale.test(fx.prop) ? 1 : 0,
  850
+					unit: fx.unit
  851
+				}
  852
+			];
  853
+		}
  854
+		
  855
+		// If we altered the values before
  856
+		// This happens in the doctored animate function when we pass a unit or multiple values
  857
+		if (initValues) {
  858
+			var start,
  859
+				rscalefunc = $.transform.rfunc.scale,
  860
+				parts;
  861
+			$.each(initValues, function(i, val) {
  862
+				// pull out the start value
  863
+				if ($.isArray(values)) {
  864
+					start = values[i];
  865
+				} else if (i > 0) {
  866
+					// scale duplicates the values for x and y
  867
+					start = rscalefunc.test(fx.prop) ? values : null;
  868
+				} else {
  869
+					start = values;
  870
+				}
  871
+				
  872
+				// if we didn't find a start value
  873
+				if (!start && start !== 0) {
  874
+					start = rscalefunc.test(fx.prop) ? 1 : 0;
  875
+				}
  876
+				
  877
+				// ensure a number
  878
+				start = parseFloat(start);
  879
+				
  880
+				// handle the existence of += and -= prefixes
  881
+				parts = rfxnum.exec(val.end);
  882
+				if (parts && parts[1]) {
  883
+					val.end = ((parts[1] === "-=" ? -1 : 1) * parseFloat(parts[2])) + start;
  884
+				}
  885
+				
  886
+				// Save the values
  887
+				fx.values.push({
  888
+					start: parseFloat(start),
  889
+					end: parseFloat(val.end),
  890
+					unit: val.unit
  891
+				});
  892
+			});
  893
+		} else {
  894
+			// Save the known value
  895
+			fx.values.push({
  896
+				start: parseFloat(fx.start),
  897
+				end: parseFloat(fx.end), // force a Number
  898
+				unit: fx.unit
  899
+			});
  900
+		}
  901
+	};
  902
+
  903
+	/**
  904
+	 * Animates a multi value attribute
  905
+	 * @param Object fx
  906
+	 * @return null
  907
+	 */
  908
+	$.fx.multivalueStep = {
  909
+		_default: function(fx) {
  910
+			$.each(fx.values, function(i, val) {
  911
+				fx.values[i].now = val.start + ((val.end - val.start) * fx.pos);
  912
+			});
  913
+		}
  914
+	};
  915
+	
  916
+	/**
  917
+	 * Step for animating tranformations
  918
+	 */
  919
+	$.each($.transform.funcs, function(i, func) {
  920
+		$.fx.step[func] = function(fx) {
  921
+			// Initialize the transformation
  922
+			if (!fx.transformInit) {
  923
+				fx.transform = fx.transform || fx.elem.transform || new $.transform(fx.elem);
  924
+								
  925
+				// Handle multiple values
  926
+				$.fx.multivalueInit(fx);
  927
+				if (fx.values.length > 1) {
  928
+					fx.multiple = true;
  929
+				}
  930
+				
  931
+				// Force degrees for angles, Remove units for unitless
  932
+				var r = $.transform.rfunc;
  933
+				if (r.angle.test(fx.prop)) {
  934
+					//TODO: we should convert from other rational units
  935
+					fx.unit = 'deg';
  936
+				} else if (r.scale.test(fx.prop)) {
  937
+					fx.unit = ''; 
  938
+				} else if (r.reflect.test(fx.prop)) {
  939
+					//TODO: for animation purposes, this is a matrix and can be animated (although it looks silly)
  940
+					fx.unit = ''; //this is a boolean func
  941
+				} else if (fx.prop == 'matrix') {
  942
+					fx.unit = '';
  943
+				}
  944
+				//TODO: I guess we already foced length units earlier
  945
+				
  946
+				// Force all units on multiple values to be the same
  947
+				//TODO: we should convert from other rational units
  948
+				$.each(fx.values, function(i) {fx.values[i].unit = fx.unit;});
  949
+				
  950
+				fx.transformInit = true;
  951
+			}
  952
+			
  953
+			
  954
+			// Increment all of the values
  955
+			if (fx.multiple) {
  956
+				($.fx.multivalueStep[fx.prop] || $.fx.multivalueStep._default)(fx);
  957
+			} else {
  958
+				fx.values[0].now = fx.now;
  959
+			}
  960
+			
  961
+			var values = [];
  962
+			
  963
+			// Do some value correction and join the values
  964
+			$.each(fx.values, function(i, value) {
  965
+				// Keep angles below 360 in either direction.
  966
+				if (value.unit == 'deg') {
  967
+					while (value.now >= 360 ) {
  968
+						value.now -= 360;
  969
+					}
  970
+					while (value.now <= -360 ) {
  971
+						value.now += 360;
  972
+					}
  973
+				}
  974
+				// TODO: handle reflection matrices here
  975
+				
  976
+				//Pretty up the final value (use the double parseFloat
  977
+				//	to correct super small decimals)
  978
+				values.push(parseFloat(parseFloat(value.now).toFixed(8)) + value.unit);
  979
+			});
  980
+			
  981
+			// Apply the transformation
  982
+			var funcs = {},
  983
+				prop = $.transform.rfunc.reflect.test(fx.prop) ? 'matrix' : fx.prop;
  984
+						
  985
+			funcs[prop] = fx.multiple ? values : values[0];
  986
+			fx.transform.exec(funcs, {preserve: true});
  987
+		};
  988
+	});
  989
+})(jQuery, this, this.document);
  990
+///////////////////////////////////////////////////////
  991
+// Angle
  992
+///////////////////////////////////////////////////////
  993
+(function($, window, document, undefined) {
  994
+	/**
  995
+	 * Converting a radian to a degree
  996
+	 * @const
  997
+	 */
  998
+	var RAD_DEG = 180/Math.PI;
  999
+	
  1000
+	/**
  1001
+	 * Converting a radian to a grad
  1002
+	 * @const
  1003
+	 */
  1004
+	var RAD_GRAD = 200/Math.PI;
  1005
+	
  1006
+	/**
  1007
+	 * Converting a degree to a radian
  1008
+	 * @const
  1009
+	 */
  1010
+	var DEG_RAD = Math.PI/180;
  1011
+	
  1012
+	/**
  1013
+	 * Converting a degree to a grad
  1014
+	 * @const
  1015
+	 */
  1016
+	var DEG_GRAD = 2/1.8;
  1017
+	
  1018
+	/**
  1019
+	 * Converting a grad to a degree
  1020
+	 * @const
  1021
+	 */
  1022
+	var GRAD_DEG = 0.9;
  1023
+	
  1024
+	/**
  1025
+	 * Converting a grad to a radian
  1026
+	 * @const
  1027
+	 */
  1028
+	var GRAD_RAD = Math.PI/200;
  1029
+	
  1030
+	/**
  1031
+	 * Functions for converting angles
  1032
+	 * @var Object
  1033
+	 */
  1034
+	$.extend({
  1035
+		angle: {
  1036
+			/**
  1037
+			 * available units for an angle
  1038
+			 * @var Regex
  1039
+			 */
  1040
+			runit: /(deg|g?rad)/,
  1041
+			
  1042
+			/**
  1043
+			 * Convert a radian into a degree
  1044
+			 * @param Number rad
  1045
+			 * @return Number
  1046
+			 */
  1047
+			radianToDegree: function(rad) {
  1048
+				return rad * RAD_DEG;
  1049
+			},
  1050
+			
  1051
+			/**
  1052
+			 * Convert a radian into a degree
  1053
+			 * @param Number rad
  1054
+			 * @return Number
  1055
+			 */
  1056
+			radianToGrad: function(rad) {
  1057
+				return rad * RAD_GRAD;
  1058
+			},
  1059
+			
  1060
+			/**
  1061
+			 * Convert a degree into a radian
  1062
+			 * @param Number deg
  1063
+			 * @return Number
  1064
+			 */
  1065
+			degreeToRadian: function(deg) {
  1066
+				return deg * DEG_RAD;
  1067
+			},
  1068
+			
  1069
+			/**
  1070
+			 * Convert a degree into a radian
  1071
+			 * @param Number deg
  1072
+			 * @return Number
  1073
+			 */
  1074
+			degreeToGrad: function(deg) {
  1075
+				return deg * DEG_GRAD;
  1076
+			},
  1077
+			
  1078
+			/**
  1079
+			 * Convert a grad into a degree
  1080
+			 * @param Number grad
  1081
+			 * @return Number
  1082
+			 */
  1083
+			gradToDegree: function(grad) {
  1084
+				return grad * GRAD_DEG;
  1085
+			},
  1086
+			
  1087
+			/**
  1088
+			 * Convert a grad into a radian
  1089
+			 * @param Number grad
  1090
+			 * @return Number
  1091
+			 */
  1092
+			gradToRadian: function(grad) {
  1093
+				return grad * GRAD_RAD;
  1094
+			}
  1095
+		}
  1096
+	});
  1097
+})(jQuery, this, this.document);
  1098
+///////////////////////////////////////////////////////
  1099
+// Matrix
  1100
+///////////////////////////////////////////////////////
  1101
+(function($, window, document, undefined) {