--- /dev/null
+/*\r
+ * jQuery UI Spinner @VERSION\r
+ *\r
+ * Copyright (c) 2010 AUTHORS.txt (http://jqueryui.com/about)\r
+ * Dual licensed under the MIT (MIT-LICENSE.txt)\r
+ * and GPL (GPL-LICENSE.txt) licenses.\r
+ *\r
+ * http://docs.jquery.com/UI/Spinner\r
+ *\r
+ * Depends:\r
+ * jquery.ui.core.js\r
+ * jquery.ui.widget.js\r
+ */\r
+(function($) {\r
+\r
+// shortcut constants\r
+var hover = 'ui-state-hover',\r
+ active = 'ui-state-active',\r
+ namespace = '.spinner',\r
+ buttonRegex = /hide|auto|fast|slow|(\d+)/,\r
+ uiSpinnerClasses = 'ui-spinner ui-state-default ui-widget ui-widget-content ui-corner-all ';\r
+\r
+$.widget('ui.spinner', {\r
+ options: {\r
+ currency: false,\r
+ dir: 'ltr',\r
+ groupSeparator: '',\r
+ incremental: true,\r
+ max: null,\r
+ min: null,\r
+ mouseWheel: true,\r
+ padding: 0,\r
+ page: 5,\r
+ precision: 0,\r
+ radix: 10,\r
+ radixPoint: '.',\r
+ spinnerClass: null,\r
+ step: null,\r
+ value: 0,\r
+ width: false\r
+ },\r
+ \r
+ _create: function() { \r
+ this._initOptions();\r
+\r
+ this.value(this._parse(this.element.val() || this.options.value));\r
+ \r
+ this._draw();\r
+\r
+ this._mousewheel();\r
+ \r
+ this._aria();\r
+ },\r
+ _initOptions: function() {\r
+ var self = this,\r
+ options = self.options;\r
+\r
+ // check for precision in stepping and set _precision as internal\r
+ var precision = parseInt(options.precision, 10);\r
+ \r
+ if (self._step().toString().indexOf('.') != -1 && precision === 0) {\r
+ var s = self._step().toString();\r
+ precision = s.slice(s.indexOf('.')+1, s.length).length;\r
+ }\r
+ \r
+ // set currency options\r
+ if (options.currency) {\r
+ precision = 2;\r
+ options.radix = 10;\r
+ options.groupSeparator = options.groupSeparator || (options.radixPoint === ',' ? '' : ',');\r
+ }\r
+ options.precision = precision;\r
+ },\r
+ _draw: function() {\r
+ var self = this,\r
+ options = self.options;\r
+\r
+ var uiSpinner = self.element\r
+ .addClass('ui-spinner-input')\r
+ .attr('autocomplete', 'off')\r
+ .wrap(self._uiSpinnerHtml())\r
+ .parent()\r
+ // add buttons\r
+ .append(self._buttonHtml())\r
+ // add behaviours\r
+ .hover(function() {\r
+ if (!options.disabled) {\r
+ $(this).addClass(hover);\r
+ }\r
+ self.hovered = true;\r
+ }, function() {\r
+ $(this).removeClass(hover);\r
+ self.hovered = false;\r
+ });\r
+\r
+ // TODO: need a better way to exclude IE8 without resorting to $.browser.version\r
+ // fix inline-block issues for IE. Since IE8 supports inline-block we need to exclude it.\r
+ if (!$.support.opacity && uiSpinner.css('display') == 'inline-block' && $.browser.version < 8) {\r
+ uiSpinner.css('display', 'inline');\r
+ }\r
+\r
+ this.element\r
+ .bind('keydown'+namespace, function(event) {\r
+ return self._start(event) ? self._keydown(event) : false;\r
+ })\r
+ .bind('keyup'+namespace, function(event) {\r
+ if (self.spinning) {\r
+ self._stop(event);\r
+ self._change(event); \r
+ }\r
+ })\r
+ .bind('focus'+namespace, function() {\r
+ uiSpinner.addClass(active);\r
+ self.focused = true;\r
+ })\r
+ .bind('blur'+namespace, function(event) {\r
+ self._value(self.element.val());\r
+ if (!self.hovered) {\r
+ uiSpinner.removeClass(active);\r
+ } \r
+ self.focused = false;\r
+ });\r
+\r
+ // force width if passed through options\r
+ if (options.width) {\r
+ this.element.width(options.width);\r
+ }\r
+\r
+ // disable spinner if element was already disabled\r
+ if (options.disabled) {\r
+ this.disable();\r
+ }\r
+ \r
+ // button bindings\r
+ this.buttons = uiSpinner.find('.ui-spinner-button')\r
+ .bind('mousedown', function(event) { \r
+ if (self._start(event) === false) {\r
+ return false;\r
+ }\r
+ self._repeat(null, $(this).hasClass('ui-spinner-up') ? 1 : -1, event);\r
+ \r
+ if (!self.options.disabled) {\r
+ $(this).addClass(active);\r
+ uiSpinner.addClass(active);\r
+ }\r
+ })\r
+ .bind('mouseup', function(event) {\r
+ if (self.counter == 1) {\r
+ self._spin(($(this).hasClass('ui-spinner-up') ? 1 : -1) * self._step(), event);\r
+ }\r
+ if (self.spinning) {\r
+ self._stop(event);\r
+ self._change(event); \r
+ }\r
+ $(this).removeClass(active);\r
+ })\r
+ .hover(function() {\r
+ if (!self.options.disabled) {\r
+ $(this).addClass(hover); \r
+ }\r
+ }, function(event) {\r
+ $(this).removeClass(active + ' ' + hover);\r
+ if (self.timer && self.spinning) {\r
+ self._stop(event);\r
+ self._change(event);\r
+ }\r
+ });\r
+ \r
+ self.uiSpinner = uiSpinner;\r
+ },\r
+ _uiSpinnerHtml: function() {\r
+ return '<div role="spinbutton" class="' + uiSpinnerClasses + \r
+ (this.options.spinnerClass || '') + \r
+ ' ui-spinner-' + this.options.dir + \r
+ '"></div>';\r
+ },\r
+ _buttonHtml: function() {\r
+ return '<a class="ui-spinner-button ui-spinner-up ui-state-default ui-corner-t' + this.options.dir.substr(-1,1) + \r
+ '"><span class="ui-icon ui-icon-triangle-1-n">▲</span></a>' +\r
+ '<a class="ui-spinner-button ui-spinner-down ui-state-default ui-corner-b' + this.options.dir.substr(-1,1) + \r
+ '"><span class="ui-icon ui-icon-triangle-1-s">▼</span></a>';\r
+ },\r
+ _start: function(event) {\r
+ if (!this.spinning && this._trigger('start', event, { value: this.value()}) !== false) {\r
+ if (!this.counter) {\r
+ this.counter = 1;\r
+ }\r
+ this.spinning = true;\r
+ return true;\r
+ }\r
+ return false;\r
+ },\r
+ _spin: function(step, event) {\r
+ if (this.options.disabled) {\r
+ return;\r
+ }\r
+ if (!this.counter) {\r
+ this.counter = 1;\r
+ }\r
+ \r
+ var newVal = this._value() + step * (this.options.incremental && this.counter > 100\r
+ ? this.counter > 200\r
+ ? 100 \r
+ : 10\r
+ : 1);\r
+ \r
+ // cancelable\r
+ if (this._trigger('spin', event, { value: newVal }) !== false) {\r
+ this._value(newVal);\r
+ this.counter++; \r
+ }\r
+ },\r
+ _stop: function(event) {\r
+ this.counter = 0;\r
+ if (this.timer) {\r
+ window.clearInterval(this.timer);\r
+ }\r
+ this.element[0].focus();\r
+ this.spinning = false;\r
+ this._trigger('stop', event);\r
+ },\r
+ _change: function(event) {\r
+ this._trigger('change', event);\r
+ },\r
+ _repeat: function(i, steps, event) {\r
+ var self = this;\r
+ i = i || 100;\r
+\r
+ if (this.timer) {\r
+ window.clearInterval(this.timer);\r
+ }\r
+ \r
+ this.timer = window.setInterval(function() {\r
+ self._repeat(self.options.incremental && self.counter > 20 ? 20 : i, steps, event);\r
+ }, i);\r
+ \r
+ self._spin(steps*self._step(), event);\r
+ },\r
+ _keydown: function(event) {\r
+ var o = this.options,\r
+ KEYS = $.ui.keyCode;\r
+\r
+ switch (event.keyCode) {\r
+ case KEYS.UP: this._repeat(null, event.shiftKey ? o.page : 1, event); break;\r
+ case KEYS.DOWN: this._repeat(null, event.shiftKey ? -o.page : -1, event); break;\r
+ case KEYS.PAGE_UP: this._repeat(null, o.page, event); break;\r
+ case KEYS.PAGE_DOWN: this._repeat(null, -o.page, event); break;\r
+ \r
+ case KEYS.HOME:\r
+ case KEYS.END:\r
+ if (event.shiftKey) {\r
+ return true;\r
+ }\r
+ this._value(this['_' + (event.keyCode == KEYS.HOME ? 'min':'max')]());\r
+ break;\r
+ \r
+ case KEYS.TAB:\r
+ case KEYS.BACKSPACE:\r
+ case KEYS.LEFT:\r
+ case KEYS.RIGHT:\r
+ case KEYS.PERIOD:\r
+ case KEYS.NUMPAD_DECIMAL:\r
+ case KEYS.NUMPAD_SUBTRACT:\r
+ return true;\r
+ \r
+ case KEYS.ENTER:\r
+ this.value(this.element.val());\r
+ return true;\r
+ \r
+ default: \r
+ if ((event.keyCode >= 96 && event.keyCode <= 105) || // numeric keypad 0-9\r
+ (new RegExp('[' + this._validChars() + ']', 'i').test(String.fromCharCode(event.keyCode)))) {\r
+ return true;\r
+ };\r
+ }\r
+ \r
+ return false;\r
+ },\r
+ _mousewheel: function() {\r
+ var self = this;\r
+ if ($.fn.mousewheel && self.options.mouseWheel) {\r
+ this.element.mousewheel(function(event, delta) {\r
+ delta = ($.browser.opera ? -delta / Math.abs(delta) : delta);\r
+ if (!self._start(event)) {\r
+ return false;\r
+ }\r
+ self._spin((delta > 0 ? 1 : -1) * self._step(), event); \r
+ if (self.timeout) {\r
+ window.clearTimeout(self.timeout);\r
+ }\r
+ self.timeout = window.setTimeout(function() {\r
+ if (self.spinning) {\r
+ self._stop(event);\r
+ self._change(event); \r
+ }\r
+ }, 400);\r
+ event.preventDefault(); \r
+ }); \r
+ }\r
+ },\r
+ _value: function(newVal) {\r
+ if (!arguments.length) {\r
+ return this._parse(this.element.val());\r
+ }\r
+ this._setOption('value', newVal);\r
+ },\r
+ _getData: function(key) {\r
+ switch (key) {\r
+ case 'min':\r
+ case 'max':\r
+ case 'step':\r
+ return this['_'+key]();\r
+ break;\r
+ }\r
+ return this.options[key];\r
+ },\r
+ _setOption: function(key, value) { \r
+ switch (key) {\r
+ case 'value':\r
+ value = this._parse(value);\r
+ if (value < this._min()) {\r
+ value = this._min();\r
+ }\r
+ if (value > this._max()) {\r
+ value = this._max();\r
+ }\r
+ break;\r
+ case 'spinnerClass':\r
+ this.uiSpinner\r
+ .removeClass(this.options.spinnerClass)\r
+ .addClass(uiSpinnerClasses + value);\r
+ break;\r
+ }\r
+\r
+ $.Widget.prototype._setOption.call( this, key, value );\r
+ \r
+ this._afterSetData(key, value);\r
+ },\r
+ _afterSetData: function(key, value) {\r
+ switch(key) {\r
+ case 'max':\r
+ case 'min':\r
+ case 'step':\r
+ if (value != null) {\r
+ // write attributes back to element if original exist\r
+ if (this.element.attr(key)) {\r
+ this.element.attr(key, value);\r
+ }\r
+ }\r
+ this._aria();\r
+ break;\r
+ case 'width':\r
+ this.element.width(value);\r
+ break;\r
+ case 'precision':\r
+ case 'value':\r
+ this._format(this._parse(this.options.value));\r
+ break;\r
+ }\r
+ },\r
+ _aria: function() {\r
+ this.uiSpinner\r
+ .attr('aria-valuemin', this._min())\r
+ .attr('aria-valuemax', this._max())\r
+ .attr('aria-valuenow', this.value());\r
+ },\r
+ _validChars: function() {\r
+ var radix = parseInt(this.options.radix);\r
+ return '\\-\\' + this.options.radixPoint + (this.options.groupSeparator\r
+ ? '\\' + this.options.groupSeparator\r
+ :'') + (radix < 10\r
+ ? '0-' + radix\r
+ : '0-9' + (radix > 10\r
+ ? 'a-' + String.fromCharCode('a'.charCodeAt(0) + radix - 11)\r
+ :''));\r
+ },\r
+ _parse: function(val) {\r
+ if (typeof val == 'string') {\r
+ if (this.options.groupSeparator) {\r
+ val = val.replace(new RegExp('\\'+this.options.groupSeparator,'g'), '');\r
+ }\r
+ val = val.replace(new RegExp('[^' + this._validChars() + ']', 'gi'), '').split(this.options.radixPoint);\r
+ result = parseInt(val[0] == '-' ? 0 : val[0] || 0, this.options.radix);\r
+ if (val.length > 1) {\r
+ result += parseInt(val[1], this.options.radix) / Math.pow(this.options.radix, val[1].length) *\r
+ // must test first character of val[0] for minus sign because -0 is parsed as 0 in result\r
+ (val[0].substr(0,1) == '-' ? -1 : 1);\r
+ }\r
+ val = result; \r
+ }\r
+ return isNaN(val) ? null : val;\r
+ },\r
+ _format: function(num) {\r
+ var regex = /(\d+)(\d{3})/,\r
+ options = this.options,\r
+ sym = options.currency || '',\r
+ dec = options.precision,\r
+ radix = options.radix,\r
+ group = options.groupSeparator,\r
+ pt = options.radixPoint,\r
+ neg = num < 0 ? '-' : '';\r
+ \r
+ for (\r
+ num = (\r
+ isNaN(num)\r
+ ? options.value\r
+ : radix === 10\r
+ ? parseFloat(num, radix).toFixed(dec) \r
+ : parseInt(num, radix)\r
+ ).toString(radix).replace('.', pt);\r
+ regex.test(num) && group;\r
+ num = num.replace(regex, '$1'+group+'$2')\r
+ );\r
+\r
+ result = num.replace('-','');\r
+ while (options.padding && (result.length < options.padding)) {\r
+ result = '0' + result;\r
+ } \r
+ this.element.val(neg + sym + result);\r
+ },\r
+ _getOption: function(key, defaultValue) {\r
+ return this._parse(this.options[key] !== null\r
+ ? this.options[key]\r
+ : this.element.attr(key)\r
+ ? this.element.attr(key)\r
+ : defaultValue);\r
+ },\r
+ _step: function(newVal) {\r
+ if (!arguments.length) {\r
+ return this._getOption('step', 1);\r
+ }\r
+ this._setOption('step', newVal);\r
+ },\r
+ _min: function(newVal) {\r
+ if (!arguments.length) {\r
+ return this._getOption('min', -Number.MAX_VALUE);\r
+ }\r
+ this._setOption('min', newVal);\r
+ },\r
+ _max: function(newVal) {\r
+ if (!arguments.length) {\r
+ return this._getOption('max', Number.MAX_VALUE);\r
+ }\r
+ this._setOption('max', newVal);\r
+ },\r
+ \r
+ destroy: function() {\r
+ if ($.fn.mousewheel) {\r
+ this.element.unmousewheel();\r
+ }\r
+ \r
+ this.element\r
+ .removeClass('ui-spinner-input')\r
+ .removeAttr('disabled')\r
+ .removeAttr('autocomplete')\r
+ .removeData('spinner')\r
+ .unbind(namespace);\r
+ \r
+ this.uiSpinner.replaceWith(this.element); \r
+ },\r
+ enable: function() {\r
+ this.element\r
+ .removeAttr('disabled')\r
+ .siblings()\r
+ .removeAttr('disabled')\r
+ .parent()\r
+ .removeClass('ui-spinner-disabled ui-state-disabled');\r
+ this.options.disabled = false;\r
+ },\r
+ disable: function() {\r
+ this.element\r
+ .attr('disabled', true)\r
+ .siblings()\r
+ .attr('disabled', true)\r
+ .parent()\r
+ .addClass('ui-spinner-disabled ui-state-disabled');\r
+ this.options.disabled = true;\r
+ },\r
+ value: function(newVal) {\r
+ if (!arguments.length) {\r
+ return this._value();\r
+ } \r
+ this._value(newVal);\r
+ },\r
+ stepUp: function(steps) {\r
+ this._spin((steps || 1) * this._step(), null);\r
+ return this;\r
+ },\r
+ stepDown: function(steps) {\r
+ this._spin((steps || 1) * -this._step(), null); \r
+ return this;\r
+ },\r
+ pageUp: function(pages) {\r
+ return this.stepUp((pages || 1) * this.options.page); \r
+ },\r
+ pageDown: function(pages) {\r
+ return this.stepDown((pages || 1) * this.options.page); \r
+ },\r
+ \r
+ widget: function() {\r
+ return this.uiSpinner;\r
+ }\r
+});\r
+\r
+})(jQuery);\r