Source: index.js

  1. import jQuery from "jquery";
  2. import AniPropertyManager from "./AniPropertyManager";
  3. import MathUtil from "./MathUtil";
  4. /**
  5. * @namespace jQuery
  6. */
  7. export default (function($) {
  8. const animateFn = $.fn.animate;
  9. const stopFn = $.fn.stop;
  10. const delayFn = $.fn.delay;
  11. /**
  12. * Generate a new easing function.
  13. *
  14. * function to avoid JS Hint error "Don't make functions within a loop"
  15. */
  16. function generateNewEasingFunc(resumePercent, remainPercent, scale, originalEasing) {
  17. return function easingFunc(percent) {
  18. const newPercent = resumePercent + remainPercent * percent;
  19. return scale(originalEasing(newPercent));
  20. };
  21. }
  22. $.fn.animate = function(prop, speed, easing, callback) {
  23. return this.each(function() {
  24. // optall should be made for each elements.
  25. const optall = $.speed(speed, easing, callback);
  26. // prepare next animation when current animation completed.
  27. optall.complete = function() {
  28. AniPropertyManager.prepareNextAniProp(this);
  29. };
  30. // Queue animation property to recover the current animation.
  31. AniPropertyManager.addAniProperty("animate", this, prop, optall);
  32. animateFn.call($(this), prop, optall);
  33. });
  34. // TODO: Below code is more reasonable?
  35. // return animateFn.call(this, prop, optall); // and declare optall at outside this.each loop.
  36. };
  37. /**
  38. * Set a timer to delay execution of subsequent items in the queue.
  39. * And it internally manages "fx"queue to support pause/resume if "fx" type.
  40. *
  41. * @param {Number} An integer indicating the number of milliseconds to delay execution of the next item in the queue.
  42. * @param {String} A string containing the name of the queue. Defaults to fx, the standard effects queue.
  43. */
  44. $.fn.delay = function(time, type, ...args) {
  45. let t;
  46. const isCallByResume = args[0]; // internal used value.
  47. if (type && type !== "fx") {
  48. return delayFn.call(this, time, type);
  49. }
  50. t = parseInt(time, 10);
  51. t = isNaN(t) ? 0 : t;
  52. return this.each(function() {
  53. if (!isCallByResume) {
  54. // Queue delay property to recover the current animation.
  55. // Don't add property when delay is called by resume.
  56. AniPropertyManager.addAniProperty("delay", this, null, {duration: t});
  57. }
  58. delayFn.call($(this), time).queue(next => {
  59. next();
  60. // Remove delay property when delay has been expired.
  61. AniPropertyManager.removeAniProperty(this);
  62. });
  63. });
  64. };
  65. /**
  66. * Pauses the animation executed through a call to the jQuery <a href=http://api.jquery.com/animate/>.animate()</a> method.
  67. * @ko jQuery의<a href=http://api.jquery.com/animate/>animate() 메서드</a>가 실행한 애니메이션을 일시 정지한다
  68. *
  69. * @name jQuery#pause
  70. * @method
  71. * @support {"ie": "10+", "ch" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"}
  72. * @example
  73. * $("#box").pause(); //paused the current animation
  74. */
  75. $.fn.pause = function() {
  76. return this.each(function() {
  77. let p;
  78. if (AniPropertyManager.getStatus(this) !== "inprogress") {
  79. return;
  80. }
  81. // Clear fx-queue except 1 dummy function
  82. // for promise not to be expired when calling stop()
  83. $.queue(this, "fx", [$.noop]);
  84. stopFn.call($(this));
  85. // Remember current animation property
  86. p = this.__aniProps[0];
  87. if (p) {
  88. p.elapsed += $.now() - p.start;
  89. // Complement native timer's inaccuracy (complete timer can be different from your request.)
  90. // (eg. your request:400ms -> real :396 ~ 415 ms ))
  91. if (p.elapsed >= p.opt.duration) {
  92. p = AniPropertyManager.prepareNextAniProp(this);
  93. }
  94. p && (p.paused = true);
  95. }
  96. });
  97. };
  98. /**
  99. * Resumes the animation paused through a call to the pause() method.
  100. * @ko pause() 메서드가 일시 정지한 애니메이션을 다시 실행한다
  101. *
  102. * @name jQuery#resume
  103. * @alias eg.Pause
  104. * @method
  105. * @support {"ie": "10+", "ch" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"}
  106. * @example
  107. * $("#box").resume(); //resume the paused animation
  108. */
  109. $.fn.resume = function() {
  110. return this.each(function() {
  111. const type = "fx";
  112. let p;
  113. let i;
  114. if (AniPropertyManager.getStatus(this) !== "paused") {
  115. return;
  116. }
  117. // Clear fx-queue,
  118. // And this queue will be initialized by animate call.
  119. $.queue(this, type || "fx", []);
  120. // Restore __aniProps
  121. i = 0;
  122. p = this.__aniProps[i];
  123. while (p) {
  124. // Restore easing status
  125. if (p.elapsed > 0 && p.opt.easing) {
  126. const resumePercent = p.elapsed / p.opt.duration;
  127. const remainPercent = 1 - resumePercent;
  128. const originalEasing = $.easing[p.opt.easing];
  129. const startEasingValue = originalEasing(resumePercent);
  130. const scale = MathUtil.scaler([startEasingValue, 1], [0, 1]);
  131. const newEasingName = `${p.opt.easing}_${p.uuid}`;
  132. // Make new easing function that continues from pause point.
  133. $.easing[newEasingName] = generateNewEasingFunc(
  134. resumePercent, remainPercent, scale, originalEasing);
  135. p.opt.easing = newEasingName;
  136. // Store new easing function to clear it later.
  137. p.addEasingFn(newEasingName);
  138. }
  139. p.paused = false;
  140. p.opt.duration -= p.elapsed;
  141. // If duration remains, request 'animate' with storing aniProps
  142. if (p.opt.duration > 0 || p.elapsed === 0) {
  143. i === 0 && p.init();
  144. if (p.type === "delay") {
  145. // pass last parameter 'true' not to add an aniProperty.
  146. $(this).delay(p.opt.duration, "fx", true);
  147. } else {
  148. animateFn.call($(this), p.prop, p.opt);
  149. }
  150. }
  151. i++;
  152. p = this.__aniProps[i];
  153. }
  154. });
  155. };
  156. $.fn.stop = function(...args) {
  157. const type = args[0];
  158. let clearQ = args[1];
  159. stopFn.apply(this, args);
  160. if (typeof type !== "string") {
  161. clearQ = type;
  162. }
  163. return this.each(function() {
  164. let p;
  165. // When this element was not animated properly, do nothing.
  166. if (AniPropertyManager.getStatus(this) === "empty") {
  167. return;
  168. }
  169. if (!clearQ) {
  170. p = this.__aniProps.shift();
  171. p && p.clearEasingFn();
  172. } else {
  173. // If clearQueue is requested,
  174. // then all properties must be initialized
  175. // for element not to be resumed.
  176. p = this.__aniProps.shift();
  177. while (p) {
  178. p.clearEasingFn();
  179. p = this.__aniProps.shift();
  180. }
  181. this.__aniProps = [];
  182. }
  183. });
  184. };
  185. $.expr.filters.paused = function(elem) {
  186. return AniPropertyManager.getStatus(elem) === "paused";
  187. };
  188. })(jQuery);
comments powered by Disqus