From 8dcf7ec1ce05ab5e10207b0838be91181fd41fdc Mon Sep 17 00:00:00 2001 From: jaubourg Date: Sun, 8 May 2011 20:02:34 +0200 Subject: [PATCH] Adds addAfterFire flag. Unit tests updated with addAfterFire cases and also for when a callback returns false. --- src/callbacks.js | 27 ++++++++++++++++++----- test/unit/callbacks.js | 49 ++++++++++++++++++++++++++---------------- 2 files changed, 53 insertions(+), 23 deletions(-) diff --git a/src/callbacks.js b/src/callbacks.js index dc7e176f..f0c0ca38 100644 --- a/src/callbacks.js +++ b/src/callbacks.js @@ -40,6 +40,9 @@ function createFlags( flags ) { * * stopOnFalse: interrupt callings when a callback returns false * + * addAfterFire: if callbacks are added while firing, then they are not executed until after + * the next call to fire/fireWith + * */ jQuery.Callbacks = function( flags, filter ) { @@ -63,6 +66,8 @@ jQuery.Callbacks = function( flags, filter ) { firing, // First callback to fire (used internally by add and fireWith) firingStart, + // End of the loop when firing + firingLength, // Index of currently firing callback (modified by remove if needed) firingIndex, // Add a list of callbacks to the list @@ -101,9 +106,15 @@ jQuery.Callbacks = function( flags, filter ) { if ( list ) { var length = list.length; add( arguments ); + // Do we need to add the callbacks to the + // current firing batch? + if ( firing ) { + if ( !flags.addAfterFire ) { + firingLength = list.length; + } // With memory, if we're not firing then // we should call right away - if ( !firing && flags.memory && memory ) { + } else if ( flags.memory && memory ) { var tmp = memory; memory = undefined; firingStart = length; @@ -117,9 +128,14 @@ jQuery.Callbacks = function( flags, filter ) { if ( list ) { for ( var i = 0; i < list.length; i++ ) { if ( fn === list[ i ][ 0 ] ) { - // Handle firingIndex - if ( firing && i <= firingIndex ) { - firingIndex--; + // Handle firingIndex and firingLength + if ( firing ) { + if ( i <= firingLength ) { + firingLength--; + if ( i <= firingIndex ) { + firingIndex--; + } + } } // Remove the element list.splice( i--, 1 ); @@ -185,7 +201,8 @@ jQuery.Callbacks = function( flags, filter ) { firing = true; firingIndex = firingStart || 0; firingStart = 0; - for ( ; list && firingIndex < list.length; firingIndex++ ) { + firingLength = list.length; + for ( ; list && firingIndex < firingLength; firingIndex++ ) { if ( list[ firingIndex ][ 1 ].apply( context, args ) === false && flags.stopOnFalse ) { break; } diff --git a/test/unit/callbacks.js b/test/unit/callbacks.js index c47c4b13..860a7cbb 100644 --- a/test/unit/callbacks.js +++ b/test/unit/callbacks.js @@ -12,22 +12,28 @@ var output, outputB = addToOutput( "B" ), outputC = addToOutput( "C" ), tests = { - "": "X XABCABCC X XBB X", - "once": "X X X X X", - "memory": "XABC XABCABCCC XA XBB XB", - "unique": "X XABCA X XBB X", - "relocate": "X XAABC X XBB X", - "stopOnFalse": "X XABCABCC X XBB X", - "once memory": "XABC X XA X XA", - "once unique": "X X X X X", - "once relocate": "X X X X X", - "once stopOnFalse": "X X X X X", - "memory unique": "XA XABCA XA XBB XB", - "memory relocate": "XB XAABC XA XBB XB", - "memory stopOnFalse": "XABC XABCABCCC XA XBB XB", - "unique relocate": "X XAABC X XBB X", - "unique stopOnFalse": "X XABCA X XBB X", - "relocate stopOnFalse": "X XAABC X XBB X" + "": "XABC X XABCABCC X XBB X XABA", + "once": "XABC X X X X X XABA", + "memory": "XABC XABC XABCABCCC XA XBB XB XABA", + "unique": "XABC X XABCA X XBB X XAB", + "relocate": "XABC X XAABC X XBB X XBA", + "stopOnFalse": "XABC X XABCABCC X XBB X XA", + "addAfterFire": "XAB X XABCAB X XBB X XABA", + "once memory": "XABC XABC X XA X XA XABA", + "once unique": "XABC X X X X X XAB", + "once relocate": "XABC X X X X X XBA", + "once stopOnFalse": "XABC X X X X X XA", + "once addAfterFire": "XAB X X X X X XABA", + "memory unique": "XABC XA XABCA XA XBB XB XAB", + "memory relocate": "XABC XB XAABC XA XBB XB XBA", + "memory stopOnFalse": "XABC XABC XABCABCCC XA XBB XB XA", + "memory addAfterFire": "XAB XAB XABCABC XA XBB XB XABA", + "unique relocate": "XABC X XAABC X XBB X XBA", + "unique stopOnFalse": "XABC X XABCA X XBB X XA", + "unique addAfterFire": "XAB X XABCA X XBB X XAB", + "relocate stopOnFalse": "XABC X XAABC X XBB X X", + "relocate addAfterFire": "XAB X XAA X XBB X XBA", + "stopOnFalse addAfterFire": "XAB X XABCAB X XBB X XA" }, filters = { "no filter": undefined, @@ -44,7 +50,7 @@ jQuery.each( tests, function( flags, resultString ) { test( "jQuery.Callbacks( \"" + flags + "\" ) - " + filterLabel, function() { - expect( 17 ); + expect( 18 ); // Give qunit a little breathing room stop(); @@ -133,7 +139,7 @@ jQuery.each( tests, function( flags, resultString ) { outputA(); }, outputB ); cblist.fire(); - strictEqual( output, "XABC", "Proper ordering" ); + strictEqual( output, results.shift(), "Proper ordering" ); // Add and fire again output = "X"; @@ -169,6 +175,13 @@ jQuery.each( tests, function( flags, resultString ) { } ); strictEqual( output, results.shift(), "Multiple fire (second new callback)" ); + // Return false + output = "X"; + cblist = jQuery.Callbacks( flags ); + cblist.add( outputA, function() { return false; }, outputB ); + cblist.add( outputA ); + cblist.fire(); + strictEqual( output, results.shift(), "Callback returning false" ); }); }); });