1
0

callbacks.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. module( "callbacks", {
  2. teardown: moduleTeardown
  3. });
  4. (function() {
  5. var output,
  6. addToOutput = function( string ) {
  7. return function() {
  8. output += string;
  9. };
  10. },
  11. outputA = addToOutput("A"),
  12. outputB = addToOutput("B"),
  13. outputC = addToOutput("C"),
  14. tests = {
  15. "": "XABC X XABCABCC X XBB X XABA X XX",
  16. "once": "XABC X X X X X XABA X XX",
  17. "memory": "XABC XABC XABCABCCC XA XBB XB XABA XC XX",
  18. "unique": "XABC X XABCA X XBB X XAB X X",
  19. "stopOnFalse": "XABC X XABCABCC X XBB X XA X XX",
  20. "once memory": "XABC XABC X XA X XA XABA XC XX",
  21. "once unique": "XABC X X X X X XAB X X",
  22. "once stopOnFalse": "XABC X X X X X XA X XX",
  23. "memory unique": "XABC XA XABCA XA XBB XB XAB XC X",
  24. "memory stopOnFalse": "XABC XABC XABCABCCC XA XBB XB XA X XX",
  25. "unique stopOnFalse": "XABC X XABCA X XBB X XA X X"
  26. },
  27. filters = {
  28. "no filter": undefined,
  29. "filter": function( fn ) {
  30. return function() {
  31. return fn.apply( this, arguments );
  32. };
  33. }
  34. };
  35. function showFlags( flags ) {
  36. if ( typeof flags === "string" ) {
  37. return "'" + flags + "'";
  38. }
  39. var output = [], key;
  40. for ( key in flags ) {
  41. output.push( "'" + key + "': " + flags[ key ] );
  42. }
  43. return "{ " + output.join( ", " ) + " }";
  44. }
  45. jQuery.each( tests, function( strFlags, resultString ) {
  46. var objectFlags = {};
  47. jQuery.each( strFlags.split( " " ), function() {
  48. if ( this.length ) {
  49. objectFlags[ this ] = true;
  50. }
  51. });
  52. jQuery.each( filters, function( filterLabel ) {
  53. jQuery.each({
  54. "string": strFlags,
  55. "object": objectFlags
  56. }, function( flagsTypes, flags ) {
  57. test( "jQuery.Callbacks( " + showFlags( flags ) + " ) - " + filterLabel, function() {
  58. expect( 21 );
  59. // Give qunit a little breathing room
  60. stop();
  61. setTimeout( start, 0 );
  62. var cblist,
  63. results = resultString.split( /\s+/ );
  64. // Basic binding and firing
  65. output = "X";
  66. cblist = jQuery.Callbacks( flags );
  67. cblist.add(function( str ) {
  68. output += str;
  69. });
  70. cblist.fire("A");
  71. strictEqual( output, "XA", "Basic binding and firing" );
  72. strictEqual( cblist.fired(), true, ".fired() detects firing" );
  73. output = "X";
  74. cblist.disable();
  75. cblist.add(function( str ) {
  76. output += str;
  77. });
  78. strictEqual( output, "X", "Adding a callback after disabling" );
  79. cblist.fire("A");
  80. strictEqual( output, "X", "Firing after disabling" );
  81. // #13517 - Emptying while firing
  82. cblist = jQuery.Callbacks( flags );
  83. cblist.add( cblist.empty );
  84. cblist.add( function() {
  85. ok( false, "not emptied" );
  86. } );
  87. cblist.fire();
  88. // Disabling while firing
  89. cblist = jQuery.Callbacks( flags );
  90. cblist.add( cblist.disable );
  91. cblist.add( function() {
  92. ok( false, "not disabled" );
  93. } );
  94. cblist.fire();
  95. // Basic binding and firing (context, arguments)
  96. output = "X";
  97. cblist = jQuery.Callbacks( flags );
  98. cblist.add(function() {
  99. equal( this, window, "Basic binding and firing (context)" );
  100. output += Array.prototype.join.call( arguments, "" );
  101. });
  102. cblist.fireWith( window, [ "A", "B" ] );
  103. strictEqual( output, "XAB", "Basic binding and firing (arguments)" );
  104. // fireWith with no arguments
  105. output = "";
  106. cblist = jQuery.Callbacks( flags );
  107. cblist.add(function() {
  108. equal( this, window, "fireWith with no arguments (context is window)" );
  109. strictEqual( arguments.length, 0, "fireWith with no arguments (no arguments)" );
  110. });
  111. cblist.fireWith();
  112. // Basic binding, removing and firing
  113. output = "X";
  114. cblist = jQuery.Callbacks( flags );
  115. cblist.add( outputA, outputB, outputC );
  116. cblist.remove( outputB, outputC );
  117. cblist.fire();
  118. strictEqual( output, "XA", "Basic binding, removing and firing" );
  119. // Empty
  120. output = "X";
  121. cblist = jQuery.Callbacks( flags );
  122. cblist.add( outputA );
  123. cblist.add( outputB );
  124. cblist.add( outputC );
  125. cblist.empty();
  126. cblist.fire();
  127. strictEqual( output, "X", "Empty" );
  128. // Locking
  129. output = "X";
  130. cblist = jQuery.Callbacks( flags );
  131. cblist.add(function( str ) {
  132. output += str;
  133. });
  134. cblist.lock();
  135. cblist.add(function( str ) {
  136. output += str;
  137. });
  138. cblist.fire("A");
  139. cblist.add(function( str ) {
  140. output += str;
  141. });
  142. strictEqual( output, "X", "Lock early" );
  143. // Ordering
  144. output = "X";
  145. cblist = jQuery.Callbacks( flags );
  146. cblist.add(function() {
  147. cblist.add( outputC );
  148. outputA();
  149. }, outputB );
  150. cblist.fire();
  151. strictEqual( output, results.shift(), "Proper ordering" );
  152. // Add and fire again
  153. output = "X";
  154. cblist.add(function() {
  155. cblist.add( outputC );
  156. outputA();
  157. }, outputB );
  158. strictEqual( output, results.shift(), "Add after fire" );
  159. output = "X";
  160. cblist.fire();
  161. strictEqual( output, results.shift(), "Fire again" );
  162. // Multiple fire
  163. output = "X";
  164. cblist = jQuery.Callbacks( flags );
  165. cblist.add(function( str ) {
  166. output += str;
  167. });
  168. cblist.fire("A");
  169. strictEqual( output, "XA", "Multiple fire (first fire)" );
  170. output = "X";
  171. cblist.add(function( str ) {
  172. output += str;
  173. });
  174. strictEqual( output, results.shift(), "Multiple fire (first new callback)" );
  175. output = "X";
  176. cblist.fire("B");
  177. strictEqual( output, results.shift(), "Multiple fire (second fire)" );
  178. output = "X";
  179. cblist.add(function( str ) {
  180. output += str;
  181. });
  182. strictEqual( output, results.shift(), "Multiple fire (second new callback)" );
  183. // Return false
  184. output = "X";
  185. cblist = jQuery.Callbacks( flags );
  186. cblist.add( outputA, function() { return false; }, outputB );
  187. cblist.add( outputA );
  188. cblist.fire();
  189. strictEqual( output, results.shift(), "Callback returning false" );
  190. // Add another callback (to control lists with memory do not fire anymore)
  191. output = "X";
  192. cblist.add( outputC );
  193. strictEqual( output, results.shift(), "Adding a callback after one returned false" );
  194. // Callbacks are not iterated
  195. output = "";
  196. function handler() {
  197. output += "X";
  198. }
  199. handler.method = function() {
  200. output += "!";
  201. };
  202. cblist = jQuery.Callbacks( flags );
  203. cblist.add( handler );
  204. cblist.add( handler );
  205. cblist.fire();
  206. strictEqual( output, results.shift(), "No callback iteration" );
  207. });
  208. });
  209. });
  210. });
  211. })();
  212. test( "jQuery.Callbacks( options ) - options are copied", function() {
  213. expect( 1 );
  214. var options = {
  215. "unique": true
  216. },
  217. cb = jQuery.Callbacks( options ),
  218. count = 0,
  219. fn = function() {
  220. ok( !( count++ ), "called once" );
  221. };
  222. options["unique"] = false;
  223. cb.add( fn, fn );
  224. cb.fire();
  225. });
  226. test( "jQuery.Callbacks.fireWith - arguments are copied", function() {
  227. expect( 1 );
  228. var cb = jQuery.Callbacks("memory"),
  229. args = ["hello"];
  230. cb.fireWith( null, args );
  231. args[ 0 ] = "world";
  232. cb.add(function( hello ) {
  233. strictEqual( hello, "hello", "arguments are copied internally" );
  234. });
  235. });
  236. test( "jQuery.Callbacks.remove - should remove all instances", function() {
  237. expect( 1 );
  238. var cb = jQuery.Callbacks();
  239. function fn() {
  240. ok( false, "function wasn't removed" );
  241. }
  242. cb.add( fn, fn, function() {
  243. ok( true, "end of test" );
  244. }).remove( fn ).fire();
  245. });
  246. test( "jQuery.Callbacks.has", function() {
  247. expect( 13 );
  248. var cb = jQuery.Callbacks();
  249. function getA() {
  250. return "A";
  251. }
  252. function getB() {
  253. return "B";
  254. }
  255. function getC() {
  256. return "C";
  257. }
  258. cb.add(getA, getB, getC);
  259. strictEqual( cb.has(), true, "No arguments to .has() returns whether callback function(s) are attached or not" );
  260. strictEqual( cb.has(getA), true, "Check if a specific callback function is in the Callbacks list" );
  261. cb.remove(getB);
  262. strictEqual( cb.has(getB), false, "Remove a specific callback function and make sure its no longer there" );
  263. strictEqual( cb.has(getA), true, "Remove a specific callback function and make sure other callback function is still there" );
  264. cb.empty();
  265. strictEqual( cb.has(), false, "Empty list and make sure there are no callback function(s)" );
  266. strictEqual( cb.has(getA), false, "Check for a specific function in an empty() list" );
  267. cb.add(getA, getB, function(){
  268. strictEqual( cb.has(), true, "Check if list has callback function(s) from within a callback function" );
  269. strictEqual( cb.has(getA), true, "Check if list has a specific callback from within a callback function" );
  270. }).fire();
  271. strictEqual( cb.has(), true, "Callbacks list has callback function(s) after firing" );
  272. cb.disable();
  273. strictEqual( cb.has(), false, "disabled() list has no callback functions (returns false)" );
  274. strictEqual( cb.has(getA), false, "Check for a specific function in a disabled() list" );
  275. cb = jQuery.Callbacks("unique");
  276. cb.add(getA);
  277. cb.add(getA);
  278. strictEqual( cb.has(), true, "Check if unique list has callback function(s) attached" );
  279. cb.lock();
  280. strictEqual( cb.has(), false, "locked() list is empty and returns false" );
  281. });
  282. test( "jQuery.Callbacks() - adding a string doesn't cause a stack overflow", function() {
  283. expect( 1 );
  284. jQuery.Callbacks().add( "hello world" );
  285. ok( true, "no stack overflow" );
  286. });