Timing_JQuery_Util

try to take over the world!

This script should not be not be installed directly. It is a library for other scripts to include with the meta directive // @require https://update.greatest.deepsurf.us/scripts/404470/812557/Timing_JQuery_Util.js

  1. /**
  2. * code from http: //creativecouple.github.io/jquery-timing/jquery-timing.js
  3. * timing.jquery.js
  4. *
  5. * JavaScript functions for waiting / repeating / stopping jQuery actions.
  6. *
  7. * This code is published under the MIT License (MIT).
  8. * http://www.opensource.org/licenses/mit-license.php
  9. *
  10. * For examples, reference, and other information see
  11. * http://creativecouple.github.com/jquery-timing/
  12. *
  13. * @author CreativeCouple
  14. * @author Peter Liske
  15. * @copyright (c) 2011 by CreativeCouple
  16. * @see http://creativecouple.github.com/jquery-timing/
  17. */
  18.  
  19. (function(jQuery, window){
  20. /**
  21. * object to store statically invoked threads
  22. */
  23. var THREAD_GROUPS = {},
  24. /**
  25. * unique timing identifier for different purposes
  26. */
  27. tuid = 1,
  28.  
  29. /**
  30. * remember original core function $.each()
  31. */
  32. originalEach = jQuery.fn.each,
  33.  
  34. /**
  35. * remember original core function $.on() (or $.bind())
  36. */
  37. originalOn = jQuery.fn.on || jQuery.fn.bind,
  38. /**
  39. * remember original core function $.off() (or $.unbind())
  40. */
  41. originalOff = jQuery.fn.off || jQuery.fn.unbind,
  42. /**
  43. * .until() and .all() have special meanings
  44. */
  45. loopEndMethods = {};
  46. function sameOrNextJQuery(before, after) {
  47. after = jQuery(after);
  48. after.prevObject = before;
  49. var i = before.length;
  50. if (i !== after.length) {
  51. return after;
  52. }
  53. while (i--) {
  54. if (before[i] !== after[i]) {
  55. return after;
  56. }
  57. }
  58. return before;
  59. }
  60. function loopCounts(loops) {
  61. var ret = [], i = loops.length;
  62. while (i--) {
  63. ret[i] = loops[i]._count;
  64. }
  65. return ret;
  66. }
  67. /**
  68. * Initialize a new timed invocation chain.
  69. *
  70. * @author CreativeCouple
  71. * @author Peter Liske
  72. *
  73. * @param context initial context
  74. * @param methodStack linked list of methods that has been or will be filled by someone else
  75. * @param ongoingLoops optional arguments for callback parameters
  76. * @param onStepCallback function to call on each step
  77. * @returns the timed invocation chain method
  78. */
  79. function createTimedInvocationChain(context, methodStack, ongoingLoops, onStepCallback) {
  80. ongoingLoops = ongoingLoops || [];
  81. var executionState = {
  82. _context: context,
  83. _method: methodStack
  84. },
  85. preventRecursion = false,
  86. method, otherExecutionState, deferred;
  87. function hookupToProxy(state, mockup){
  88. state._canContinue = false;
  89. function fire(){
  90. state._next = sameOrNextJQuery(state._context, state._next);
  91. state._canContinue = true;
  92. timedInvocationChain();
  93. }
  94. return typeof mockup.promise == "function" ? mockup.promise().then(fire) : mockup.then(fire, true);
  95. }
  96. /**
  97. * Invoke all the methods currently in the timed invocation chain.
  98. *
  99. * @author CreativeCouple
  100. * @author Peter Liske
  101. */
  102. function timedInvocationChain(deferredReturnValue) {
  103. while (!preventRecursion) try {
  104. // keep recursive calls away
  105. preventRecursion = !preventRecursion;
  106. // save current context state
  107. if (typeof onStepCallback == "function") {
  108. onStepCallback(jQuery.makeArray(executionState._next || executionState._context));
  109. }
  110. // leave the chain when waiting for a trigger
  111. if (executionState._canContinue == false) {
  112. break;
  113. }
  114. // check end of chain
  115. if (!executionState._method._name) {
  116. if (deferred && (!ongoingLoops.length || ongoingLoops[0]._allowPromise)) {
  117. // resolve any waiting promise
  118. if (executionState._context && typeof executionState._context.promise == "function") {
  119. executionState._context.promise().then(deferred.resolve);
  120. } else {
  121. deferred.resolveWith(executionState._context);
  122. }
  123. deferred = null;
  124. }
  125. if (!ongoingLoops.length) {
  126. /*
  127. * We've reached the end of our TIC
  128. * and there is nothing left to wait for.
  129. * So we can safely return the original jQuery object
  130. * hence enabling instant invocation.
  131. */
  132. return executionState._context;
  133. }
  134. /*
  135. * Now we have ongoing loops but reached the chain's end.
  136. */
  137. otherExecutionState = ongoingLoops[0]._openEndAction && ongoingLoops[0]._openEndAction(timedInvocationChain, executionState, ongoingLoops);
  138. if (!otherExecutionState) {
  139. // if innermost loop can't help us, just leave the chain
  140. break;
  141. }
  142. executionState = otherExecutionState;
  143. continue;
  144. }
  145. // check if user tries to use a non-existing function call
  146. method = executionState._context && executionState._context[executionState._method._name] || loopEndMethods[executionState._method._name];
  147. if (!method) {
  148. throw 'no such method "'+executionState._method._name+'" on object ('+executionState._context+')';
  149. }
  150. // check whether we came here triggered or not
  151. if (method.timing && !executionState._canContinue) {
  152. // prevent automatic re-trigger in case of loops
  153. executionState._canContinue = false;
  154. // handle timing method
  155. executionState = method.timing(timedInvocationChain, executionState, ongoingLoops, onStepCallback) || executionState;
  156. } else {
  157. if (!method.timing && !executionState._canContinue) {
  158. // prevent automatic re-trigger in case of loops
  159. executionState._next = executionState._context[executionState._method._name].apply(executionState._context, executionState._method._arguments);
  160. if (ongoingLoops.length && executionState._next && executionState._next instanceof PredictingProxy) {
  161. hookupToProxy(executionState, executionState._next);
  162. continue;
  163. }
  164. }
  165. // go to next step
  166. otherExecutionState = {
  167. _context: executionState._next,
  168. _method: executionState._method._next
  169. };
  170. // prevent automatic re-trigger in case of loops
  171. executionState._canContinue = false;
  172. // invoke callback method with given arguments
  173. if (typeof executionState._callback == "function") {
  174. executionState._callback.apply(executionState._context, loopCounts(ongoingLoops));
  175. }
  176. executionState = otherExecutionState;
  177. }
  178. } catch(e) {
  179. /*
  180. * We had a runtime exception.
  181. * In plain JavaScript live the chain would break now.
  182. * So we do, too.
  183. */
  184. preventRecursion = !preventRecursion;
  185. throw e;
  186. } finally {
  187. preventRecursion = !preventRecursion;
  188. }
  189. return deferredReturnValue;
  190. };
  191. if (jQuery.Deferred) {
  192. // add .promise() method to tic
  193. timedInvocationChain.promise = function(type, target){
  194. var ret = (deferred = deferred || jQuery.Deferred()).promise(target);
  195. timedInvocationChain();
  196. return ret;
  197. };
  198. }
  199. return timedInvocationChain;
  200. }
  201. /**
  202. * Create a placeholder object to collect chained method calls.
  203. *
  204. * @author CreativeCouple
  205. * @author Peter Liske
  206. *
  207. * @param context initial context
  208. * @param methodStack a linked list that this placeholder will fill with call parameters
  209. * @return the placeholder object
  210. */
  211. function PredictingProxy(context, methodStack, onStepCallback) {
  212. this['.methods'] = methodStack;
  213. this['.callback'] = onStepCallback;
  214. this.length = 0;
  215. Array.prototype.push.apply(this, jQuery.makeArray(this._ = context._ = context));
  216. for (var key in context) {
  217. if (!(key in PredictingProxy.prototype) && typeof context[key] == "function") {
  218. this[key] = extendMockupPrototype(key);
  219. }
  220. }
  221. }
  222. // enabling jQuery.when(tic);
  223. if (jQuery.Deferred) {
  224. PredictingProxy.prototype.promise = function(type, target) {
  225. if (typeof type == "object") {
  226. target = type;
  227. type = null;
  228. }
  229. return (this['.callback'] && typeof this['.callback'].promise == "function") ? this['.callback'].promise(type, target) : jQuery.Deferred().resolveWith(this).promise(target);
  230. };
  231. }
  232. /**
  233. * Create and return a new placeholder function on the prototype of PredictingProxy.
  234. */
  235. function extendMockupPrototype(name){
  236. return PredictingProxy.prototype[name] = function(){
  237. this['.methods']._name = name;
  238. this['.methods']._arguments = arguments;
  239. this['.methods'] = this['.methods']._next = {};
  240. return this['.callback'] ? this['.callback'](this, name, arguments) : this;
  241. };
  242. }
  243. /**
  244. * Create replacement methods for .bind(), .on(), .one(), .live(), and .delegate()
  245. * that support chaining instead of giving a callback function.
  246. */
  247. jQuery.each(['bind','on','one','live','delegate'], function(index, name){
  248. if (jQuery.fn[name]) {
  249. var original = jQuery.fn[name];
  250. jQuery.fn[name] = function(){
  251. var i, methodStack, placeholder, timedInvocationChain, deferred, context = this;
  252. for(i=0; i<arguments.length; i++) {
  253. if (typeof arguments[i] == "function" || (arguments[i] && typeof arguments[i] == "object") || arguments[i] === false) {
  254. if (arguments[i] !== jQuery) {
  255. // fix for jQuery 1.6 .one() + .unbind()
  256. if (typeof arguments[i] == "function" && jQuery.guid) {
  257. arguments[i].guid = arguments[i].guid || jQuery.guid++;
  258. }
  259. return original.apply(context, arguments);
  260. }
  261. break;
  262. }
  263. }
  264. Array.prototype.splice.call(arguments, i, 1, function(){
  265. timedInvocationChain = createTimedInvocationChain(context.$(this), methodStack, [{
  266. _count: jQuery.extend(Array.prototype.shift.apply(arguments), arguments),
  267. _allowPromise: true
  268. }], function(elements){
  269. placeholder.length = 0;
  270. Array.prototype.push.apply(placeholder, elements);
  271. });
  272. if (deferred) {
  273. timedInvocationChain.promise().then(deferred.resolve);
  274. deferred = null;
  275. }
  276. return timedInvocationChain();
  277. });
  278. function fire(){
  279. return timedInvocationChain ? timedInvocationChain(placeholder) : placeholder;
  280. }
  281. if (jQuery.Deferred) {
  282. fire.promise = function(type, target){
  283. if (typeof type == "object") {
  284. target = type;
  285. type = null;
  286. }
  287. return (timedInvocationChain && !type) ? timedInvocationChain.promise(type, target) : (deferred = deferred || jQuery.Deferred()).promise(target);
  288. };
  289. }
  290. return placeholder = new PredictingProxy(original.apply(context, arguments), methodStack = {}, fire);
  291. };
  292. }
  293. });
  294. /**
  295. * Create replacement method for .animate() and .load()
  296. * that support chaining if $ is given as callback function.
  297. */
  298. jQuery.each(['animate','load'], function(index, name){
  299. if (jQuery.fn[name]) {
  300. var original = jQuery.fn[name];
  301. jQuery.fn[name] = function(){
  302. while (arguments.length && arguments[arguments.length-1] == null) {
  303. Array.prototype.pop.apply(arguments);
  304. }
  305. if (this.length && arguments.length > 1 && arguments[arguments.length-1] === jQuery) {
  306. var event = '_timing'+tuid++;
  307. arguments[arguments.length-1] = function(){
  308. jQuery(this).trigger(event);
  309. };
  310. return this.each().one(event).all(original.apply(this, arguments));
  311. }
  312. return original.apply(this, arguments);
  313. };
  314. }
  315. });
  316. /**
  317. * Define new methods .wait(), .repeat(), .join(), .then()
  318. * which will always start a new TIC if invoked outside of a TIC.
  319. */
  320. jQuery.each(['wait','repeat','join','then'], function(index, name){
  321. jQuery.fn[name] = function(){
  322. var methodStack = {},
  323. placeholder = new PredictingProxy(this, methodStack, createTimedInvocationChain(this, methodStack, [], function(elements){
  324. placeholder.length = 0;
  325. Array.prototype.push.apply(placeholder, elements);
  326. }));
  327. return placeholder[name].apply(placeholder, arguments);
  328. };
  329. });
  330. /**
  331. * Define to wait for joining all animation queues.
  332. *
  333. * @param timedInvocationChain
  334. * @param executionState
  335. */
  336. jQuery.fn.join.timing = function(timedInvocationChain, executionState) {
  337. var queueName,
  338. promising,
  339. waitingElements = executionState._context.length;
  340. if (typeof executionState._method._arguments[0] == "string") {
  341. queueName = executionState._method._arguments[0];
  342. if (typeof executionState._method._arguments[1] == "function") {
  343. executionState._callback = executionState._method._arguments[1];
  344. } else {
  345. promising = executionState._method._arguments[1];
  346. executionState._callback = executionState._method._arguments[2];
  347. }
  348. } else {
  349. if (typeof executionState._method._arguments[0] == "function") {
  350. executionState._callback = executionState._method._arguments[0];
  351. } else {
  352. promising = executionState._method._arguments[0];
  353. executionState._callback = executionState._method._arguments[1];
  354. }
  355. }
  356. executionState._next = executionState._context;
  357. executionState._canContinue = !waitingElements;
  358.  
  359. // wait for each element to reach the current end of its queue
  360. if (promising) {
  361. executionState._context.promise(queueName == null ? 'fx' : queueName).then(function(){
  362. executionState._canContinue = true;
  363. timedInvocationChain();
  364. });
  365. } else {
  366. executionState._context.queue(queueName == null ? 'fx' : queueName, function(next){
  367. executionState._canContinue = !--waitingElements;
  368. timedInvocationChain();
  369. next();
  370. });
  371. }
  372. };
  373.  
  374. /**
  375. * Define to simply run callback method for .then()
  376. *
  377. * @param timedInvocationChain
  378. * @param executionState
  379. */
  380. jQuery.fn.then.timing = function(timedInvocationChain, executionState){
  381. executionState._callback = executionState._method._arguments[0];
  382. executionState._next = executionState._context;
  383. executionState._canContinue = true;
  384. if (executionState._method._arguments[1]) {
  385. Array.prototype.shift.apply(executionState._method._arguments);
  386. }
  387. };
  388. /**
  389. * Define timeout or binding to wait for.
  390. *
  391. * @param timedInvocationChain
  392. * @param executionState
  393. */
  394. jQuery.fn.wait.timing = function(timedInvocationChain, executionState, ongoingLoops) {
  395. var trigger, event, timeout, context = executionState._context;
  396. trigger = executionState._method._arguments[0];
  397. executionState._callback = executionState._method._arguments[1];
  398.  
  399. function triggerAction() {
  400. originalOff.call(event ? originalOff.call(context, event, triggerAction) : context, 'unwait', unwaitAction);
  401. executionState._canContinue = true;
  402. executionState._next = sameOrNextJQuery(executionState._context, executionState._next);
  403. timedInvocationChain();
  404. }
  405. function unwaitAction(evt, skipWait){
  406. originalOff.call(event ? originalOff.call(jQuery(this), event, triggerAction) : jQuery(this), 'unwait', unwaitAction);
  407. context = context.not(this);
  408. if (!skipWait) {
  409. executionState._next = executionState._next.not(this);
  410. }
  411. if (!context.length) {
  412. executionState._canContinue = executionState._next.length;
  413. executionState._next = sameOrNextJQuery(executionState._context, executionState._next);
  414. window.clearTimeout(timeout);
  415. executionState = { _context: context };
  416. }
  417. // just update the snapshot info
  418. timedInvocationChain();
  419. }
  420.  
  421. originalOn.call(context, 'unwait', unwaitAction);
  422. executionState._next = context;
  423.  
  424. if (trigger == null || trigger == jQuery) {
  425. trigger = context;
  426. }
  427. if (typeof trigger == "function") {
  428. trigger = trigger.apply(context, loopCounts(ongoingLoops));
  429. }
  430. if (typeof trigger == "string") {
  431.  
  432. originalOn.call(context, event = trigger, triggerAction);
  433.  
  434. } else if (trigger && typeof trigger.promise == "function") {
  435. trigger.promise().then(triggerAction);
  436. } else if (trigger && typeof trigger.then == "function") {
  437. trigger.then(triggerAction, true);
  438. } else {
  439.  
  440. timeout = window.setTimeout(triggerAction, Math.max(0,trigger));
  441.  
  442. }
  443. };
  444.  
  445. /**
  446. * Define to simply run callback method for .then()
  447. *
  448. * @param timedInvocationChain
  449. * @param executionState
  450. */
  451. jQuery.fn.each = function(callback){
  452. if (!callback || callback === jQuery) {
  453. var methodStack = {},
  454. placeholder = new PredictingProxy(this, methodStack, createTimedInvocationChain(this, methodStack, [], function(elements){
  455. placeholder.length = 0;
  456. Array.prototype.push.apply(placeholder, elements);
  457. }));
  458. return placeholder.each(callback);
  459. }
  460. return originalEach.apply(this, arguments);
  461. };
  462. /**
  463. * Define interval or binding to repeat.
  464. *
  465. * @param timedInvocationChain
  466. * @param executionState
  467. */
  468. jQuery.fn.each.timing = function(timedInvocationChain, executionState, ongoingLoops, onStepCallback) {
  469. if (executionState._method._arguments[0] && executionState._method._arguments[0] !== jQuery) {
  470. executionState._canContinue = true;
  471. executionState._next = originalEach.apply(executionState._context, executionState._method._arguments);
  472. return;
  473. }
  474. var size = Math.max(executionState._context.length, 1),
  475. finished = 0,
  476. key, methodToGoOn, openLoopTimeout,
  477. innerTICs = [],
  478. innerElements = [],
  479. proxyPlaceholder = jQuery.extend({}, executionState._context),
  480. stepByStep = executionState._method._arguments[0] === jQuery;
  481.  
  482. if (stepByStep) {
  483. window.setTimeout(function(){
  484. openLoopTimeout = true;
  485. timedInvocationChain();
  486. },0);
  487. }
  488. function spreadAction(){
  489. if (stepByStep) {
  490. if (finished < size) {
  491. (innerTICs[finished])();
  492. }
  493. } else {
  494. for (var i=0; i<size; i++) {
  495. (innerTICs[i])();
  496. }
  497. }
  498. return proxyPlaceholder;
  499. }
  500. for (key in PredictingProxy.prototype) {
  501. proxyPlaceholder[key] = spreadAction;
  502. }
  503. proxyPlaceholder.length = size;
  504. for(key=0; key<size; key++) (function(index){
  505. var innerLoops = ongoingLoops.slice(),
  506. context = executionState._context.eq(index);
  507. innerElements[index] = context.get();
  508. innerLoops.unshift({
  509. _count: index,
  510. _allAction: function(state){
  511. finished++;
  512. if (finished == size) {
  513. methodToGoOn = state._method._next;
  514. }
  515. timedInvocationChain();
  516. },
  517. _fixOpenLoop: loopEndMethods.all,
  518. _openEndAction: function(tic, state){
  519. if (openLoopTimeout) {
  520. finished++;
  521. if (finished == size) {
  522. methodToGoOn = state._method;
  523. }
  524. timedInvocationChain();
  525. }
  526. }
  527. });
  528. innerTICs[index] = createTimedInvocationChain(context, executionState._method._next, innerLoops, function(elements){
  529. innerElements[index] = elements;
  530. proxyPlaceholder.length = 0;
  531. for (var i=0; i<size; i++) {
  532. Array.prototype.push.apply(proxyPlaceholder, innerElements[i]);
  533. }
  534. if (onStepCallback)
  535. onStepCallback(jQuery.makeArray(proxyPlaceholder));
  536. });
  537. })(key);
  538.  
  539. executionState._next = proxyPlaceholder;
  540. executionState._canContinue = true;
  541. executionState._openEndAction = function(tic, state){
  542. if (finished == size) {
  543. ongoingLoops.shift();
  544. return {
  545. _context: sameOrNextJQuery(executionState._context, proxyPlaceholder),
  546. _method: methodToGoOn
  547. };
  548. }
  549. var finishedBefore = finished;
  550. spreadAction();
  551. if (finished != finishedBefore) {
  552. return state;
  553. }
  554. };
  555. executionState._count = size;
  556. ongoingLoops.unshift(executionState);
  557. };
  558.  
  559. loopEndMethods.all = function(executionState){
  560. jQuery.extend(executionState._method, {
  561. _next: jQuery.extend({}, executionState._method),
  562. _name: 'all',
  563. _arguments: []
  564. });
  565. executionState._canContinue = null;
  566. };
  567. loopEndMethods.all.timing = function(timedInvocationChain, executionState, ongoingLoops) {
  568. if (!ongoingLoops.length || !ongoingLoops[0]._fixOpenLoop) {
  569. throw '.all() method must be used after .each() only';
  570. }
  571. if (!ongoingLoops[0]._allAction) {
  572. ongoingLoops[0]._fixOpenLoop(executionState);
  573. return;
  574. }
  575. ongoingLoops[0]._allAction(executionState);
  576. };
  577. /**
  578. * Define interval or binding to repeat.
  579. *
  580. * @param timedInvocationChain
  581. * @param executionState
  582. */
  583. jQuery.fn.repeat.timing = function(timedInvocationChain, executionState, ongoingLoops) {
  584. var trigger,
  585. firstRunNow,
  586. openLoopTimeout,
  587. event,
  588. interval;
  589.  
  590. if (typeof executionState._method._arguments[0] == "function") {
  591. executionState._callback = executionState._method._arguments[0];
  592. } else if (typeof executionState._method._arguments[1] == "function") {
  593. trigger = executionState._method._arguments[0];
  594. executionState._callback = executionState._method._arguments[1];
  595. } else {
  596. trigger = executionState._method._arguments[0];
  597. firstRunNow = executionState._method._arguments[1];
  598. executionState._callback = executionState._method._arguments[2];
  599. }
  600. function triggerAction() {
  601. executionState._next = executionState._next || executionState._context;
  602. executionState._canContinue = true;
  603. timedInvocationChain();
  604. }
  605. function unrepeatAction(){
  606. originalOff.call(event ? originalOff.call(jQuery(this), event, triggerAction) : jQuery(this), 'unrepeat', unrepeatAction);
  607. var context = executionState._context.not(this);
  608. executionState._next = (executionState._next == executionState._context) ? context : executionState._next;
  609. executionState._context = context;
  610. executionState._canContinue = executionState._context.length && executionState._canContinue;
  611. trigger = executionState._context.length && trigger;
  612. window.clearInterval(!executionState._context.length && interval);
  613. // just update the snapshot info
  614. timedInvocationChain();
  615. }
  616. executionState._openEndAction = function(tic, state){
  617. if (executionState._canContinue || openLoopTimeout) {
  618. executionState._count++;
  619. executionState._next = executionState._next || executionState._context;
  620. executionState._canContinue = executionState._canContinue || (trigger && state._context && state._context.length);
  621. return executionState;
  622. }
  623. };
  624.  
  625. if (trigger == null) {
  626. firstRunNow = trigger = true;
  627. window.setTimeout(function(){
  628. openLoopTimeout = true;
  629. timedInvocationChain();
  630. },0);
  631. } else {
  632. if (typeof trigger == "string") {
  633. originalOn.call(executionState._context, event = trigger, triggerAction);
  634. } else {
  635. interval = window.setInterval(triggerAction, Math.max(0, trigger));
  636. }
  637. trigger = false;
  638. }
  639.  
  640. originalOn.call(executionState._context, 'unrepeat', unrepeatAction);
  641. executionState._next = executionState._context;
  642. executionState._count = 0;
  643. executionState._untilAction = function(end){
  644. if (end) {
  645. unrepeatAction.apply(executionState._context);
  646. }
  647. if (trigger) {
  648. triggerAction();
  649. }
  650. };
  651. executionState._fixOpenLoop = loopEndMethods.until;
  652.  
  653. if (firstRunNow) {
  654. triggerAction();
  655. }
  656. ongoingLoops.unshift(executionState);
  657. };
  658.  
  659. /**
  660. * Defined to evaluate condition when calling .until()
  661. */
  662. loopEndMethods.until = function(executionState){
  663. jQuery.extend(executionState._method, {
  664. _next: jQuery.extend({}, executionState._method),
  665. _name: 'until',
  666. _arguments: []
  667. });
  668. executionState._canContinue = null;
  669. };
  670. loopEndMethods.until.timing = function(timedInvocationChain, executionState, ongoingLoops) {
  671. if (!ongoingLoops.length || !ongoingLoops[0]._fixOpenLoop) {
  672. throw '.until() method must be used after .repeat() only';
  673. }
  674. if (!ongoingLoops[0]._untilAction) {
  675. ongoingLoops[0]._fixOpenLoop(executionState);
  676. return;
  677. }
  678.  
  679. var condition = executionState._method._arguments[0],
  680. loopContext = executionState._method._arguments[1];
  681. if (condition === jQuery) {
  682. condition = null;
  683. loopContext = executionState._method._arguments.length <= 1 || loopContext;
  684. }
  685. if (typeof condition == "function") {
  686. condition = condition.apply(executionState._context, loopCounts(ongoingLoops));
  687. }
  688. if (condition == null) {
  689. condition = !executionState._context.size();
  690. }
  691. if (typeof condition == "object") {
  692. condition = condition.toString();
  693. }
  694. if (typeof condition == "number") {
  695. condition = ongoingLoops[0]._count >= condition-1;
  696. }
  697. if (condition) {
  698. executionState._canContinue = true;
  699. executionState._next = executionState._context;
  700. ongoingLoops.shift()._untilAction(condition);
  701. } else {
  702. if (loopContext) {
  703. ongoingLoops[0]._next = executionState._context;
  704. }
  705. executionState = ongoingLoops[0];
  706. executionState._count++;
  707. executionState._untilAction(condition);
  708. return executionState;
  709. }
  710. };
  711. // support .until() and .all()
  712. new PredictingProxy(loopEndMethods);
  713. /**
  714. * Define unwait and unrepeat methods.
  715. */
  716. jQuery.each(['unwait','unrepeat'], function(index, name){
  717. jQuery.fn[name] = function(){
  718. return this.trigger(name, arguments);
  719. };
  720. });
  721. /**
  722. * define all static timing methods:
  723. * $.wait, $.repeat ,$.join, $.then, $.unwait, $.unrepeat
  724. */
  725. jQuery.each(['wait','repeat','join','then','unwait','unrepeat'], function(index, name){
  726. jQuery[name] = function(){
  727. var group = typeof arguments[0] == "string" ? Array.prototype.shift.apply(arguments) : '';
  728. return jQuery.fn[name].apply(THREAD_GROUPS[group] = (THREAD_GROUPS[group] || jQuery('<div>').text(group)), arguments);
  729. };
  730. });
  731.  
  732. /**
  733. * X defines deferred variables that can be used in timed invocation chains
  734. *
  735. * @author CreativeCouple
  736. * @author Peter Liske
  737. */
  738. function X(compute, Var, calculation){
  739. if (typeof compute == "string") {
  740. calculation = new Function('x','return ['+compute+'\n,x]');
  741. compute = function(x, result){
  742. result = calculation(x);
  743. callbackVariable.x = result[1];
  744. return result[0];
  745. };
  746. }
  747. var hasRelatedVariable = typeof Var == "function",
  748. hasComputation = typeof compute == "function",
  749. callbackVariable = function(value) {
  750. if (arguments.length == 1) {
  751. callbackVariable.x = value;
  752. if (hasRelatedVariable) {
  753. Var(value);
  754. }
  755. } else {
  756. return evaluate();
  757. }
  758. };
  759. function evaluate(value){
  760. value = hasRelatedVariable ? Var() : callbackVariable.x;
  761. return hasComputation ? compute(value) : value;
  762. }
  763. callbackVariable.x = 0;
  764. callbackVariable._ = { toString: callbackVariable.$ = callbackVariable.toString = evaluate.toString = evaluate };
  765. callbackVariable.mod = function(val){
  766. return X(function(x){
  767. return x % val;
  768. }, callbackVariable);
  769. };
  770. callbackVariable.add = function(val){
  771. return X(function(x){
  772. return x + val;
  773. }, callbackVariable);
  774. };
  775. callbackVariable.neg = function(){
  776. return X('-x', callbackVariable);
  777. };
  778. // $$ only for backward compatibility
  779. callbackVariable.$$ = callbackVariable.X = function(compute){
  780. return X(compute, callbackVariable);
  781. };
  782. jQuery.each(['a','b','c','d','e','f','g','h','i','j'], function(index, character){
  783. callbackVariable[index] = callbackVariable[character] = function(){
  784. callbackVariable(arguments[index]);
  785. };
  786. });
  787. return callbackVariable;
  788. };
  789. // $$ only for backward compatibility
  790. window.$$ = jQuery.$$ = jQuery.X = X;
  791. /**
  792. * Define chained version of $().
  793. * This allows to use .end() to come back to previous jQuery selection.
  794. */
  795. jQuery.fn.$ = function(){
  796. var ret = jQuery.apply(window, arguments);
  797. ret.prevObject = this;
  798. return ret;
  799. };
  800. })(jQuery, window);