|
1 /** |
|
2 * Interface Elements for jQuery |
|
3 * FX |
|
4 * |
|
5 * http://interface.eyecon.ro |
|
6 * |
|
7 * Copyright (c) 2006 Stefan Petre |
|
8 * Dual licensed under the MIT (MIT-LICENSE.txt) |
|
9 * and GPL (GPL-LICENSE.txt) licenses. |
|
10 * |
|
11 * |
|
12 */ |
|
13 |
|
14 /** |
|
15 * Validates elements that can be animated |
|
16 */ |
|
17 jQuery.fxCheckTag = function(e) |
|
18 { |
|
19 if (/^tr$|^td$|^tbody$|^caption$|^thead$|^tfoot$|^col$|^colgroup$|^th$|^body$|^header$|^script$|^frame$|^frameset$|^option$|^optgroup$|^meta$/i.test(e.nodeName) ) |
|
20 return false; |
|
21 else |
|
22 return true; |
|
23 }; |
|
24 |
|
25 /** |
|
26 * Destroy the wrapper used for some animations |
|
27 */ |
|
28 jQuery.fx.destroyWrapper = function(e, old) |
|
29 { |
|
30 var c = e.firstChild; |
|
31 var cs = c.style; |
|
32 cs.position = old.position; |
|
33 cs.marginTop = old.margins.t; |
|
34 cs.marginLeft = old.margins.l; |
|
35 cs.marginBottom = old.margins.b; |
|
36 cs.marginRight = old.margins.r; |
|
37 cs.top = old.top + 'px'; |
|
38 cs.left = old.left + 'px'; |
|
39 e.parentNode.insertBefore(c, e); |
|
40 e.parentNode.removeChild(e); |
|
41 }; |
|
42 |
|
43 /** |
|
44 * Builds a wrapper used for some animations |
|
45 */ |
|
46 jQuery.fx.buildWrapper = function(e) |
|
47 { |
|
48 if (!jQuery.fxCheckTag(e)) |
|
49 return false; |
|
50 var t = jQuery(e); |
|
51 var es = e.style; |
|
52 var restoreStyle = false; |
|
53 |
|
54 if (t.css('display') == 'none') { |
|
55 oldVisibility = t.css('visibility'); |
|
56 t.css('visibility', 'hidden').show(); |
|
57 restoreStyle = true; |
|
58 } |
|
59 var oldStyle = {}; |
|
60 oldStyle.position = t.css('position'); |
|
61 oldStyle.sizes = jQuery.iUtil.getSize(e); |
|
62 oldStyle.margins = jQuery.iUtil.getMargins(e); |
|
63 |
|
64 var oldFloat = e.currentStyle ? e.currentStyle.styleFloat : t.css('float'); |
|
65 oldStyle.top = parseInt(t.css('top'))||0; |
|
66 oldStyle.left = parseInt(t.css('left'))||0; |
|
67 var wid = 'w_' + parseInt(Math.random() * 10000); |
|
68 var wr = document.createElement(/^img$|^br$|^input$|^hr$|^select$|^textarea$|^object$|^iframe$|^button$|^form$|^table$|^ul$|^dl$|^ol$/i.test(e.nodeName) ? 'div' : e.nodeName); |
|
69 jQuery.attr(wr,'id', wid); |
|
70 var wrapEl = jQuery(wr).addClass('fxWrapper'); |
|
71 var wrs = wr.style; |
|
72 var top = 0; |
|
73 var left = 0; |
|
74 if (oldStyle.position == 'relative' || oldStyle.position == 'absolute'){ |
|
75 top = oldStyle.top; |
|
76 left = oldStyle.left; |
|
77 } |
|
78 |
|
79 wrs.top = top + 'px'; |
|
80 wrs.left = left + 'px'; |
|
81 wrs.position = oldStyle.position != 'relative' && oldStyle.position != 'absolute' ? 'relative' : oldStyle.position; |
|
82 wrs.height = oldStyle.sizes.hb + 'px'; |
|
83 wrs.width = oldStyle.sizes.wb + 'px'; |
|
84 wrs.marginTop = oldStyle.margins.t; |
|
85 wrs.marginRight = oldStyle.margins.r; |
|
86 wrs.marginBottom = oldStyle.margins.b; |
|
87 wrs.marginLeft = oldStyle.margins.l; |
|
88 wrs.overflow = 'hidden'; |
|
89 if (jQuery.browser.msie) { |
|
90 wrs.styleFloat = oldFloat; |
|
91 } else { |
|
92 wrs.cssFloat = oldFloat; |
|
93 } |
|
94 if (jQuery.browser == "msie") { |
|
95 es.filter = "alpha(opacity=" + 0.999*100 + ")"; |
|
96 } |
|
97 es.opacity = 0.999; |
|
98 //t.wrap(wr); |
|
99 e.parentNode.insertBefore(wr, e); |
|
100 wr.appendChild(e); |
|
101 es.marginTop = '0px'; |
|
102 es.marginRight = '0px'; |
|
103 es.marginBottom = '0px'; |
|
104 es.marginLeft = '0px'; |
|
105 es.position = 'absolute'; |
|
106 es.listStyle = 'none'; |
|
107 es.top = '0px'; |
|
108 es.left = '0px'; |
|
109 if (restoreStyle) { |
|
110 t.hide(); |
|
111 es.visibility = oldVisibility; |
|
112 } |
|
113 return {oldStyle:oldStyle, wrapper:jQuery(wr)}; |
|
114 }; |
|
115 |
|
116 /** |
|
117 * named colors |
|
118 */ |
|
119 jQuery.fx.namedColors = { |
|
120 aqua:[0,255,255], |
|
121 azure:[240,255,255], |
|
122 beige:[245,245,220], |
|
123 black:[0,0,0], |
|
124 blue:[0,0,255], |
|
125 brown:[165,42,42], |
|
126 cyan:[0,255,255], |
|
127 darkblue:[0,0,139], |
|
128 darkcyan:[0,139,139], |
|
129 darkgrey:[169,169,169], |
|
130 darkgreen:[0,100,0], |
|
131 darkkhaki:[189,183,107], |
|
132 darkmagenta:[139,0,139], |
|
133 darkolivegreen:[85,107,47], |
|
134 darkorange:[255,140,0], |
|
135 darkorchid:[153,50,204], |
|
136 darkred:[139,0,0], |
|
137 darksalmon:[233,150,122], |
|
138 darkviolet:[148,0,211], |
|
139 fuchsia:[255,0,255], |
|
140 gold:[255,215,0], |
|
141 green:[0,128,0], |
|
142 indigo:[75,0,130], |
|
143 khaki:[240,230,140], |
|
144 lightblue:[173,216,230], |
|
145 lightcyan:[224,255,255], |
|
146 lightgreen:[144,238,144], |
|
147 lightgrey:[211,211,211], |
|
148 lightpink:[255,182,193], |
|
149 lightyellow:[255,255,224], |
|
150 lime:[0,255,0], |
|
151 magenta:[255,0,255], |
|
152 maroon:[128,0,0], |
|
153 navy:[0,0,128], |
|
154 olive:[128,128,0], |
|
155 orange:[255,165,0], |
|
156 pink:[255,192,203], |
|
157 purple:[128,0,128], |
|
158 red:[255,0,0], |
|
159 silver:[192,192,192], |
|
160 white:[255,255,255], |
|
161 yellow:[255,255,0] |
|
162 }; |
|
163 |
|
164 /** |
|
165 * parses a color to an object for reg, green and blue |
|
166 */ |
|
167 jQuery.fx.parseColor = function(color, notColor) |
|
168 { |
|
169 if (jQuery.fx.namedColors[color]) |
|
170 return { |
|
171 r: jQuery.fx.namedColors[color][0], |
|
172 g: jQuery.fx.namedColors[color][1], |
|
173 b: jQuery.fx.namedColors[color][2] |
|
174 }; |
|
175 else if (result = /^rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)$/.exec(color)) |
|
176 return { |
|
177 r: parseInt(result[1]), |
|
178 g: parseInt(result[2]), |
|
179 b: parseInt(result[3]) |
|
180 }; |
|
181 else if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)$/.exec(color)) |
|
182 return { |
|
183 r: parseFloat(result[1])*2.55, |
|
184 g: parseFloat(result[2])*2.55, |
|
185 b: parseFloat(result[3])*2.55 |
|
186 }; |
|
187 else if (result = /^#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])$/.exec(color)) |
|
188 return { |
|
189 r: parseInt("0x"+ result[1] + result[1]), |
|
190 g: parseInt("0x" + result[2] + result[2]), |
|
191 b: parseInt("0x" + result[3] + result[3]) |
|
192 }; |
|
193 else if (result = /^#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})$/.exec(color)) |
|
194 return { |
|
195 r: parseInt("0x" + result[1]), |
|
196 g: parseInt("0x" + result[2]), |
|
197 b: parseInt("0x" + result[3]) |
|
198 }; |
|
199 else |
|
200 return notColor == true ? false : {r: 255, g: 255, b: 255}; |
|
201 }; |
|
202 /** |
|
203 * CSS rules that can be animated |
|
204 */ |
|
205 jQuery.fx.cssProps = { |
|
206 borderBottomWidth:1, |
|
207 borderLeftWidth:1, |
|
208 borderRightWidth:1, |
|
209 borderTopWidth:1, |
|
210 bottom:1, |
|
211 fontSize:1, |
|
212 height:1, |
|
213 left:1, |
|
214 letterSpacing:1, |
|
215 lineHeight:1, |
|
216 marginBottom:1, |
|
217 marginLeft:1, |
|
218 marginRight:1, |
|
219 marginTop:1, |
|
220 maxHeight:1, |
|
221 maxWidth:1, |
|
222 minHeight:1, |
|
223 minWidth:1, |
|
224 opacity:1, |
|
225 outlineOffset:1, |
|
226 outlineWidth:1, |
|
227 paddingBottom:1, |
|
228 paddingLeft:1, |
|
229 paddingRight:1, |
|
230 paddingTop:1, |
|
231 right:1, |
|
232 textIndent:1, |
|
233 top:1, |
|
234 width:1, |
|
235 zIndex:1 |
|
236 }; |
|
237 /** |
|
238 * CSS color rules that can be animated |
|
239 */ |
|
240 jQuery.fx.colorCssProps = { |
|
241 backgroundColor:1, |
|
242 borderBottomColor:1, |
|
243 borderLeftColor:1, |
|
244 borderRightColor:1, |
|
245 borderTopColor:1, |
|
246 color:1, |
|
247 outlineColor:1 |
|
248 }; |
|
249 |
|
250 jQuery.fx.cssSides = ['Top', 'Right', 'Bottom', 'Left']; |
|
251 jQuery.fx.cssSidesEnd = { |
|
252 'borderWidth': ['border', 'Width'], |
|
253 'borderColor': ['border', 'Color'], |
|
254 'margin': ['margin', ''], |
|
255 'padding': ['padding', ''] |
|
256 }; |
|
257 |
|
258 /** |
|
259 * Overwrite animation to use new FX function |
|
260 */ |
|
261 jQuery.fn.extend({ |
|
262 |
|
263 animate: function( prop, speed, easing, callback ) { |
|
264 return this.queue(function(){ |
|
265 var opt = jQuery.speed(speed, easing, callback); |
|
266 var e = new jQuery.fxe( this, opt, prop ); |
|
267 |
|
268 }); |
|
269 }, |
|
270 pause: function(speed, callback) { |
|
271 return this.queue(function(){ |
|
272 var opt = jQuery.speed(speed, callback); |
|
273 var e = new jQuery.pause( this, opt ); |
|
274 }); |
|
275 }, |
|
276 stop : function(step) { |
|
277 return this.each(function(){ |
|
278 if (this.animationHandler) |
|
279 jQuery.stopAnim(this, step); |
|
280 |
|
281 }); |
|
282 }, |
|
283 stopAll : function(step) { |
|
284 return this.each(function(){ |
|
285 if (this.animationHandler) |
|
286 jQuery.stopAnim(this, step); |
|
287 if ( this.queue && this.queue['fx'] ) |
|
288 this.queue.fx = []; |
|
289 }); |
|
290 } |
|
291 }); |
|
292 /** |
|
293 * Improved FXC function that aniamtes collection of properties per timer. Accepts inline styles and class names to animate |
|
294 */ |
|
295 jQuery.extend({ |
|
296 pause: function(elem, options) |
|
297 { |
|
298 var z = this, values; |
|
299 z.step = function() |
|
300 { |
|
301 if ( jQuery.isFunction( options.complete ) ) |
|
302 options.complete.apply( elem ); |
|
303 }; |
|
304 z.timer=setInterval(function(){z.step();},options.duration); |
|
305 elem.animationHandler = z; |
|
306 }, |
|
307 easing : { |
|
308 linear: function(p, n, firstNum, delta, duration) { |
|
309 return ((-Math.cos(p*Math.PI)/2) + 0.5) * delta + firstNum; |
|
310 } |
|
311 }, |
|
312 fxe: function( elem, options, prop ){ |
|
313 var z = this, values; |
|
314 |
|
315 // The styles |
|
316 var y = elem.style; |
|
317 var oldOverflow = jQuery.css(elem, "overflow"); |
|
318 var oldDisplay= jQuery.css(elem, "display"); |
|
319 var props = {}; |
|
320 z.startTime = (new Date()).getTime(); |
|
321 options.easing = options.easing && jQuery.easing[options.easing] ? options.easing : 'linear'; |
|
322 |
|
323 z.getValues = function(tp, vp) |
|
324 { |
|
325 if (jQuery.fx.cssProps[tp]) { |
|
326 if (vp == 'show' || vp == 'hide' || vp == 'toggle') { |
|
327 if ( !elem.orig ) elem.orig = {}; |
|
328 var r = parseFloat( jQuery.curCSS(elem, tp) ); |
|
329 elem.orig[tp] = r && r > -10000 ? r : (parseFloat( jQuery.css(elem,tp) )||0); |
|
330 vp = vp == 'toggle' ? ( oldDisplay == 'none' ? 'show' : 'hide') : vp; |
|
331 options[vp] = true; |
|
332 props[tp] = vp == 'show' ? [0, elem.orig[tp]] : [elem.orig[tp], 0]; |
|
333 if (tp != 'opacity') |
|
334 y[tp] = props[tp][0] + (tp != 'zIndex' && tp != 'fontWeight' ? 'px':''); |
|
335 else |
|
336 jQuery.attr(y, "opacity", props[tp][0]); |
|
337 } else { |
|
338 props[tp] = [parseFloat( jQuery.curCSS(elem, tp) ), parseFloat(vp)||0]; |
|
339 } |
|
340 } else if (jQuery.fx.colorCssProps[tp]) |
|
341 props[tp] = [jQuery.fx.parseColor(jQuery.curCSS(elem, tp)), jQuery.fx.parseColor(vp)]; |
|
342 else if(/^margin$|padding$|border$|borderColor$|borderWidth$/i.test(tp)) { |
|
343 var m = vp.replace(/\s+/g, ' ').replace(/rgb\s*\(\s*/g,'rgb(').replace(/\s*,\s*/g,',').replace(/\s*\)/g,')').match(/([^\s]+)/g); |
|
344 switch(tp){ |
|
345 case 'margin': |
|
346 case 'padding': |
|
347 case 'borderWidth': |
|
348 case 'borderColor': |
|
349 m[3] = m[3]||m[1]||m[0]; |
|
350 m[2] = m[2]||m[0]; |
|
351 m[1] = m[1]||m[0]; |
|
352 for(var i = 0; i < jQuery.fx.cssSides.length; i++) { |
|
353 var nmp = jQuery.fx.cssSidesEnd[tp][0] + jQuery.fx.cssSides[i] + jQuery.fx.cssSidesEnd[tp][1]; |
|
354 props[nmp] = tp == 'borderColor' ? |
|
355 [jQuery.fx.parseColor(jQuery.curCSS(elem, nmp)), jQuery.fx.parseColor(m[i])] |
|
356 : [parseFloat( jQuery.curCSS(elem, nmp) ), parseFloat(m[i])]; |
|
357 } |
|
358 break; |
|
359 case 'border': |
|
360 for(var i = 0; i< m.length; i++) { |
|
361 var floatVal = parseFloat(m[i]); |
|
362 var sideEnd = !isNaN(floatVal) ? 'Width' : (!/transparent|none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset/i.test(m[i]) ? 'Color' : false); |
|
363 if (sideEnd) { |
|
364 for(var j = 0; j < jQuery.fx.cssSides.length; j++) { |
|
365 nmp = 'border' + jQuery.fx.cssSides[j] + sideEnd; |
|
366 props[nmp] = sideEnd == 'Color' ? |
|
367 [jQuery.fx.parseColor(jQuery.curCSS(elem, nmp)), jQuery.fx.parseColor(m[i])] |
|
368 : [parseFloat( jQuery.curCSS(elem, nmp) ), floatVal]; |
|
369 } |
|
370 } else { |
|
371 y['borderStyle'] = m[i]; |
|
372 } |
|
373 } |
|
374 break; |
|
375 } |
|
376 } else { |
|
377 y[tp] = vp; |
|
378 } |
|
379 return false; |
|
380 }; |
|
381 |
|
382 for(p in prop) { |
|
383 if (p == 'style') { |
|
384 var newStyles = jQuery.parseStyle(prop[p]); |
|
385 for (np in newStyles) { |
|
386 this.getValues(np, newStyles[np]); |
|
387 } |
|
388 } else if (p == 'className') { |
|
389 if (document.styleSheets) |
|
390 for (var i=0; i<document.styleSheets.length; i++){ |
|
391 var cssRules = document.styleSheets[i].cssRules||document.styleSheets[i].rules||null; |
|
392 if (cssRules) { |
|
393 for (var j=0; j<cssRules.length; j++) { |
|
394 if(cssRules[j].selectorText == '.' + prop[p]) { |
|
395 var rule = new RegExp('\.' + prop[p] + ' {'); |
|
396 var styles = cssRules[j].style.cssText; |
|
397 var newStyles = jQuery.parseStyle(styles.replace(rule, '').replace(/}/g, '')); |
|
398 for (np in newStyles) { |
|
399 this.getValues(np, newStyles[np]); |
|
400 } |
|
401 } |
|
402 } |
|
403 } |
|
404 } |
|
405 } else { |
|
406 this.getValues(p, prop[p]); |
|
407 } |
|
408 } |
|
409 y.display = oldDisplay == 'none' ? 'block' : oldDisplay; |
|
410 y.overflow = 'hidden'; |
|
411 |
|
412 /*if (options.show) |
|
413 y.display = "";*/ |
|
414 |
|
415 z.step = function(){ |
|
416 var t = (new Date()).getTime(); |
|
417 if (t > options.duration + z.startTime) { |
|
418 clearInterval(z.timer); |
|
419 z.timer = null; |
|
420 for (p in props) { |
|
421 if ( p == "opacity" ) |
|
422 jQuery.attr(y, "opacity", props[p][1]); |
|
423 else if (typeof props[p][1] == 'object') |
|
424 y[p] = 'rgb(' + props[p][1].r +',' + props[p][1].g +',' + props[p][1].b +')'; |
|
425 else |
|
426 y[p] = props[p][1] + (p != 'zIndex' && p != 'fontWeight' ? 'px':''); |
|
427 } |
|
428 if ( options.hide || options.show ) |
|
429 for ( var p in elem.orig ) |
|
430 if (p == "opacity") |
|
431 jQuery.attr(y, p, elem.orig[p]); |
|
432 else |
|
433 y[p] = ""; |
|
434 y.display = options.hide ? 'none' : (oldDisplay !='none' ? oldDisplay : 'block'); |
|
435 y.overflow = oldOverflow; |
|
436 elem.animationHandler = null; |
|
437 if ( jQuery.isFunction( options.complete ) ) |
|
438 options.complete.apply( elem ); |
|
439 } else { |
|
440 var n = t - this.startTime; |
|
441 var pr = n / options.duration; |
|
442 for (p in props) { |
|
443 if (typeof props[p][1] == 'object') { |
|
444 y[p] = 'rgb(' |
|
445 + parseInt(jQuery.easing[options.easing](pr, n, props[p][0].r, (props[p][1].r-props[p][0].r), options.duration)) |
|
446 + ',' |
|
447 + parseInt(jQuery.easing[options.easing](pr, n, props[p][0].g, (props[p][1].g-props[p][0].g), options.duration)) |
|
448 + ',' |
|
449 + parseInt(jQuery.easing[options.easing](pr, n, props[p][0].b, (props[p][1].b-props[p][0].b), options.duration)) |
|
450 +')'; |
|
451 } else { |
|
452 var pValue = jQuery.easing[options.easing](pr, n, props[p][0], (props[p][1]-props[p][0]), options.duration); |
|
453 if ( p == "opacity" ) |
|
454 jQuery.attr(y, "opacity", pValue); |
|
455 else |
|
456 y[p] = pValue + (p != 'zIndex' && p != 'fontWeight' ? 'px':''); |
|
457 } |
|
458 } |
|
459 |
|
460 } |
|
461 }; |
|
462 z.timer=setInterval(function(){z.step();},13); |
|
463 elem.animationHandler = z; |
|
464 }, |
|
465 stopAnim: function(elem, step) |
|
466 { |
|
467 if (step) |
|
468 elem.animationHandler.startTime -= 100000000; |
|
469 else { |
|
470 window.clearInterval(elem.animationHandler.timer); |
|
471 elem.animationHandler = null; |
|
472 jQuery.dequeue(elem, "fx"); |
|
473 } |
|
474 } |
|
475 } |
|
476 ); |
|
477 |
|
478 jQuery.parseStyle = function(styles) { |
|
479 var newStyles = {}; |
|
480 if (typeof styles == 'string') { |
|
481 styles = styles.toLowerCase().split(';'); |
|
482 for(var i=0; i< styles.length; i++){ |
|
483 rule = styles[i].split(':'); |
|
484 if (rule.length == 2) { |
|
485 newStyles[jQuery.trim(rule[0].replace(/\-(\w)/g,function(m,c){return c.toUpperCase();}))] = jQuery.trim(rule[1]); |
|
486 } |
|
487 } |
|
488 } |
|
489 return newStyles; |
|
490 }; |