Нет описания

callbacks.js 11KB

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