You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

233 lines
5.3KB

  1. define( [
  2. "./core",
  3. "./var/rnotwhite"
  4. ], function( jQuery, rnotwhite ) {
  5. // Convert String-formatted options into Object-formatted ones
  6. function createOptions( options ) {
  7. var object = {};
  8. jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
  9. object[ flag ] = true;
  10. } );
  11. return object;
  12. }
  13. /*
  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 ) {
  36. // Convert options from String-formatted to Object-formatted if needed
  37. // (we check in cache first)
  38. options = typeof options === "string" ?
  39. createOptions( options ) :
  40. jQuery.extend( {}, options );
  41. var // Flag to know if list is currently firing
  42. firing,
  43. // Last fire value for non-forgettable lists
  44. memory,
  45. // Flag to know if list was already fired
  46. fired,
  47. // Flag to prevent firing
  48. locked,
  49. // Actual callback list
  50. list = [],
  51. // Queue of execution data for repeatable lists
  52. queue = [],
  53. // Index of currently firing callback (modified by add/remove as needed)
  54. firingIndex = -1,
  55. // Fire callbacks
  56. fire = function() {
  57. // Enforce single-firing
  58. locked = options.once;
  59. // Execute callbacks for all pending executions,
  60. // respecting firingIndex overrides and runtime changes
  61. fired = firing = true;
  62. for ( ; queue.length; firingIndex = -1 ) {
  63. memory = queue.shift();
  64. while ( ++firingIndex < list.length ) {
  65. // Run callback and check for early termination
  66. if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
  67. options.stopOnFalse ) {
  68. // Jump to end and forget the data so .add doesn't re-fire
  69. firingIndex = list.length;
  70. memory = false;
  71. }
  72. }
  73. }
  74. // Forget the data if we're done with it
  75. if ( !options.memory ) {
  76. memory = false;
  77. }
  78. firing = false;
  79. // Clean up if we're done firing for good
  80. if ( locked ) {
  81. // Keep an empty list if we have data for future add calls
  82. if ( memory ) {
  83. list = [];
  84. // Otherwise, this object is spent
  85. } else {
  86. list = "";
  87. }
  88. }
  89. },
  90. // Actual Callbacks object
  91. self = {
  92. // Add a callback or a collection of callbacks to the list
  93. add: function() {
  94. if ( list ) {
  95. // If we have memory from a past run, we should fire after adding
  96. if ( memory && !firing ) {
  97. firingIndex = list.length - 1;
  98. queue.push( memory );
  99. }
  100. ( function add( args ) {
  101. jQuery.each( args, function( _, arg ) {
  102. if ( jQuery.isFunction( arg ) ) {
  103. if ( !options.unique || !self.has( arg ) ) {
  104. list.push( arg );
  105. }
  106. } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
  107. // Inspect recursively
  108. add( arg );
  109. }
  110. } );
  111. } )( arguments );
  112. if ( memory && !firing ) {
  113. fire();
  114. }
  115. }
  116. return this;
  117. },
  118. // Remove a callback from the list
  119. remove: function() {
  120. jQuery.each( arguments, function( _, arg ) {
  121. var index;
  122. while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
  123. list.splice( index, 1 );
  124. // Handle firing indexes
  125. if ( index <= firingIndex ) {
  126. firingIndex--;
  127. }
  128. }
  129. } );
  130. return this;
  131. },
  132. // Check if a given callback is in the list.
  133. // If no argument is given, return whether or not list has callbacks attached.
  134. has: function( fn ) {
  135. return fn ?
  136. jQuery.inArray( fn, list ) > -1 :
  137. list.length > 0;
  138. },
  139. // Remove all callbacks from the list
  140. empty: function() {
  141. if ( list ) {
  142. list = [];
  143. }
  144. return this;
  145. },
  146. // Disable .fire and .add
  147. // Abort any current/pending executions
  148. // Clear all callbacks and values
  149. disable: function() {
  150. locked = queue = [];
  151. list = memory = "";
  152. return this;
  153. },
  154. disabled: function() {
  155. return !list;
  156. },
  157. // Disable .fire
  158. // Also disable .add unless we have memory (since it would have no effect)
  159. // Abort any pending executions
  160. lock: function() {
  161. locked = queue = [];
  162. if ( !memory ) {
  163. list = memory = "";
  164. }
  165. return this;
  166. },
  167. locked: function() {
  168. return !!locked;
  169. },
  170. // Call all callbacks with the given context and arguments
  171. fireWith: function( context, args ) {
  172. if ( !locked ) {
  173. args = args || [];
  174. args = [ context, args.slice ? args.slice() : args ];
  175. queue.push( args );
  176. if ( !firing ) {
  177. fire();
  178. }
  179. }
  180. return this;
  181. },
  182. // Call all the callbacks with the given arguments
  183. fire: function() {
  184. self.fireWith( this, arguments );
  185. return this;
  186. },
  187. // To know if the callbacks have already been called at least once
  188. fired: function() {
  189. return !!fired;
  190. }
  191. };
  192. return self;
  193. };
  194. return jQuery;
  195. } );