Update copyright year
[jquery.git] / src / callbacks.js
blob5ca7cea25a04a75311dec7f29000f4548128caf2
1 // String to Object options format cache
2 var optionsCache = {};
4 // Convert String-formatted options into Object-formatted ones and store in cache
5 function createOptions( options ) {
6         var object = optionsCache[ options ] = {};
7         jQuery.each( options.match( core_rnotwhite ) || [], function( _, flag ) {
8                 object[ flag ] = true;
9         });
10         return object;
14  * Create a callback list using the following parameters:
15  *
16  *      options: an optional list of space-separated options that will change how
17  *                      the callback list behaves or a more traditional option object
18  *
19  * By default a callback list will act like an event callback list and can be
20  * "fired" multiple times.
21  *
22  * Possible options:
23  *
24  *      once:                   will ensure the callback list can only be fired once (like a Deferred)
25  *
26  *      memory:                 will keep track of previous values and will call any callback added
27  *                                      after the list has been fired right away with the latest "memorized"
28  *                                      values (like a Deferred)
29  *
30  *      unique:                 will ensure a callback can only be added once (no duplicate in the list)
31  *
32  *      stopOnFalse:    interrupt callings when a callback returns false
33  *
34  */
35 jQuery.Callbacks = function( options ) {
37         // Convert options from String-formatted to Object-formatted if needed
38         // (we check in cache first)
39         options = typeof options === "string" ?
40                 ( optionsCache[ options ] || createOptions( options ) ) :
41                 jQuery.extend( {}, options );
43         var // Flag to know if list is currently firing
44                 firing,
45                 // Last fire value (for non-forgettable lists)
46                 memory,
47                 // Flag to know if list was already fired
48                 fired,
49                 // End of the loop when firing
50                 firingLength,
51                 // Index of currently firing callback (modified by remove if needed)
52                 firingIndex,
53                 // First callback to fire (used internally by add and fireWith)
54                 firingStart,
55                 // Actual callback list
56                 list = [],
57                 // Stack of fire calls for repeatable lists
58                 stack = !options.once && [],
59                 // Fire callbacks
60                 fire = function( data ) {
61                         memory = options.memory && data;
62                         fired = true;
63                         firingIndex = firingStart || 0;
64                         firingStart = 0;
65                         firingLength = list.length;
66                         firing = true;
67                         for ( ; list && firingIndex < firingLength; firingIndex++ ) {
68                                 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
69                                         memory = false; // To prevent further calls using add
70                                         break;
71                                 }
72                         }
73                         firing = false;
74                         if ( list ) {
75                                 if ( stack ) {
76                                         if ( stack.length ) {
77                                                 fire( stack.shift() );
78                                         }
79                                 } else if ( memory ) {
80                                         list = [];
81                                 } else {
82                                         self.disable();
83                                 }
84                         }
85                 },
86                 // Actual Callbacks object
87                 self = {
88                         // Add a callback or a collection of callbacks to the list
89                         add: function() {
90                                 if ( list ) {
91                                         // First, we save the current length
92                                         var start = list.length;
93                                         (function add( args ) {
94                                                 jQuery.each( args, function( _, arg ) {
95                                                         var type = jQuery.type( arg );
96                                                         if ( type === "function" ) {
97                                                                 if ( !options.unique || !self.has( arg ) ) {
98                                                                         list.push( arg );
99                                                                 }
100                                                         } else if ( arg && arg.length && type !== "string" ) {
101                                                                 // Inspect recursively
102                                                                 add( arg );
103                                                         }
104                                                 });
105                                         })( arguments );
106                                         // Do we need to add the callbacks to the
107                                         // current firing batch?
108                                         if ( firing ) {
109                                                 firingLength = list.length;
110                                         // With memory, if we're not firing then
111                                         // we should call right away
112                                         } else if ( memory ) {
113                                                 firingStart = start;
114                                                 fire( memory );
115                                         }
116                                 }
117                                 return this;
118                         },
119                         // Remove a callback from the list
120                         remove: function() {
121                                 if ( list ) {
122                                         jQuery.each( arguments, function( _, arg ) {
123                                                 var index;
124                                                 while( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
125                                                         list.splice( index, 1 );
126                                                         // Handle firing indexes
127                                                         if ( firing ) {
128                                                                 if ( index <= firingLength ) {
129                                                                         firingLength--;
130                                                                 }
131                                                                 if ( index <= firingIndex ) {
132                                                                         firingIndex--;
133                                                                 }
134                                                         }
135                                                 }
136                                         });
137                                 }
138                                 return this;
139                         },
140                         // Check if a given callback is in the list.
141                         // If no argument is given, return whether or not list has callbacks attached.
142                         has: function( fn ) {
143                                 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
144                         },
145                         // Remove all callbacks from the list
146                         empty: function() {
147                                 list = [];
148                                 firingLength = 0;
149                                 return this;
150                         },
151                         // Have the list do nothing anymore
152                         disable: function() {
153                                 list = stack = memory = undefined;
154                                 return this;
155                         },
156                         // Is it disabled?
157                         disabled: function() {
158                                 return !list;
159                         },
160                         // Lock the list in its current state
161                         lock: function() {
162                                 stack = undefined;
163                                 if ( !memory ) {
164                                         self.disable();
165                                 }
166                                 return this;
167                         },
168                         // Is it locked?
169                         locked: function() {
170                                 return !stack;
171                         },
172                         // Call all callbacks with the given context and arguments
173                         fireWith: function( context, args ) {
174                                 args = args || [];
175                                 args = [ context, args.slice ? args.slice() : args ];
176                                 if ( list && ( !fired || stack ) ) {
177                                         if ( firing ) {
178                                                 stack.push( args );
179                                         } else {
180                                                 fire( args );
181                                         }
182                                 }
183                                 return this;
184                         },
185                         // Call all the callbacks with the given arguments
186                         fire: function() {
187                                 self.fireWith( this, arguments );
188                                 return this;
189                         },
190                         // To know if the callbacks have already been called at least once
191                         fired: function() {
192                                 return !!fired;
193                         }
194                 };
196         return self;