1. Introduces a set of helper methods to easily create and define new effects.
2. Uses clip animations and placeholders instead of wrappers for clip effects.
3. Ensures all animations are detectable as animated
Fixes #10599
Fixes #9477
Fixes #9257
Fixes #9066
Fixes #8867
Fixes #8671
Fixes #8505
Fixes #7885
Fixes #7041
Closes gh-1017
<style>
.toggler { width: 500px; height: 200px; position: relative; }
#button { padding: .5em 1em; text-decoration: none; }
- #effect { width: 240px; padding: 1em; font-size: 1.2em; border: 1px solid #000; background: #eee; color: #333; }
- .newClass { text-indent: 40px; letter-spacing: .4em; width: 410px; height: 100px; padding: 30px; margin: 10px; font-size: 1.6em; }
+ #effect { width: 240px; padding: 1em; border: 1px solid #000; background: #eee; color: #333; }
+ .newClass { text-indent: 40px; letter-spacing: .4em; width: 410px; height: 120px; padding: 30px; margin: 10px; font-size: 1.1em; }
</style>
<script>
$(function() {
<style>
.toggler { width: 500px; height: 200px; position: relative; }
#button { padding: .5em 1em; text-decoration: none; }
- #effect { width: 240px; height: 135px; padding: 0.4em; position: relative; background: #fff; }
+ #effect { width: 240px; height: 170px; padding: 0.4em; position: relative; background: #fff; }
#effect h3 { margin: 0; padding: 0.4em; text-align: center; }
</style>
<script>
<style>
.toggler { width: 500px; height: 200px; position: relative; }
#button { padding: .5em 1em; text-decoration: none; }
- #effect { width: 240px; height: 135px; padding: 0.4em; position: relative; }
+ #effect { width: 240px; height: 170px; padding: 0.4em; position: relative; }
#effect h3 { margin: 0; padding: 0.4em; text-align: center; }
.ui-effects-transfer { border: 2px dotted gray; }
</style>
var options = {};
// some effects have required parameters
if ( selectedEffect === "scale" ) {
- options = { percent: 0 };
+ options = { percent: 50 };
} else if ( selectedEffect === "transfer" ) {
options = { to: "#button", className: "ui-effects-transfer" };
} else if ( selectedEffect === "size" ) {
<script src="../../ui/effect-clip.js"></script>
<script src="../../ui/effect-drop.js"></script>
<script src="../../ui/effect-explode.js"></script>
+ <script src="../../ui/effect-fade.js"></script>
<script src="../../ui/effect-fold.js"></script>
<script src="../../ui/effect-highlight.js"></script>
<script src="../../ui/effect-puff.js"></script>
<style>
.toggler { width: 500px; height: 200px; }
#button { padding: .5em 1em; text-decoration: none; }
- #effect { width: 240px; height: 135px; padding: 0.4em; position: relative; }
+ #effect { width: 240px; height: 170px; padding: 0.4em; position: relative; }
#effect h3 { margin: 0; padding: 0.4em; text-align: center; }
</style>
<script>
var options = {};
// some effects have required parameters
if ( selectedEffect === "scale" ) {
- options = { percent: 0 };
+ options = { percent: 50 };
} else if ( selectedEffect === "size" ) {
options = { to: { width: 200, height: 60 } };
}
<option value="clip">Clip</option>
<option value="drop">Drop</option>
<option value="explode">Explode</option>
+ <option value="fade">Fade</option>
<option value="fold">Fold</option>
<option value="highlight">Highlight</option>
<option value="puff">Puff</option>
<script src="../../ui/effect-clip.js"></script>
<script src="../../ui/effect-drop.js"></script>
<script src="../../ui/effect-explode.js"></script>
+ <script src="../../ui/effect-fade.js"></script>
<script src="../../ui/effect-fold.js"></script>
<script src="../../ui/effect-highlight.js"></script>
<script src="../../ui/effect-puff.js"></script>
<style>
.toggler { width: 500px; height: 200px; }
#button { padding: .5em 1em; text-decoration: none; }
- #effect { width: 240px; height: 135px; padding: 0.4em; position: relative; }
+ #effect { width: 240px; height: 170px; padding: 0.4em; position: relative; }
#effect h3 { margin: 0; padding: 0.4em; text-align: center; }
</style>
<script>
var options = {};
// some effects have required parameters
if ( selectedEffect === "scale" ) {
- options = { percent: 100 };
+ options = { percent: 50 };
} else if ( selectedEffect === "size" ) {
options = { to: { width: 280, height: 185 } };
}
<option value="clip">Clip</option>
<option value="drop">Drop</option>
<option value="explode">Explode</option>
+ <option value="fade">Fade</option>
<option value="fold">Fold</option>
<option value="highlight">Highlight</option>
<option value="puff">Puff</option>
.toggler { width: 500px; height: 200px; position: relative; }
#button { padding: .5em 1em; text-decoration: none; }
#effect { position: relative; }
- .newClass { width: 240px; padding: 1em; letter-spacing: 0; font-size: 1.2em; margin: 0; }
- .anotherNewClass { text-indent: 40px; letter-spacing: .4em; width: 410px; height: 100px; padding: 30px; margin: 10px; font-size: 1.6em; }
+ .newClass { width: 240px; padding: 1em; letter-spacing: 0; margin: 0; }
+ .anotherNewClass { text-indent: 40px; letter-spacing: .2em; width: 410px; height: 100px; padding: 30px; margin: 10px; font-size: 1.1em; }
</style>
<script>
$(function() {
<script src="../../ui/effect-clip.js"></script>
<script src="../../ui/effect-drop.js"></script>
<script src="../../ui/effect-explode.js"></script>
+ <script src="../../ui/effect-fade.js"></script>
<script src="../../ui/effect-fold.js"></script>
<script src="../../ui/effect-highlight.js"></script>
<script src="../../ui/effect-puff.js"></script>
#effect {
position: relative;
width: 240px;
- height: 135px;
+ height: 170px;
padding: 0.4em;
}
#effect h3 {
var options = {};
// some effects have required parameters
if ( selectedEffect === "scale" ) {
- options = { percent: 0 };
+ options = { percent: 50 };
} else if ( selectedEffect === "size" ) {
options = { to: { width: 200, height: 60 } };
}
<option value="clip">Clip</option>
<option value="drop">Drop</option>
<option value="explode">Explode</option>
+ <option value="fade">Fade</option>
<option value="fold">Fold</option>
<option value="highlight">Highlight</option>
<option value="puff">Puff</option>
width: 100px;
}
+ .relative {
+ position: relative;
+ top: 0px;
+ left: 0px;
+ }
+ .absolute {
+ position: absolute;
+ top: 0px;
+ left: 0px;
+ }
+ .fixed {
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ }
+ .static {
+ position: static;
+ }
+
</style>
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture">
-<div id="elem" class="test">
-</div>
-<div class="hidden test">
- <div>.</div>
-</div>
-<div class="animateClass test">
- <h2>Child Element Test</h2>
-</div>
-<div class="relWidth relHeight testAddBorder">
- <h2>Slide with relative width</h2>
-</div>
-<div class="testScale">
-</div>
-<div class="ticket7106">
-</div>
-
+ <div id="elem" class="test"></div>
+ <div class="hidden test">
+ <div>.</div>
+ </div>
+ <div class="animateClass test">
+ <h2>Child Element Test</h2>
+ </div>
+ <div class="relWidth relHeight testAddBorder">
+ <h2>Slide with relative width</h2>
+ </div>
+ <div class="testScale"></div>
+ <div class="ticket7106"></div>
+ <div class="relative"></div>
+ <div class="absolute"></div>
+ <div class="fixed"></div>
+ <div class="static"></div>
</div>
</body>
</html>
(function($) {
function present( value, array, message ) {
- QUnit.push( jQuery.inArray( value, array ) !== -1 , value, array, message );
+ QUnit.push( jQuery.inArray( value, array ) !== -1, value, array, message );
}
function notPresent( value, array, message ) {
- QUnit.push( jQuery.inArray( value, array ) === -1 , value, array, message );
+ QUnit.push( jQuery.inArray( value, array ) === -1, value, array, message );
}
// minDuration is used for "short" animate tests where we are only concerned about the final
equal( "", element[ 0 ].className );
});
-
-/* TODO: Disabled - Can't figure out why this is failing in IE 6/7
-test( "createWrapper and removeWrapper retain focused elements (#7595)", function() {
- expect( 2 );
- var test = $( "div.hidden" ).show(),
- input = $( "<input type='text'>" ).appendTo( test ).focus();
-
- $.effects.createWrapper( test );
- equal( document.activeElement, input[ 0 ], "Active element is still input after createWrapper" );
- $.effects.removeWrapper( test );
- equal( document.activeElement, input[ 0 ], "Active element is still input after removeWrapper" );
-});
-*/
-
module( "effects.core: animateClass" );
asyncTest( "animateClass works with borderStyle", function() {
.height( 100 );
});
+test( "createPlaceholder: only created for static or relative elements", function() {
+ expect( 4 );
+
+ ok( $.effects.createPlaceholder( $( ".relative" ) ).length, "placeholder created for relative element" );
+ ok( $.effects.createPlaceholder( $( ".static" ) ).length, "placeholder created for static element" );
+ ok( !$.effects.createPlaceholder( $( ".absolute" ) ), "placeholder not created for absolute element" );
+ ok( !$.effects.createPlaceholder( $( ".fixed" ) ), "placeholder not created for fixed element" );
+});
+
+test( "createPlaceholder: preserves layout affecting properties", function() {
+ expect( 7 );
+
+ var position = 5,
+ element = $( ".relative" ).css({
+ top: position,
+ left: position
+ }),
+ before = {
+ offset: element.offset(),
+ outerWidth: element.outerWidth( true ),
+ outerHeight: element.outerHeight( true ),
+ "float": element.css( "float" ),
+ position: element.position()
+ },
+ placeholder = $.effects.createPlaceholder( element );
+
+ // Placeholders are only placed to preserve the effect on layout. Considering
+ // top and left do not change layout, they are not preserved, which makes some
+ // of the math simpler in the implementation.
+ deepEqual( before.offset.top - position, placeholder.offset().top, "offset top preserved" );
+ deepEqual( before.offset.left - position, placeholder.offset().left, "offset left preserved" );
+ deepEqual( before.position.top - position, placeholder.position().top, "position top preserved" );
+ deepEqual( before.position.left - position, placeholder.position().left, "position left preserved" );
+
+ deepEqual( before[ "float" ], placeholder.css( "float" ), "float preserved" );
+ deepEqual( before.outerWidth, placeholder.outerWidth( true ), "width preserved" );
+ deepEqual( before.outerHeight, placeholder.outerHeight( true ), "height preserved" );
+});
$.each( $.effects.effect, function( effect ) {
module( "effects." + effect );
return;
}
asyncTest( "show/hide", function() {
- expect( 8 );
+ expect( 12 );
var hidden = $( "div.hidden" ),
count = 0,
test = 0;
};
}
- hidden.queue( queueTest() ).show( effect, minDuration, queueTest(function() {
- equal( hidden.css("display"), "block", "Hidden is shown after .show(\"" +effect+ "\", time)" );
- })).queue( queueTest() ).hide( effect, minDuration, queueTest(function() {
- equal( hidden.css("display"), "none", "Back to hidden after .hide(\"" +effect+ "\", time)" );
- })).queue( queueTest(function() {
- deepEqual( hidden.queue(), ["inprogress"], "Only the inprogress sentinel remains");
- start();
- }));
+ function duringTest( fn ) {
+ return function( next ) {
+ setTimeout( fn );
+ next();
+ };
+ }
+
+ hidden
+ .queue( queueTest() )
+ .queue( duringTest(function() {
+ ok( hidden.is( ":animated" ),
+ "Hidden is seen as animated during .show(\"" + effect + "\", time)" );
+ }) )
+ .show( effect, minDuration, queueTest(function() {
+ equal( hidden.css( "display" ), "block",
+ "Hidden is shown after .show(\"" + effect + "\", time)" );
+ ok( !$( ".ui-effects-placeholder" ).length,
+ "No placeholder remains after .show(\"" + effect + "\", time)" );
+ }) )
+ .queue( queueTest() )
+ .queue( duringTest(function() {
+ ok( hidden.is( ":animated" ),
+ "Hidden is seen as animated during .hide(\"" + effect + "\", time)" );
+ }) )
+ .hide( effect, minDuration, queueTest(function() {
+ equal( hidden.css( "display" ), "none",
+ "Back to hidden after .hide(\"" + effect + "\", time)" );
+ ok( !$( ".ui-effects-placeholder" ).length,
+ "No placeholder remains after .hide(\"" + effect + "\", time)" );
+ }) )
+ .queue( queueTest(function() {
+ deepEqual( hidden.queue(), [ "inprogress" ], "Only the inprogress sentinel remains" );
+ start();
+ }) );
});
asyncTest( "relative width & height - properties are preserved", function() {
asyncTest( desc, function() {
expect( 2 );
function complete() {
- equal( parseInt( test.css( h ), 10 ), target[ h ], "Horizontal Position Correct " + desc );
- equal( parseInt( test.css( v ), 10 ), target[ v ], "Vertical Position Correct " + desc );
+ closeEnough( parseInt( test.css( h ), 10 ), target[ h ], 1, "Horizontal Position Correct " + desc );
+ closeEnough( parseInt( test.css( v ), 10 ), target[ v ], 1, "Vertical Position Correct " + desc );
start();
}
var test = $( ".testScale" ),
<script src="../../../ui/effect-fade.js"></script>
<script src="../../../ui/effect-fold.js"></script>
<script src="../../../ui/effect-highlight.js"></script>
+ <script src="../../../ui/effect-puff.js"></script>
<script src="../../../ui/effect-pulsate.js"></script>
<script src="../../../ui/effect-scale.js"></script>
+ <script src="../../../ui/effect-size.js"></script>
<script src="../../../ui/effect-shake.js"></script>
<script src="../../../ui/effect-slide.js"></script>
<script src="../../../ui/effect-transfer.js"></script>
<p>EXPECTED: Clicking "Toggle" or "Effect Toggle" a second time reverses the animation, first showing all elements at their original dimensions, and restoring them to their original state.</p>
<p>EXPECTED: Clicking "Effect Default" should always perform a "hide" animation.</p>
<p>EXPECTED: Clicking any of the buttons in quick succession should queue the relevant animations.</p>
+<p>EXPECTED CANTFIX: In IE8, the clip animation jumps due to a bug that causes .css('clip') to return undefined unless the clip property is an inline style.</p>
<div class="container">
<button class="toggle">Toggle</button>
<p>Jerky corned beef short loin fatback jowl tail. Rump spare ribs shoulder pork belly. Sausage cow ground round bacon. Bresaola kielbasa pastrami brisket ham hock. Andouille kielbasa ham, pork beef tenderloin ground round beef ribs flank turkey pancetta tri-tip.</p>
<div class="column">
<p>Shankle filet mignon ribeye chicken, bacon jowl drumstick frankfurter swine short loin capicola leberkas tenderloin pig. Shankle bacon shank pork loin, shoulder ham drumstick biltong. Shankle ham pastrami ball tip turkey leberkas pork loin ground round. Chicken strip steak venison shoulder biltong ham. Bacon pork loin tenderloin kielbasa, prosciutto sausage leberkas jowl ribeye turducken. Flank short loin venison tenderloin spare ribs boudin, tongue pork chop shank sirloin. Ground round ham pork belly, corned beef jowl strip steak short ribs prosciutto pig bresaola spare ribs.</p>
- <img class="target" style="margin: 10px 20px 30px 40px;" src="../../images/jquery_521x191.png" alt="jQuery Logo">
+ <img class="target margin" src="../../images/jquery_521x191.png" alt="jQuery Logo">
<p>Pork loin biltong ball tip tail jerky beef ribs prosciutto short loin turducken. Turkey chicken jowl pork loin shank tri-tip swine brisket. Doner prosciutto leberkas venison ground round, short loin capicola hamburger pork bacon. Spare ribs beef pork tenderloin rump shoulder pork belly turducken cow beef ribs pastrami tail flank. Spare ribs tri-tip shank, pork beef ribs ribeye chicken bacon boudin shoulder venison. Sirloin beef ribs boudin, andouille doner tail ball tip biltong prosciutto chicken beef turkey tongue hamburger tri-tip.</p>
</div>
<p>Doner salami jowl beef ribs. Pork chop beef short loin pork, kielbasa tail andouille salami sausage meatball short ribs t-bone tri-tip ham. Meatball short ribs prosciutto flank chicken fatback frankfurter brisket turducken. Corned beef hamburger swine short ribs pancetta. Jerky bresaola pork chuck spare ribs pastrami shoulder flank chicken leberkas beef.</p>
effect( "#pulsate", "pulsate", { times: 2 } );
-effect( "#puff", "puff", { times: 2 } );
+effect( "#puff", "puff", {} );
effect( "#scale", "scale", {} );
effect( "#size", "size", {} );
$( "#sizeToggle" ).click(function() {
<h2>Effects</h2>
<ul>
<li><a href="effects/all.html">All</a></li>
+ <li><a href="effects/clip.html">Clip</a></li>
<li><a href="effects/scale.html">Scale</a></li>
<li><a href="effects/shake.html">Shake</a></li>
</ul>
}
}(function( $ ) {
-return $.effects.effect.blind = function( o, done ) {
- // Create element
- var el = $( this ),
- rvertical = /up|down|vertical/,
- rpositivemotion = /up|left|vertical|horizontal/,
- props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
- mode = $.effects.setMode( el, o.mode || "hide" ),
- direction = o.direction || "up",
- vertical = rvertical.test( direction ),
- ref = vertical ? "height" : "width",
- ref2 = vertical ? "top" : "left",
- motion = rpositivemotion.test( direction ),
- animation = {},
- show = mode === "show",
- wrapper, distance, margin;
+return $.effects.define( "blind", "hide", function( options, done ) {
+ var map = {
+ up: [ "bottom", "top" ],
+ vertical: [ "bottom", "top" ],
+ down: [ "top", "bottom" ],
+ left: [ "right", "left" ],
+ horizontal: [ "right", "left" ],
+ right: [ "left", "right" ]
+ },
+ element = $( this ),
+ direction = options.direction || "up",
+ start = element.cssClip(),
+ animate = { clip: $.extend( {}, start ) },
+ placeholder = $.effects.createPlaceholder( element );
- // if already wrapped, the wrapper's properties are my property. #6245
- if ( el.parent().is( ".ui-effects-wrapper" ) ) {
- $.effects.save( el.parent(), props );
- } else {
- $.effects.save( el, props );
- }
- el.show();
- wrapper = $.effects.createWrapper( el ).css({
- overflow: "hidden"
- });
-
- distance = wrapper[ ref ]();
- margin = parseFloat( wrapper.css( ref2 ) ) || 0;
+ animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
- animation[ ref ] = show ? distance : 0;
- if ( !motion ) {
- el
- .css( vertical ? "bottom" : "right", 0 )
- .css( vertical ? "top" : "left", "auto" )
- .css({ position: "absolute" });
+ if ( options.mode === "show" ) {
+ element.cssClip( animate.clip );
+ if ( placeholder ) {
+ placeholder.css( $.effects.clipToBox( animate ) );
+ }
- animation[ ref2 ] = show ? margin : distance + margin;
+ animate.clip = start;
}
- // start at 0 if we are showing
- if ( show ) {
- wrapper.css( ref, 0 );
- if ( !motion ) {
- wrapper.css( ref2, margin + distance );
- }
+ if ( placeholder ) {
+ placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
}
- // Animate
- wrapper.animate( animation, {
- duration: o.duration,
- easing: o.easing,
+ element.animate( animate, {
queue: false,
- complete: function() {
- if ( mode === "hide" ) {
- el.hide();
- }
- $.effects.restore( el, props );
- $.effects.removeWrapper( el );
- done();
- }
+ duration: options.duration,
+ easing: options.easing,
+ complete: done
});
-};
+});
}));
}
}(function( $ ) {
-return $.effects.effect.bounce = function( o, done ) {
- var el = $( this ),
- props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
+return $.effects.define( "bounce", function( options, done ) {
+ var upAnim, downAnim, refValue,
+ element = $( this ),
// defaults:
- mode = $.effects.setMode( el, o.mode || "effect" ),
+ mode = options.mode,
hide = mode === "hide",
show = mode === "show",
- direction = o.direction || "up",
- distance = o.distance,
- times = o.times || 5,
+ direction = options.direction || "up",
+ distance = options.distance,
+ times = options.times || 5,
// number of internal animations
anims = times * 2 + ( show || hide ? 1 : 0 ),
- speed = o.duration / anims,
- easing = o.easing,
+ speed = options.duration / anims,
+ easing = options.easing,
// utility:
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
motion = ( direction === "up" || direction === "left" ),
- i,
- upAnim,
- downAnim,
+ i = 0,
- // we will need to re-assemble the queue to stack our animations in place
- queue = el.queue(),
- queuelen = queue.length;
+ queuelen = element.queue().length;
- // Avoid touching opacity to prevent clearType and PNG issues in IE
- if ( show || hide ) {
- props.push( "opacity" );
- }
+ $.effects.createPlaceholder( element );
- $.effects.save( el, props );
- el.show();
- $.effects.createWrapper( el ); // Create Wrapper
+ refValue = element.css( ref );
// default distance for the BIGGEST bounce is the outer Distance / 3
if ( !distance ) {
- distance = el[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
+ distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
}
if ( show ) {
downAnim = { opacity: 1 };
- downAnim[ ref ] = 0;
+ downAnim[ ref ] = refValue;
// if we are showing, force opacity 0 and set the initial position
// then do the "first" animation
- el.css( "opacity", 0 )
+ element
+ .css( "opacity", 0 )
.css( ref, motion ? -distance * 2 : distance * 2 )
.animate( downAnim, speed, easing );
}
}
downAnim = {};
- downAnim[ ref ] = 0;
+ downAnim[ ref ] = refValue;
// Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
- for ( i = 0; i < times; i++ ) {
+ for ( ; i < times; i++ ) {
upAnim = {};
upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
- el.animate( upAnim, speed, easing )
+ element
+ .animate( upAnim, speed, easing )
.animate( downAnim, speed, easing );
distance = hide ? distance * 2 : distance / 2;
upAnim = { opacity: 0 };
upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
- el.animate( upAnim, speed, easing );
+ element.animate( upAnim, speed, easing );
}
- el.queue(function() {
- if ( hide ) {
- el.hide();
- }
- $.effects.restore( el, props );
- $.effects.removeWrapper( el );
- done();
- });
-
- // inject all the animations we just queued to be first in line (after "inprogress")
- if ( queuelen > 1) {
- queue.splice.apply( queue,
- [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
- }
- el.dequeue();
+ element.queue( done );
-};
+ $.effects.unshift( element, queuelen, anims + 1 );
+});
}));
}
}(function( $ ) {
-return $.effects.effect.clip = function( o, done ) {
- // Create element
- var el = $( this ),
- props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
- mode = $.effects.setMode( el, o.mode || "hide" ),
- show = mode === "show",
- direction = o.direction || "vertical",
- vert = direction === "vertical",
- size = vert ? "height" : "width",
- position = vert ? "top" : "left",
- animation = {},
- wrapper, animate, distance;
+return $.effects.define( "clip", "hide", function( options, done ) {
+ var start,
+ animate = {},
+ element = $( this ),
+ direction = options.direction || "vertical",
+ both = direction === "both",
+ horizontal = both || direction === "horizontal",
+ vertical = both || direction === "vertical";
- // Save & Show
- $.effects.save( el, props );
- el.show();
+ start = element.cssClip();
+ animate.clip = {
+ top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
+ right: horizontal ? ( start.right - start.left ) / 2 : start.right,
+ bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
+ left: horizontal ? ( start.right - start.left ) / 2 : start.left
+ };
- // Create Wrapper
- wrapper = $.effects.createWrapper( el ).css({
- overflow: "hidden"
- });
- animate = ( el[0].tagName === "IMG" ) ? wrapper : el;
- distance = animate[ size ]();
+ $.effects.createPlaceholder( element );
- // Shift
- if ( show ) {
- animate.css( size, 0 );
- animate.css( position, distance / 2 );
+ if ( options.mode === "show" ) {
+ element.cssClip( animate.clip );
+ animate.clip = start;
}
- // Create Animation Object:
- animation[ size ] = show ? distance : 0;
- animation[ position ] = show ? 0 : distance / 2;
-
- // Animate
- animate.animate( animation, {
+ element.animate( animate, {
queue: false,
- duration: o.duration,
- easing: o.easing,
- complete: function() {
- if ( !show ) {
- el.hide();
- }
- $.effects.restore( el, props );
- $.effects.removeWrapper( el );
- done();
- }
+ duration: options.duration,
+ easing: options.easing,
+ complete: done
});
-};
+});
}));
}
}(function( $ ) {
-return $.effects.effect.drop = function( o, done ) {
+return $.effects.define( "drop", "hide", function( options, done ) {
- var el = $( this ),
- props = [ "position", "top", "bottom", "left", "right", "opacity", "height", "width" ],
- mode = $.effects.setMode( el, o.mode || "hide" ),
+ var distance,
+ element = $( this ),
+ mode = options.mode,
show = mode === "show",
- direction = o.direction || "left",
+ direction = options.direction || "left",
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
- motion = ( direction === "up" || direction === "left" ) ? "pos" : "neg",
+ motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
+ oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
animation = {
- opacity: show ? 1 : 0
- },
- distance;
+ opacity: 0
+ };
- // Adjust
- $.effects.save( el, props );
- el.show();
- $.effects.createWrapper( el );
+ $.effects.createPlaceholder( element );
- distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
+ distance = options.distance || element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
+
+ animation[ ref ] = motion + distance;
if ( show ) {
- el
- .css( "opacity", 0 )
- .css( ref, motion === "pos" ? -distance : distance );
- }
+ element.css( animation );
- // Animation
- animation[ ref ] = ( show ?
- ( motion === "pos" ? "+=" : "-=" ) :
- ( motion === "pos" ? "-=" : "+=" ) ) +
- distance;
+ animation[ ref ] = oppositeMotion + distance;
+ animation.opacity = 1;
+ }
// Animate
- el.animate( animation, {
+ element.animate( animation, {
queue: false,
- duration: o.duration,
- easing: o.easing,
- complete: function() {
- if ( mode === "hide" ) {
- el.hide();
- }
- $.effects.restore( el, props );
- $.effects.removeWrapper( el );
- done();
- }
+ duration: options.duration,
+ easing: options.easing,
+ complete: done
});
-};
+});
}));
}
}(function( $ ) {
-return $.effects.effect.explode = function( o, done ) {
+return $.effects.define( "explode", "hide", function( options, done ) {
- var rows = o.pieces ? Math.round( Math.sqrt( o.pieces ) ) : 3,
+ var i, j, left, top, mx, my,
+ rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
cells = rows,
- el = $( this ),
- mode = $.effects.setMode( el, o.mode || "hide" ),
+ element = $( this ),
+ mode = options.mode,
show = mode === "show",
// show and then visibility:hidden the element before calculating offset
- offset = el.show().css( "visibility", "hidden" ).offset(),
+ offset = element.show().css( "visibility", "hidden" ).offset(),
// width and height of a piece
- width = Math.ceil( el.outerWidth() / cells ),
- height = Math.ceil( el.outerHeight() / rows ),
- pieces = [],
-
- // loop
- i, j, left, top, mx, my;
+ width = Math.ceil( element.outerWidth() / cells ),
+ height = Math.ceil( element.outerHeight() / rows ),
+ pieces = [];
// children animate complete:
function childComplete() {
// Create a clone of the now hidden main element that will be absolute positioned
// within a wrapper div off the -left and -top equal to size of our pieces
- el
+ element
.clone()
.appendTo( "body" )
.wrap( "<div></div>" )
left: left + ( show ? 0 : mx * width ),
top: top + ( show ? 0 : my * height ),
opacity: show ? 1 : 0
- }, o.duration || 500, o.easing, childComplete );
+ }, options.duration || 500, options.easing, childComplete );
}
}
function animComplete() {
- el.css({
+ element.css({
visibility: "visible"
});
$( pieces ).remove();
- if ( !show ) {
- el.hide();
- }
done();
}
-};
+});
}));
}
}(function( $ ) {
-return $.effects.effect.fade = function( o, done ) {
- var el = $( this ),
- mode = $.effects.setMode( el, o.mode || "toggle" );
+return $.effects.define( "fade", "toggle", function( options, done ) {
+ var show = options.mode === "show";
- el.animate({
- opacity: mode
- }, {
- queue: false,
- duration: o.duration,
- easing: o.easing,
- complete: done
- });
-};
+ $( this )
+ .css( "opacity", show ? 0 : 1 )
+ .animate({
+ opacity: show ? 1 : 0
+ }, {
+ queue: false,
+ duration: options.duration,
+ easing: options.easing,
+ complete: done
+ });
+});
}));
}
}(function( $ ) {
-return $.effects.effect.fold = function( o, done ) {
+return $.effects.define( "fold", "hide", function( options, done ) {
// Create element
- var el = $( this ),
- props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
- mode = $.effects.setMode( el, o.mode || "hide" ),
+ var element = $( this ),
+ mode = options.mode,
show = mode === "show",
hide = mode === "hide",
- size = o.size || 15,
+ size = options.size || 15,
percent = /([0-9]+)%/.exec( size ),
- horizFirst = !!o.horizFirst,
- widthFirst = show !== horizFirst,
- ref = widthFirst ? [ "width", "height" ] : [ "height", "width" ],
- duration = o.duration / 2,
- wrapper, distance,
- animation1 = {},
- animation2 = {};
-
- $.effects.save( el, props );
- el.show();
-
- // Create Wrapper
- wrapper = $.effects.createWrapper( el ).css({
- overflow: "hidden"
- });
- distance = widthFirst ?
- [ wrapper.width(), wrapper.height() ] :
- [ wrapper.height(), wrapper.width() ];
+ horizFirst = !!options.horizFirst,
+ ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
+ duration = options.duration / 2,
+
+ placeholder = $.effects.createPlaceholder( element ),
+
+ start = element.cssClip(),
+ animation1 = { clip: $.extend( {}, start ) },
+ animation2 = { clip: $.extend( {}, start ) },
+
+ distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
+
+ queuelen = element.queue().length;
if ( percent ) {
size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
}
+ animation1.clip[ ref[ 0 ] ] = size;
+ animation2.clip[ ref[ 0 ] ] = size;
+ animation2.clip[ ref[ 1 ] ] = 0;
+
if ( show ) {
- wrapper.css( horizFirst ? {
- height: 0,
- width: size
- } : {
- height: size,
- width: 0
- });
- }
+ element.cssClip( animation2.clip );
+ if ( placeholder ) {
+ placeholder.css( $.effects.clipToBox( animation2 ) );
+ }
- // Animation
- animation1[ ref[ 0 ] ] = show ? distance[ 0 ] : size;
- animation2[ ref[ 1 ] ] = show ? distance[ 1 ] : 0;
+ animation2.clip = start;
+ }
// Animate
- wrapper
- .animate( animation1, duration, o.easing )
- .animate( animation2, duration, o.easing, function() {
- if ( hide ) {
- el.hide();
+ element
+ .queue(function( next ) {
+ if ( placeholder ) {
+ placeholder
+ .animate( $.effects.clipToBox( animation1 ), duration, options.easing )
+ .animate( $.effects.clipToBox( animation2 ), duration, options.easing );
}
- $.effects.restore( el, props );
- $.effects.removeWrapper( el );
- done();
- });
-};
+ next();
+ })
+ .animate( animation1, duration, options.easing )
+ .animate( animation2, duration, options.easing )
+ .queue( done );
+
+ $.effects.unshift( element, queuelen, 4 );
+});
}));
}
}(function( $ ) {
-return $.effects.effect.highlight = function( o, done ) {
- var elem = $( this ),
- props = [ "backgroundImage", "backgroundColor", "opacity" ],
- mode = $.effects.setMode( elem, o.mode || "show" ),
+return $.effects.define( "highlight", "show", function( options, done ) {
+ var element = $( this ),
animation = {
- backgroundColor: elem.css( "backgroundColor" )
+ backgroundColor: element.css( "backgroundColor" )
};
- if (mode === "hide") {
+ if ( options.mode === "hide" ) {
animation.opacity = 0;
}
- $.effects.save( elem, props );
+ $.effects.saveStyle( element );
- elem
- .show()
+ element
.css({
backgroundImage: "none",
- backgroundColor: o.color || "#ffff99"
+ backgroundColor: options.color || "#ffff99"
})
.animate( animation, {
queue: false,
- duration: o.duration,
- easing: o.easing,
- complete: function() {
- if ( mode === "hide" ) {
- elem.hide();
- }
- $.effects.restore( elem, props );
- done();
- }
+ duration: options.duration,
+ easing: options.easing,
+ complete: done
});
-};
+});
}));
}
}(function( $ ) {
-return $.effects.effect.puff = function( o, done ) {
- var elem = $( this ),
- mode = $.effects.setMode( elem, o.mode || "hide" ),
- hide = mode === "hide",
- percent = parseInt( o.percent, 10 ) || 150,
- factor = percent / 100,
- original = {
- height: elem.height(),
- width: elem.width(),
- outerHeight: elem.outerHeight(),
- outerWidth: elem.outerWidth()
- };
-
- $.extend( o, {
- effect: "scale",
- queue: false,
+return $.effects.define( "puff", "hide", function( options, done ) {
+ var newOptions = $.extend( true, {}, options, {
fade: true,
- mode: mode,
- complete: done,
- percent: hide ? percent : 100,
- from: hide ?
- original :
- {
- height: original.height * factor,
- width: original.width * factor,
- outerHeight: original.outerHeight * factor,
- outerWidth: original.outerWidth * factor
- }
+ percent: parseInt( options.percent, 10 ) || 150
});
- elem.effect( o );
-};
+ $.effects.effect.scale.call( this, newOptions, done );
+});
}));
}
}(function( $ ) {
-return $.effects.effect.pulsate = function( o, done ) {
- var elem = $( this ),
- mode = $.effects.setMode( elem, o.mode || "show" ),
+return $.effects.define( "pulsate", "show", function( options, done ) {
+ var element = $( this ),
+ mode = options.mode,
show = mode === "show",
hide = mode === "hide",
- showhide = ( show || mode === "hide" ),
+ showhide = show || hide,
- // showing or hiding leaves of the "last" animation
- anims = ( ( o.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
- duration = o.duration / anims,
+ // Showing or hiding leaves off the "last" animation
+ anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
+ duration = options.duration / anims,
animateTo = 0,
- queue = elem.queue(),
- queuelen = queue.length,
- i;
+ i = 1,
+ queuelen = element.queue().length;
- if ( show || !elem.is(":visible")) {
- elem.css( "opacity", 0 ).show();
+ if ( show || !element.is( ":visible" ) ) {
+ element.css( "opacity", 0 ).show();
animateTo = 1;
}
- // anims - 1 opacity "toggles"
- for ( i = 1; i < anims; i++ ) {
- elem.animate({
- opacity: animateTo
- }, duration, o.easing );
+ // Anims - 1 opacity "toggles"
+ for ( ; i < anims; i++ ) {
+ element.animate( { opacity: animateTo }, duration, options.easing );
animateTo = 1 - animateTo;
}
- elem.animate({
- opacity: animateTo
- }, duration, o.easing);
+ element.animate( { opacity: animateTo }, duration, options.easing );
- elem.queue(function() {
- if ( hide ) {
- elem.hide();
- }
- done();
- });
+ element.queue( done );
- // We just queued up "anims" animations, we need to put them next in the queue
- if ( queuelen > 1 ) {
- queue.splice.apply( queue,
- [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
- }
- elem.dequeue();
-};
+ $.effects.unshift( element, queuelen, anims + 1 );
+});
}));
}
}(function( $ ) {
-return $.effects.effect.scale = function( o, done ) {
+return $.effects.define( "scale", function( options, done ) {
// Create element
var el = $( this ),
- options = $.extend( true, {}, o ),
- mode = $.effects.setMode( el, o.mode || "effect" ),
- percent = parseInt( o.percent, 10 ) ||
- ( parseInt( o.percent, 10 ) === 0 ? 0 : ( mode === "hide" ? 0 : 100 ) ),
- direction = o.direction || "both",
- origin = o.origin,
- original = {
- height: el.height(),
- width: el.width(),
- outerHeight: el.outerHeight(),
- outerWidth: el.outerWidth()
- },
- factor = {
- y: direction !== "horizontal" ? (percent / 100) : 1,
- x: direction !== "vertical" ? (percent / 100) : 1
- };
+ mode = options.mode,
+ percent = parseInt( options.percent, 10 ) ||
+ ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
- // We are going to pass this effect to the size effect:
- options.effect = "size";
- options.queue = false;
- options.complete = done;
-
- // Set default origin and restore for show/hide
- if ( mode !== "effect" ) {
- options.origin = origin || [ "middle", "center" ];
- options.restore = true;
- }
-
- options.from = o.from || ( mode === "show" ? {
- height: 0,
- width: 0,
- outerHeight: 0,
- outerWidth: 0
- } : original );
- options.to = {
- height: original.height * factor.y,
- width: original.width * factor.x,
- outerHeight: original.outerHeight * factor.y,
- outerWidth: original.outerWidth * factor.x
- };
+ newOptions = $.extend( true, {
+ from: $.effects.scaledDimensions( el ),
+ to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
+ origin: options.origin || [ "middle", "center" ]
+ }, options );
// Fade option to support puff
if ( options.fade ) {
- if ( mode === "show" ) {
- options.from.opacity = 0;
- options.to.opacity = 1;
- }
- if ( mode === "hide" ) {
- options.from.opacity = 1;
- options.to.opacity = 0;
- }
+ newOptions.from.opacity = 1;
+ newOptions.to.opacity = 0;
}
- // Animate
- el.effect( options );
-
-};
+ $.effects.effect.size.call( this, newOptions, done );
+});
}));
}
}(function( $ ) {
-return $.effects.effect.shake = function( o, done ) {
+return $.effects.define( "shake", function( options, done ) {
- var el = $( this ),
- props = [ "position", "top", "bottom", "left", "right", "height", "width" ],
- mode = $.effects.setMode( el, o.mode || "effect" ),
- direction = o.direction || "left",
- distance = o.distance || 20,
- times = o.times || 3,
+ var i = 1,
+ element = $( this ),
+ direction = options.direction || "left",
+ distance = options.distance || 20,
+ times = options.times || 3,
anims = times * 2 + 1,
- speed = Math.round( o.duration / anims ),
- ref = (direction === "up" || direction === "down") ? "top" : "left",
- positiveMotion = (direction === "up" || direction === "left"),
+ speed = Math.round( options.duration / anims ),
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ positiveMotion = ( direction === "up" || direction === "left" ),
animation = {},
animation1 = {},
animation2 = {},
- i,
- // we will need to re-assemble the queue to stack our animations in place
- queue = el.queue(),
- queuelen = queue.length;
+ queuelen = element.queue().length;
- $.effects.save( el, props );
- el.show();
- $.effects.createWrapper( el );
+ $.effects.createPlaceholder( element );
// Animation
animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
// Animate
- el.animate( animation, speed, o.easing );
+ element.animate( animation, speed, options.easing );
// Shakes
- for ( i = 1; i < times; i++ ) {
- el.animate( animation1, speed, o.easing ).animate( animation2, speed, o.easing );
+ for ( ; i < times; i++ ) {
+ element.animate( animation1, speed, options.easing ).animate( animation2, speed, options.easing );
}
- el
- .animate( animation1, speed, o.easing )
- .animate( animation, speed / 2, o.easing )
- .queue(function() {
- if ( mode === "hide" ) {
- el.hide();
- }
- $.effects.restore( el, props );
- $.effects.removeWrapper( el );
- done();
- });
- // inject all the animations we just queued to be first in line (after "inprogress")
- if ( queuelen > 1) {
- queue.splice.apply( queue,
- [ 1, 0 ].concat( queue.splice( queuelen, anims + 1 ) ) );
- }
- el.dequeue();
+ element
+ .animate( animation1, speed, options.easing )
+ .animate( animation, speed / 2, options.easing )
+ .queue( done );
-};
+ $.effects.unshift( element, queuelen, anims + 1 );
+});
}));
}
}(function( $ ) {
-return $.effects.effect.size = function( o, done ) {
+return $.effects.define( "size", function( options, done ) {
// Create element
- var original, baseline, factor,
- el = $( this ),
- props0 = [ "position", "top", "bottom", "left", "right", "width", "height", "overflow", "opacity" ],
-
- // Always restore
- props1 = [ "position", "top", "bottom", "left", "right", "overflow", "opacity" ],
+ var baseline, factor, temp,
+ element = $( this ),
// Copy for children
- props2 = [ "width", "height", "overflow" ],
cProps = [ "fontSize" ],
vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
// Set options
- mode = $.effects.setMode( el, o.mode || "effect" ),
- restore = o.restore || mode !== "effect",
- scale = o.scale || "both",
- origin = o.origin || [ "middle", "center" ],
- position = el.css( "position" ),
- props = restore ? props0 : props1,
- zero = {
- height: 0,
- width: 0,
- outerHeight: 0,
- outerWidth: 0
- };
+ mode = options.mode,
+ restore = mode !== "effect",
+ scale = options.scale || "both",
+ origin = options.origin || [ "middle", "center" ],
+ position = element.css( "position" ),
+ pos = element.position(),
+ original = $.effects.scaledDimensions( element ),
+ from = options.from || original,
+ to = options.to || $.effects.scaledDimensions( element, 0 );
+
+ $.effects.createPlaceholder( element );
if ( mode === "show" ) {
- el.show();
- }
- original = {
- height: el.height(),
- width: el.width(),
- outerHeight: el.outerHeight(),
- outerWidth: el.outerWidth()
- };
-
- if ( o.mode === "toggle" && mode === "show" ) {
- el.from = o.to || zero;
- el.to = o.from || original;
- } else {
- el.from = o.from || ( mode === "show" ? zero : original );
- el.to = o.to || ( mode === "hide" ? zero : original );
+ temp = from;
+ from = to;
+ to = temp;
}
// Set scaling factor
factor = {
from: {
- y: el.from.height / original.height,
- x: el.from.width / original.width
+ y: from.height / original.height,
+ x: from.width / original.width
},
to: {
- y: el.to.height / original.height,
- x: el.to.width / original.width
+ y: to.height / original.height,
+ x: to.width / original.width
}
};
// Vertical props scaling
if ( factor.from.y !== factor.to.y ) {
- props = props.concat( vProps );
- el.from = $.effects.setTransition( el, vProps, factor.from.y, el.from );
- el.to = $.effects.setTransition( el, vProps, factor.to.y, el.to );
+ from = $.effects.setTransition( element, vProps, factor.from.y, from );
+ to = $.effects.setTransition( element, vProps, factor.to.y, to );
}
// Horizontal props scaling
if ( factor.from.x !== factor.to.x ) {
- props = props.concat( hProps );
- el.from = $.effects.setTransition( el, hProps, factor.from.x, el.from );
- el.to = $.effects.setTransition( el, hProps, factor.to.x, el.to );
+ from = $.effects.setTransition( element, hProps, factor.from.x, from );
+ to = $.effects.setTransition( element, hProps, factor.to.x, to );
}
}
// Vertical props scaling
if ( factor.from.y !== factor.to.y ) {
- props = props.concat( cProps ).concat( props2 );
- el.from = $.effects.setTransition( el, cProps, factor.from.y, el.from );
- el.to = $.effects.setTransition( el, cProps, factor.to.y, el.to );
+ from = $.effects.setTransition( element, cProps, factor.from.y, from );
+ to = $.effects.setTransition( element, cProps, factor.to.y, to );
}
}
- $.effects.save( el, props );
- el.show();
- $.effects.createWrapper( el );
- el.css( "overflow", "hidden" ).css( el.from );
-
- // Adjust
- if (origin) { // Calculate baseline shifts
+ // Adjust the position properties based on the provided origin points
+ if ( origin ) {
baseline = $.effects.getBaseline( origin, original );
- el.from.top = ( original.outerHeight - el.outerHeight() ) * baseline.y;
- el.from.left = ( original.outerWidth - el.outerWidth() ) * baseline.x;
- el.to.top = ( original.outerHeight - el.to.outerHeight ) * baseline.y;
- el.to.left = ( original.outerWidth - el.to.outerWidth ) * baseline.x;
+ from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
+ from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
+ to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
+ to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
}
- el.css( el.from ); // set top & left
+ element.css( from );
- // Animate
- if ( scale === "content" || scale === "both" ) { // Scale the children
+ // Animate the children if desired
+ if ( scale === "content" || scale === "both" ) {
- // Add margins/font-size
- vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat(cProps);
+ vProps = vProps.concat([ "marginTop", "marginBottom" ]).concat( cProps );
hProps = hProps.concat([ "marginLeft", "marginRight" ]);
- props2 = props0.concat(vProps).concat(hProps);
- el.find( "*[width]" ).each( function() {
+ // Only animate children with width attributes specified
+ // TODO: is this right? should we include anything with css width specified as well
+ element.find( "*[width]" ).each( function() {
var child = $( this ),
- c_original = {
- height: child.height(),
- width: child.width(),
- outerHeight: child.outerHeight(),
- outerWidth: child.outerWidth()
+ childOriginal = $.effects.scaledDimensions( child ),
+ childFrom = {
+ height: childOriginal.height * factor.from.y,
+ width: childOriginal.width * factor.from.x,
+ outerHeight: childOriginal.outerHeight * factor.from.y,
+ outerWidth: childOriginal.outerWidth * factor.from.x
+ },
+ childTo = {
+ height: childOriginal.height * factor.to.y,
+ width: childOriginal.width * factor.to.x,
+ outerHeight: childOriginal.height * factor.to.y,
+ outerWidth: childOriginal.width * factor.to.x
};
- if (restore) {
- $.effects.save(child, props2);
- }
-
- child.from = {
- height: c_original.height * factor.from.y,
- width: c_original.width * factor.from.x,
- outerHeight: c_original.outerHeight * factor.from.y,
- outerWidth: c_original.outerWidth * factor.from.x
- };
- child.to = {
- height: c_original.height * factor.to.y,
- width: c_original.width * factor.to.x,
- outerHeight: c_original.height * factor.to.y,
- outerWidth: c_original.width * factor.to.x
- };
// Vertical props scaling
if ( factor.from.y !== factor.to.y ) {
- child.from = $.effects.setTransition( child, vProps, factor.from.y, child.from );
- child.to = $.effects.setTransition( child, vProps, factor.to.y, child.to );
+ childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
+ childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
}
// Horizontal props scaling
if ( factor.from.x !== factor.to.x ) {
- child.from = $.effects.setTransition( child, hProps, factor.from.x, child.from );
- child.to = $.effects.setTransition( child, hProps, factor.to.x, child.to );
+ childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
+ childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
+ }
+
+ if ( restore ) {
+ $.effects.saveStyle( child );
}
// Animate children
- child.css( child.from );
- child.animate( child.to, o.duration, o.easing, function() {
+ child.css( childFrom );
+ child.animate( childTo, options.duration, options.easing, function() {
// Restore children
if ( restore ) {
- $.effects.restore( child, props2 );
+ $.effects.restoreStyle( child );
}
});
});
}
// Animate
- el.animate( el.to, {
+ element.animate( to, {
queue: false,
- duration: o.duration,
- easing: o.easing,
+ duration: options.duration,
+ easing: options.easing,
complete: function() {
- if ( el.to.opacity === 0 ) {
- el.css( "opacity", el.from.opacity );
- }
- if ( mode === "hide" ) {
- el.hide();
+
+ var offset = element.offset();
+
+ if ( to.opacity === 0 ) {
+ element.css( "opacity", from.opacity );
}
- $.effects.restore( el, props );
+
if ( !restore ) {
+ element
+ .css( "position", position === "static" ? "relative" : position )
+ .offset( offset );
- // we need to calculate our new positioning based on the scaling
- if ( position === "static" ) {
- el.css({
- position: "relative",
- top: el.to.top,
- left: el.to.left
- });
- } else {
- $.each([ "top", "left" ], function( idx, pos ) {
- el.css( pos, function( _, str ) {
- var val = parseInt( str, 10 ),
- toRef = idx ? el.to.left : el.to.top;
-
- // if original was "auto", recalculate the new value from wrapper
- if ( str === "auto" ) {
- return toRef + "px";
- }
-
- return val + toRef + "px";
- });
- });
- }
+ // Need to save style here so that automatic style restoration
+ // doesn't restore to the original styles from before the animation.
+ $.effects.saveStyle( element );
}
- $.effects.removeWrapper( el );
done();
}
});
-};
+});
}));
}
}(function( $ ) {
-return $.effects.effect.slide = function( o, done ) {
-
- // Create element
- var el = $( this ),
- props = [ "position", "top", "bottom", "left", "right", "width", "height" ],
- mode = $.effects.setMode( el, o.mode || "show" ),
- show = mode === "show",
- direction = o.direction || "left",
- ref = (direction === "up" || direction === "down") ? "top" : "left",
- positiveMotion = (direction === "up" || direction === "left"),
- distance,
+return $.effects.define( "slide", "show", function( options, done ) {
+ var startClip, startRef,
+ element = $( this ),
+ map = {
+ up: [ "bottom", "top" ],
+ down: [ "top", "bottom" ],
+ left: [ "right", "left" ],
+ right: [ "left", "right" ]
+ },
+ mode = options.mode,
+ direction = options.direction || "left",
+ ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
+ positiveMotion = ( direction === "up" || direction === "left" ),
+ distance = options.distance || element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
animation = {};
- // Adjust
- $.effects.save( el, props );
- el.show();
- distance = o.distance || el[ ref === "top" ? "outerHeight" : "outerWidth" ]( true );
+ $.effects.createPlaceholder( element );
- $.effects.createWrapper( el ).css({
- overflow: "hidden"
- });
+ startClip = element.cssClip();
+ startRef = element.position()[ ref ];
- if ( show ) {
- el.css( ref, positiveMotion ? (isNaN(distance) ? "-" + distance : -distance) : distance );
- }
+ // Define hide animation
+ animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
+ animation.clip = element.cssClip();
+ animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
- // Animation
- animation[ ref ] = ( show ?
- ( positiveMotion ? "+=" : "-=") :
- ( positiveMotion ? "-=" : "+=")) +
- distance;
+ // Reverse the animation if we're showing
+ if ( mode === "show" ) {
+ element.cssClip( animation.clip );
+ element.css( ref, animation[ ref ] );
+ animation.clip = startClip;
+ animation[ ref ] = startRef;
+ }
- // Animate
- el.animate( animation, {
+ // Actually animate
+ element.animate( animation, {
queue: false,
- duration: o.duration,
- easing: o.easing,
- complete: function() {
- if ( mode === "hide" ) {
- el.hide();
- }
- $.effects.restore( el, props );
- $.effects.removeWrapper( el );
- done();
- }
+ duration: options.duration,
+ easing: options.easing,
+ complete: done
});
-};
+});
}));
}
}(function( $ ) {
-return $.effects.effect.transfer = function( o, done ) {
- var elem = $( this ),
- target = $( o.to ),
- targetFixed = target.css( "position" ) === "fixed",
- body = $("body"),
- fixTop = targetFixed ? body.scrollTop() : 0,
- fixLeft = targetFixed ? body.scrollLeft() : 0,
- endPosition = target.offset(),
- animation = {
- top: endPosition.top - fixTop,
- left: endPosition.left - fixLeft,
- height: target.innerHeight(),
- width: target.innerWidth()
- },
- startPosition = elem.offset(),
- transfer = $( "<div class='ui-effects-transfer'></div>" )
- .appendTo( document.body )
- .addClass( o.className )
- .css({
- top: startPosition.top - fixTop,
- left: startPosition.left - fixLeft,
- height: elem.innerHeight(),
- width: elem.innerWidth(),
- position: targetFixed ? "fixed" : "absolute"
- })
- .animate( animation, o.duration, o.easing, function() {
- transfer.remove();
- done();
- });
-};
+if ( $.uiBackCompat !== false ) {
+ return $.effects.define( "transfer", function( options, done ) {
+ $( this ).transfer( options, done );
+ });
+}
}));
}(function( $ ) {
var dataSpace = "ui-effects-",
+ dataSpaceStyle = "ui-effects-style",
+ dataSpaceAnimated = "ui-effects-animated",
// Create a local jQuery because jQuery Color relies on it and the
// global may not exist with AMD and a custom build (#10199)
(function() {
+if ( $.expr && $.expr.filters && $.expr.filters.animated ) {
+ $.expr.filters.animated = (function( orig ) {
+ return function( elem ) {
+ return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
+ };
+ })( $.expr.filters.animated );
+}
+
+if ( $.uiBackCompat !== false ) {
+ $.extend( $.effects, {
+ // Saves a set of properties in a data storage
+ save: function( element, set ) {
+ var i = 0, length = set.length;
+ for ( ; i < length; i++ ) {
+ if ( set[ i ] !== null ) {
+ element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
+ }
+ }
+ },
+
+ // Restores a set of previously saved properties from a data storage
+ restore: function( element, set ) {
+ var val, i = 0, length = set.length;
+ for ( ; i < length; i++ ) {
+ if ( set[ i ] !== null ) {
+ val = element.data( dataSpace + set[ i ] );
+ // support: jQuery 1.6.2
+ // http://bugs.jquery.com/ticket/9917
+ // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
+ // We can't differentiate between "" and 0 here, so we just assume
+ // empty string since it's likely to be a more common value...
+ if ( val === undefined ) {
+ val = "";
+ }
+ element.css( set[ i ], val );
+ }
+ }
+ },
+
+ setMode: function( el, mode ) {
+ if ( mode === "toggle" ) {
+ mode = el.is( ":hidden" ) ? "show" : "hide";
+ }
+ return mode;
+ },
+
+ // Wraps the element around a wrapper that copies position properties
+ createWrapper: function( element ) {
+
+ // if the element is already wrapped, return it
+ if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+ return element.parent();
+ }
+
+ // wrap the element
+ var props = {
+ width: element.outerWidth( true ),
+ height: element.outerHeight( true ),
+ "float": element.css( "float" )
+ },
+ wrapper = $( "<div></div>" )
+ .addClass( "ui-effects-wrapper" )
+ .css({
+ fontSize: "100%",
+ background: "transparent",
+ border: "none",
+ margin: 0,
+ padding: 0
+ }),
+ // Store the size in case width/height are defined in % - Fixes #5245
+ size = {
+ width: element.width(),
+ height: element.height()
+ },
+ active = document.activeElement;
+
+ // support: Firefox
+ // Firefox incorrectly exposes anonymous content
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
+ try {
+ active.id;
+ } catch ( e ) {
+ active = document.body;
+ }
+
+ element.wrap( wrapper );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+
+ wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
+
+ // transfer positioning properties to the wrapper
+ if ( element.css( "position" ) === "static" ) {
+ wrapper.css({ position: "relative" });
+ element.css({ position: "relative" });
+ } else {
+ $.extend( props, {
+ position: element.css( "position" ),
+ zIndex: element.css( "z-index" )
+ });
+ $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
+ props[ pos ] = element.css( pos );
+ if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
+ props[ pos ] = "auto";
+ }
+ });
+ element.css({
+ position: "relative",
+ top: 0,
+ left: 0,
+ right: "auto",
+ bottom: "auto"
+ });
+ }
+ element.css(size);
+
+ return wrapper.css( props ).show();
+ },
+
+ removeWrapper: function( element ) {
+ var active = document.activeElement;
+
+ if ( element.parent().is( ".ui-effects-wrapper" ) ) {
+ element.parent().replaceWith( element );
+
+ // Fixes #7595 - Elements lose focus when wrapped.
+ if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
+ $( active ).focus();
+ }
+ }
+
+ return element;
+ }
+ });
+}
+
$.extend( $.effects, {
version: "@VERSION",
- // Saves a set of properties in a data storage
- save: function( element, set ) {
- for ( var i = 0; i < set.length; i++ ) {
- if ( set[ i ] !== null ) {
- element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
- }
+ define: function( name, mode, effect ) {
+ if ( !effect ) {
+ effect = mode;
+ mode = "effect";
}
+
+ $.effects.effect[ name ] = effect;
+ $.effects.effect[ name ].mode = mode;
+
+ return effect;
},
- // Restores a set of previously saved properties from a data storage
- restore: function( element, set ) {
- var val, i;
- for ( i = 0; i < set.length; i++ ) {
- if ( set[ i ] !== null ) {
- val = element.data( dataSpace + set[ i ] );
- // support: jQuery 1.6.2
- // http://bugs.jquery.com/ticket/9917
- // jQuery 1.6.2 incorrectly returns undefined for any falsy value.
- // We can't differentiate between "" and 0 here, so we just assume
- // empty string since it's likely to be a more common value...
- if ( val === undefined ) {
- val = "";
- }
- element.css( set[ i ], val );
- }
+ scaledDimensions: function( element, percent, direction ) {
+ if ( percent === 0 ) {
+ return {
+ height: 0,
+ width: 0,
+ outerHeight: 0,
+ outerWidth: 0
+ };
}
+
+ var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
+ y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
+
+ return {
+ height: element.height() * y,
+ width: element.width() * x,
+ outerHeight: element.outerHeight() * y,
+ outerWidth: element.outerWidth() * x
+ };
+
+ },
+
+ clipToBox: function( animation ) {
+ return {
+ width: animation.clip.right - animation.clip.left,
+ height: animation.clip.bottom - animation.clip.top,
+ left: animation.clip.left,
+ top: animation.clip.top
+ };
+ },
+
+ // Injects recently queued functions to be first in line (after "inprogress")
+ unshift: function( element, queueLength, count ) {
+ var queue = element.queue();
+
+ if ( queueLength > 1 ) {
+ queue.splice.apply( queue,
+ [ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
+ }
+ element.dequeue();
+ },
+
+ saveStyle: function( element ) {
+ element.data( dataSpaceStyle, element[ 0 ].style.cssText );
+ },
+
+ restoreStyle: function( element ) {
+ element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
+ element.removeData( dataSpaceStyle );
},
- setMode: function( el, mode ) {
- if (mode === "toggle") {
- mode = el.is( ":hidden" ) ? "show" : "hide";
+ mode: function( element, mode ) {
+ var hidden = element.is( ":hidden" );
+
+ if ( mode === "toggle" ) {
+ mode = hidden ? "show" : "hide";
+ }
+ if ( hidden ? mode === "hide" : mode === "show" ) {
+ mode = "none";
}
return mode;
},
// Translates a [top,left] array into a baseline value
- // this should be a little more flexible in the future to handle a string & hash
getBaseline: function( origin, original ) {
var y, x;
+
switch ( origin[ 0 ] ) {
- case "top": y = 0; break;
- case "middle": y = 0.5; break;
- case "bottom": y = 1; break;
- default: y = origin[ 0 ] / original.height;
+ case "top":
+ y = 0;
+ break;
+ case "middle":
+ y = 0.5;
+ break;
+ case "bottom":
+ y = 1;
+ break;
+ default:
+ y = origin[ 0 ] / original.height;
}
+
switch ( origin[ 1 ] ) {
- case "left": x = 0; break;
- case "center": x = 0.5; break;
- case "right": x = 1; break;
- default: x = origin[ 1 ] / original.width;
+ case "left":
+ x = 0;
+ break;
+ case "center":
+ x = 0.5;
+ break;
+ case "right":
+ x = 1;
+ break;
+ default:
+ x = origin[ 1 ] / original.width;
}
+
return {
x: x,
y: y
};
},
- // Wraps the element around a wrapper that copies position properties
- createWrapper: function( element ) {
-
- // if the element is already wrapped, return it
- if ( element.parent().is( ".ui-effects-wrapper" )) {
- return element.parent();
- }
-
- // wrap the element
- var props = {
- width: element.outerWidth(true),
- height: element.outerHeight(true),
+ // Creates a placeholder element so that the original element can be made absolute
+ createPlaceholder: function( element ) {
+ var placeholder,
+ cssPosition = element.css( "position" ),
+ position = element.position();
+
+ // Lock in margins first to account for form elements, which
+ // will change margin if you explicitly set height
+ // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
+ // Support: Safari
+ element.css({
+ marginTop: element.css( "marginTop" ),
+ marginBottom: element.css( "marginBottom" ),
+ marginLeft: element.css( "marginLeft" ),
+ marginRight: element.css( "marginRight" )
+ })
+ .outerWidth( element.outerWidth() )
+ .outerHeight( element.outerHeight() );
+
+ if ( /^(static|relative)/.test( cssPosition ) ) {
+ cssPosition = "absolute";
+
+ placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css({
+
+ // Convert inline to inline block to account for inline elements
+ // that turn to inline block based on content (like img)
+ display: /^(inline|ruby)/.test( element.css( "display" ) ) ? "inline-block" : "block",
+ visibility: "hidden",
+
+ // Margins need to be set to account for margin collapse
+ marginTop: element.css( "marginTop" ),
+ marginBottom: element.css( "marginBottom" ),
+ marginLeft: element.css( "marginLeft" ),
+ marginRight: element.css( "marginRight" ),
"float": element.css( "float" )
- },
- wrapper = $( "<div></div>" )
- .addClass( "ui-effects-wrapper" )
- .css({
- fontSize: "100%",
- background: "transparent",
- border: "none",
- margin: 0,
- padding: 0
- }),
- // Store the size in case width/height are defined in % - Fixes #5245
- size = {
- width: element.width(),
- height: element.height()
- },
- active = document.activeElement;
-
- // support: Firefox
- // Firefox incorrectly exposes anonymous content
- // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
- try {
- active.id;
- } catch ( e ) {
- active = document.body;
- }
+ })
+ .outerWidth( element.outerWidth() )
+ .outerHeight( element.outerHeight() )
+ .addClass( "ui-effects-placeholder" );
- element.wrap( wrapper );
-
- // Fixes #7595 - Elements lose focus when wrapped.
- if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
- $( active ).focus();
+ element.data( dataSpace + "placeholder", placeholder );
}
- wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element
-
- // transfer positioning properties to the wrapper
- if ( element.css( "position" ) === "static" ) {
- wrapper.css({ position: "relative" });
- element.css({ position: "relative" });
- } else {
- $.extend( props, {
- position: element.css( "position" ),
- zIndex: element.css( "z-index" )
- });
- $.each([ "top", "left", "bottom", "right" ], function(i, pos) {
- props[ pos ] = element.css( pos );
- if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
- props[ pos ] = "auto";
- }
- });
- element.css({
- position: "relative",
- top: 0,
- left: 0,
- right: "auto",
- bottom: "auto"
- });
- }
- element.css(size);
+ element.css({
+ position: cssPosition,
+ left: position.left,
+ top: position.top
+ });
- return wrapper.css( props ).show();
+ return placeholder;
},
- removeWrapper: function( element ) {
- var active = document.activeElement;
+ removePlaceholder: function( element ) {
+ var dataKey = dataSpace + "placeholder",
+ placeholder = element.data( dataKey );
- if ( element.parent().is( ".ui-effects-wrapper" ) ) {
- element.parent().replaceWith( element );
-
- // Fixes #7595 - Elements lose focus when wrapped.
- if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
- $( active ).focus();
- }
+ if ( placeholder ) {
+ placeholder.remove();
+ element.removeData( dataKey );
}
+ },
- return element;
+ // Removes a placeholder if it exists and restores
+ // properties that were modified during placeholder creation
+ cleanUp: function( element ) {
+ $.effects.restoreStyle( element );
+ $.effects.removePlaceholder( element );
},
setTransition: function( element, list, factor, value ) {
$.fn.extend({
effect: function( /* effect, options, speed, callback */ ) {
var args = _normalizeArguments.apply( this, arguments ),
- mode = args.mode,
+ effectMethod = $.effects.effect[ args.effect ],
+ defaultMode = effectMethod.mode,
queue = args.queue,
- effectMethod = $.effects.effect[ args.effect ];
+ queueName = queue || "fx",
+ complete = args.complete,
+ mode = args.mode,
+ modes = [],
+ prefilter = function( next ) {
+ var el = $( this ),
+ normalizedMode = $.effects.mode( el, mode ) || defaultMode;
+
+ // Sentinel for duck-punching the :animated psuedo-selector
+ el.data( dataSpaceAnimated, true );
+
+ // Save effect mode for later use,
+ // we can't just call $.effects.mode again later,
+ // as the .show() below destroys the initial state
+ modes.push( normalizedMode );
+
+ // See $.uiBackCompat inside of run() for removal of defaultMode in 1.13
+ if ( defaultMode && ( normalizedMode === "show" ||
+ ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
+ el.show();
+ }
+
+ if ( !defaultMode || normalizedMode !== "none" ) {
+ $.effects.saveStyle( el );
+ }
+
+ if ( $.isFunction( next ) ) {
+ next();
+ }
+ };
if ( $.fx.off || !effectMethod ) {
// delegate to the original method (e.g., .show()) if possible
if ( mode ) {
- return this[ mode ]( args.duration, args.complete );
+ return this[ mode ]( args.duration, complete );
} else {
return this.each( function() {
- if ( args.complete ) {
- args.complete.call( this );
+ if ( complete ) {
+ complete.call( this );
}
});
}
}
function run( next ) {
- var elem = $( this ),
- complete = args.complete,
- mode = args.mode;
+ var elem = $( this );
+
+ function cleanup() {
+ elem.removeData( dataSpaceAnimated );
+
+ $.effects.cleanUp( elem );
+
+ if ( args.mode === "hide" ) {
+ elem.hide();
+ }
+
+ done();
+ }
function done() {
if ( $.isFunction( complete ) ) {
- complete.call( elem[0] );
+ complete.call( elem[ 0 ] );
}
+
if ( $.isFunction( next ) ) {
next();
}
}
- // If the element already has the correct final state, delegate to
- // the core methods so the internal tracking of "olddisplay" works.
- if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
- elem[ mode ]();
- done();
+ // Override mode option on a per element basis,
+ // as toggle can be either show or hide depending on element state
+ args.mode = modes.shift();
+
+ if ( $.uiBackCompat !== false && !defaultMode ) {
+ if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
+
+ // Call the core method to track "olddisplay" properly
+ elem[ mode ]();
+ done();
+ } else {
+ effectMethod.call( elem[ 0 ], args, done );
+ }
} else {
- effectMethod.call( elem[0], args, done );
+ if ( args.mode === "none" ) {
+
+ // Call the core method to track "olddisplay" properly
+ elem[ mode ]();
+ done();
+ } else {
+ effectMethod.call( elem[ 0 ], args, cleanup );
+ }
}
}
- return queue === false ? this.each( run ) : this.queue( queue || "fx", run );
+ // Run prefilter on all elements first to ensure that
+ // any showing or hiding happens before placeholder creation,
+ // which ensures that any layout changes are correctly captured.
+ return queue === false ?
+ this.each( prefilter ).each( run ) :
+ this.queue( queueName, prefilter ).queue( queueName, run );
},
show: (function( orig ) {
};
})( $.fn.toggle ),
- // helper functions
cssUnit: function(key) {
var style = this.css( key ),
val = [];
}
});
return val;
+ },
+
+ cssClip: function( clipObj ) {
+ return clipObj ?
+ this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " + clipObj.bottom + "px " + clipObj.left + "px)" ) :
+ parseClip( this.css("clip"), this );
+ },
+
+ transfer: function( options, done ) {
+ var element = $( this ),
+ target = $( options.to ),
+ targetFixed = target.css( "position" ) === "fixed",
+ body = $( "body" ),
+ fixTop = targetFixed ? body.scrollTop() : 0,
+ fixLeft = targetFixed ? body.scrollLeft() : 0,
+ endPosition = target.offset(),
+ animation = {
+ top: endPosition.top - fixTop,
+ left: endPosition.left - fixLeft,
+ height: target.innerHeight(),
+ width: target.innerWidth()
+ },
+ startPosition = element.offset(),
+ transfer = $( "<div class='ui-effects-transfer'></div>" )
+ .appendTo( "body" )
+ .addClass( options.className )
+ .css({
+ top: startPosition.top - fixTop,
+ left: startPosition.left - fixLeft,
+ height: element.innerHeight(),
+ width: element.innerWidth(),
+ position: targetFixed ? "fixed" : "absolute"
+ })
+ .animate( animation, options.duration, options.easing, function() {
+ transfer.remove();
+ done();
+ });
}
});
+function parseClip( str, element ) {
+ var outerWidth = element.outerWidth(),
+ outerHeight = element.outerHeight(),
+ clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,
+ values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
+
+ return {
+ top: parseFloat( values[ 1 ] ) || 0,
+ right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
+ bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
+ left: parseFloat( values[ 4 ] ) || 0
+ };
+}
+
+$.fx.step.clip = function( fx ) {
+ if ( !fx.clipInit ) {
+ fx.start = $( fx.elem ).cssClip();
+ if ( typeof fx.end === "string" ) {
+ fx.end = parseClip( fx.end, fx.elem );
+ }
+ fx.clipInit = true;
+ }
+
+ $( fx.elem ).cssClip({
+ top: fx.pos * (fx.end.top - fx.start.top) + fx.start.top,
+ right: fx.pos * (fx.end.right - fx.start.right) + fx.start.right,
+ bottom: fx.pos * (fx.end.bottom - fx.start.bottom) + fx.start.bottom,
+ left: fx.pos * (fx.end.left - fx.start.left) + fx.start.left
+ });
+};
+
})();
/******************************************************************************/