jquery.spinner.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*!
  2. * jquery.spinner v0.2.1 (https://vsn4ik.github.io/jquery.spinner/)
  3. * Copyright 2013-2016 xixilive
  4. * Licensed under the MIT license
  5. */
  6. 'use strict';
  7. (function(factory) {
  8. if (typeof define === 'function' && define.amd) {
  9. // AMD. Register as an anonymous module
  10. define(['jquery'], factory);
  11. }
  12. else if (typeof exports === 'object') {
  13. // Node/CommonJS
  14. module.exports = factory(require('jquery'));
  15. }
  16. else {
  17. // Browser globals
  18. factory(jQuery);
  19. }
  20. })(function($) {
  21. var spinningTimer;
  22. var Spinner;
  23. var Spinning = function($element, options) {
  24. this.$el = $element;
  25. this.options = $.extend({}, Spinning.rules.defaults, Spinning.rules[options.rule] || {}, options);
  26. this.min = Number(this.options.min) || 0;
  27. this.max = Number(this.options.max) || 0;
  28. this.$el.on({
  29. 'focus.spinner': $.proxy(function(e) {
  30. e.preventDefault();
  31. $(document).trigger('mouseup.spinner');
  32. this.oldValue = this.value();
  33. }, this),
  34. 'change.spinner': $.proxy(function(e) {
  35. e.preventDefault();
  36. this.value(this.$el.val());
  37. }, this),
  38. 'keydown.spinner': $.proxy(function(e) {
  39. var dir = {
  40. 38: 'up',
  41. 40: 'down'
  42. }[e.which];
  43. if (dir) {
  44. e.preventDefault();
  45. this.spin(dir);
  46. }
  47. }, this)
  48. });
  49. //init input value
  50. this.oldValue = this.value();
  51. this.value(this.$el.val());
  52. return this;
  53. };
  54. Spinning.rules = {
  55. defaults: { min: null, max: null, step: 1, precision: 0 },
  56. currency: { min: 0.00, max: null, step: 0.01, precision: 2 },
  57. quantity: { min: 1, max: 999, step: 1, precision: 0 },
  58. percent: { min: 1, max: 100, step: 1, precision: 0 },
  59. month: { min: 1, max: 12, step: 1, precision: 0 },
  60. day: { min: 1, max: 31, step: 1, precision: 0 },
  61. hour: { min: 0, max: 23, step: 1, precision: 0 },
  62. minute: { min: 1, max: 59, step: 1, precision: 0 },
  63. second: { min: 1, max: 59, step: 1, precision: 0 }
  64. };
  65. Spinning.prototype = {
  66. spin: function(dir) {
  67. if (this.$el.prop('disabled')) {
  68. return;
  69. }
  70. this.oldValue = this.value();
  71. var step = $.isFunction(this.options.step) ? this.options.step.call(this, dir) : this.options.step;
  72. var multipler = dir === 'up' ? 1 : -1;
  73. this.value(this.oldValue + Number(step) * multipler);
  74. },
  75. value: function(v) {
  76. if (v === null || v === undefined) {
  77. return this.numeric(this.$el.val());
  78. }
  79. v = this.numeric(v);
  80. var valid = this.validate(v);
  81. if (valid !== 0) {
  82. v = (valid === -1) ? this.min : this.max;
  83. }
  84. this.$el.val(v.toFixed(this.options.precision));
  85. if (this.oldValue !== this.value()) {
  86. // changing.spinner
  87. this.$el.trigger('changing.spinner', [this.value(), this.oldValue]);
  88. // lazy changed.spinner
  89. clearTimeout(spinningTimer);
  90. spinningTimer = setTimeout($.proxy(function() {
  91. this.$el.trigger('changed.spinner', [this.value(), this.oldValue]);
  92. }, this), Spinner.delay);
  93. }
  94. },
  95. numeric: function(v) {
  96. v = this.options.precision > 0 ? parseFloat(v, 10) : parseInt(v, 10);
  97. // If the variable is a number
  98. if (isFinite(v)) {
  99. return v;
  100. }
  101. return v || this.options.min || 0;
  102. },
  103. validate: function(val) {
  104. if (this.options.min !== null && val < this.min) {
  105. return -1;
  106. }
  107. if (this.options.max !== null && val > this.max) {
  108. return 1;
  109. }
  110. return 0;
  111. }
  112. };
  113. Spinner = function(element, options) {
  114. this.$el = $(element);
  115. this.$spinning = this.$el.find('[data-spin="spinner"]');
  116. if (this.$spinning.length === 0) {
  117. this.$spinning = this.$el.find(':input[type="text"]');
  118. }
  119. options = $.extend({}, options, this.$spinning.data());
  120. this.spinning = new Spinning(this.$spinning, options);
  121. this.$el
  122. .on('click.spinner', '[data-spin="up"], [data-spin="down"]', $.proxy(this, 'spin'))
  123. .on('mousedown.spinner', '[data-spin="up"], [data-spin="down"]', $.proxy(this, 'spin'));
  124. $(document).on('mouseup.spinner', $.proxy(function() {
  125. clearTimeout(this.spinTimeout);
  126. clearInterval(this.spinInterval);
  127. }, this));
  128. if (options.delay) {
  129. this.delay(options.delay);
  130. }
  131. if (options.changed) {
  132. this.changed(options.changed);
  133. }
  134. if (options.changing) {
  135. this.changing(options.changing);
  136. }
  137. };
  138. Spinner.delay = 500;
  139. Spinner.prototype = {
  140. constructor: Spinner,
  141. spin: function(e) {
  142. var dir = $(e.currentTarget).data('spin');
  143. switch (e.type) {
  144. case 'click':
  145. e.preventDefault();
  146. this.spinning.spin(dir);
  147. break;
  148. case 'mousedown':
  149. if (e.which === 1) {
  150. this.spinTimeout = setTimeout($.proxy(this, 'beginSpin', dir), 300);
  151. }
  152. break;
  153. }
  154. },
  155. delay: function(ms) {
  156. var delay = Number(ms);
  157. if (delay >= 0) {
  158. this.constructor.delay = delay + 100;
  159. }
  160. },
  161. value: function() {
  162. return this.spinning.value();
  163. },
  164. changed: function(fn) {
  165. this.bindHandler('changed.spinner', fn);
  166. },
  167. changing: function(fn) {
  168. this.bindHandler('changing.spinner', fn);
  169. },
  170. bindHandler: function(t, fn) {
  171. if ($.isFunction(fn)) {
  172. this.$spinning.on(t, fn);
  173. }
  174. else {
  175. this.$spinning.off(t);
  176. }
  177. },
  178. beginSpin: function(dir) {
  179. this.spinInterval = setInterval($.proxy(this.spinning, 'spin', dir), 100);
  180. }
  181. };
  182. var old = $.fn.spinner;
  183. $.fn.spinner = function(options, value) {
  184. return this.each(function() {
  185. var data = $.data(this, 'spinner');
  186. if (!data) {
  187. data = new Spinner(this, options);
  188. $.data(this, 'spinner', data);
  189. }
  190. if (options === 'delay' || options === 'changed' || options === 'changing') {
  191. data[options](value);
  192. }
  193. else if (options === 'step' && value) {
  194. data.spinning.step = value;
  195. }
  196. else if (options === 'spin' && value) {
  197. data.spinning.spin(value);
  198. }
  199. });
  200. };
  201. $.fn.spinner.Constructor = Spinner;
  202. $.fn.spinner.noConflict = function() {
  203. $.fn.spinner = old;
  204. return this;
  205. };
  206. $(function() {
  207. $('[data-trigger="spinner"]').spinner();
  208. });
  209. return $.fn.spinner;
  210. });