r2946 - spinner: further code clean-up and bugfixes in _parse and _format methods.

r2946 - spinner: further code clean-up and bugfixes in _parse and _format methods.


Author: pazu2k@gmail.com
Date: Mon Jul 20 02:07:03 2009
New Revision: 2946
Modified:
branches/dev/spinner/ui/ui.spinner.js
Log:
spinner: further code clean-up and bugfixes in _parse and _format methods.
Modified: branches/dev/spinner/ui/ui.spinner.js
==============================================================================
--- branches/dev/spinner/ui/ui.spinner.js    (original)
+++ branches/dev/spinner/ui/ui.spinner.js    Mon Jul 20 02:07:03 2009
@@ -19,27 +19,20 @@
$.widget('ui.spinner', {
    _init: function() {
-        // currentDelay can't be initialized as part of the prototype because
all widgets would share the same object
-        this.currentDelay = {};            
        
        this._initOptions();
        
        // set value on init
-        this._value(this._value());    
+        this._value(this._value() || this.options.value);    
        // draw widget
-        this._draw();
+        this._draw();        
            
        if (this.options.hide) {
            this._hide();
        }
        this._mousewheel();
-                
-        // disable spinner if element was already disabled
-        if (this.element.attr("disabled")) {
-            this.disable();
-        }
    },
    _initOptions: function() {
        var self = this,
@@ -87,15 +80,17 @@
            spinnerClass = options.spinnerClass,
            spinnerBoxClass = 'ui-spinner-box',
            widgetClasses = 'ui-spinner ui-state-default ui-widget
ui-widget-content ui-corner-all ui-spinner-' + dir + (spinnerClass ? ' '+
spinnerClass: '');
-        
+
        var widget = self.element
            .addClass(spinnerBoxClass)
            .attr('autocomplete', 'off') // switch off autocomplete in opera
            .wrap('<div role="spinbutton">')
            .parent()
                .addClass(widgetClasses)
-                .append('<a class="ui-spinner-button ui-spinner-up ui-state-default
ui-corner-t'+ dir.substr(-1,1) +'"><span
class="ui-spinner-button-inner"><span class="ui-icon
ui-icon-triangle-1-n">&#9650;</span></span></a>')
-                .append('<a class="ui-spinner-button ui-spinner-down ui-state-default
ui-corner-b'+ dir.substr(-1,1) +'"><span
class="ui-spinner-button-inner"><span class="ui-icon
ui-icon-triangle-1-s">&#9660;</span></span></a>');
+                .append(
+                    '<a class="ui-spinner-button ui-spinner-up ui-state-default
ui-corner-t'+ dir.substr(-1,1) +'"><span
class="ui-spinner-button-inner"><span class="ui-icon
ui-icon-triangle-1-n">&#9650;</span></span></a>' +
+                    '<a class="ui-spinner-button ui-spinner-down ui-state-default
ui-corner-b'+ dir.substr(-1,1) +'"><span
class="ui-spinner-button-inner"><span class="ui-icon
ui-icon-triangle-1-s">&#9660;</span></span></a>'
+                );
        // TODO: need a better way to exclude IE8 without resorting to
$.browser.version
        // fix inline-block issues for IE. Since IE8 supports inline-block we
need to exclude it.
@@ -138,8 +133,8 @@
                    self._delay(self._hide, 100, 'hide', options.hide);
                }
            });
-        
-        self.buttons = widget.find('.ui-spinner-button')
+
+        this.buttons = widget.find('.ui-spinner-button')
            .bind('mousedown', function(event) {
                self._start(event);
                self._mousedown(100, $(this).hasClass('ui-spinner-up') ? 1 : -1,
event);
@@ -182,12 +177,12 @@
                }
            });
-        self.element
+        this.element
            .bind('keydown'+namespace, function(event) {
                self._start(event);
            })
            .bind('keypress'+namespace, function(event) {
-                return self._keydown.call(self, event);
+                return self._keydown(event);
            })
            .bind('keyup'+namespace, function(event) {
                self._stop(event);
@@ -213,15 +208,21 @@
                    self._delay(self._hide, 100, 'hide', options.hide);
                }
                self._cleanUp();
-            });
+            });        
+
+        // disable spinner if element was already disabled
+        if (this.element.attr("disabled")) {
+            this.disable();
+        }
                    
-        self.widget = widget;
+        self.widget = widget;        
    },
    _constrain: function() {
-        if (this.options.min !== null && this._value() < this.options.min) {
+        var value = this._value();
+        if (value < this.options.min) {
            this._value(this.options.min);
        }
-        if (this.options.max !== null && this._value() > this.options.max) {
+        if (value > this.options.max) {
            this._value(this.options.max);
        }
    },
@@ -230,11 +231,15 @@
        this._constrain();
    },
    _start: function(event) {
-        if (!this.counter) {
-            this.counter = 1;
+        if (!self.spinning) {
+            if (!this.counter) {
+                this.counter = 1;
+            }
+            this.spinning = true;
+            this._trigger('start', event, {
+                value: this.value()
+            });
        }
-        this.spinning = true;
-        this._trigger('start', event, { value: this.value() });
    },
    _spin: function(step, event) {
        if (this.disabled) {
@@ -276,7 +281,7 @@
    },
    _keydown: function(event) {
        var o = this.options,
-            jump = o.page * o.step;
+            jump = o.page * o.step,
            KEYS = $.ui.keyCode;
        switch (event.keyCode) {
@@ -297,8 +302,9 @@
                return true;
                
            default:                
+                var code = event.keyCode || event.charCode;
                if ((event.keyCode >= 96 && event.keyCode <= 105) || // numeric keypad
0-9
-                    (new RegExp('[' + this._validChars()
+ ']', 'i').test(String.fromCharCode(event.keyCode)))) {
+                    (new RegExp('[' + this._validChars()
+ ']', 'i').test(String.fromCharCode(code)))) {
                    return true;
                };
        }
@@ -310,9 +316,7 @@
        if ($.fn.mousewheel && self.options.mouseWheel) {
            this.element.mousewheel(function(event, delta) {
                delta = ($.browser.opera ? -delta / Math.abs(delta) : delta);
-                if (!self.spinning) {
-                    self._start(event);
-                }
+                self._start(event);
                self._spin((delta > 0 ? 1 : -1) * self.options.step, event);
                if (self.timeout) {
                    window.clearTimeout(self.timeout);
@@ -325,39 +329,21 @@
            });            
        }
    },
-    _parse: function(val) {
-        if (typeof val == 'string') {
-            // Because groupSeparator is included in the regex, we must replace it
independently
-            if (this.options.groupSeparator) {
-                val = val.replace(this.options.groupSeparator, '');
-            }
-    
-            val = val.replace(new RegExp('[^' + this._validChars()
+ ']', 'gi'), '').split(this.options.radixPoint);
-            
-            result = parseInt(val[0], this.options.radix);
-            if (val.length > 1) {
-                result += parseInt(val[1], this.options.radix) /
Math.pow(this.options.radix, val[1].length) *
-                    // must test first character of val[0] for minus sign because -0 is
parsed as 0 in result
-                    (val[0][0] == '-' ? -1 : 1);
-            }
-            val = result;            
-        }
-        return isNaN(val) ? null : val;
-    },
    _value: function(newVal) {
        if (!arguments.length) {
-            var value = this._parse(this.element.val());
-            return isNaN(value) ? this.options.value : value;            
+            return this._parse(this.element.val());
        }
        
-        this.element.val(this._format(newVal));
+        this._format(newVal);
        this.element.parents('.' + this.widgetBaseClass
+ ':first').attr('aria-valuenow', this.value());
    },
        
    // delays a function call, allowing only one at a time of the same type
    _delay: function(callback, delay, type) {
        type = type || 'a';
-
+        if (!this.currentDelay) {
+            this.currentDelay = {};
+        }
        var self = this,
            curDelay = self.currentDelay[type] || {},
            args = Array.prototype.slice.call(arguments, 3);
@@ -387,7 +373,6 @@
        return this;
    },
    _hide: function(speed) {
-        // also removeClass(hover) in case it was left despite losing mouse hover
        var buttons = this.buttons.stop().removeClass(hover);
        if (!speed) {
            buttons.css('opacity', 0);
@@ -420,32 +405,50 @@
        $.widget.prototype._setData.call(this, key, value);
    },
-    _format: function(num) {
-        var sym = this.options.currency ? this.options.currency : '',
-            dec = this.options.currency ? 2 : this._precision,
-            radix = this.options.currency ? 10 : this.options.radix,
-            group = this.options.currency ? (this.options.groupSeparator || ',') :
this.options.groupSeprator,        
-            whole = Math.floor(Math.abs(num)),
-            result = whole.toString(radix),
-            part = Math.floor(((Math.abs(num) - whole) * Math.pow(radix,
dec))).toString(radix),
-            regex = /(\d+)(\d{3})/;
-        
-        while (regex.test(result) && group) {
-            result = result.replace(regex, '$1'+group+'$2');
-        }
-        
-        if (dec > 0) {
-            while (part.length < dec) {
-                part = '0' + part;
+    _parse: function(val) {
+        if (typeof val == 'string') {
+            if (this.options.groupSeparator) {
+                val = val.replace(new
RegExp('\\'+this.options.groupSeparator,'g'), '');
            }
-            result += this.options.radixPoint + part;
+            val = val.replace(new RegExp('[^' + this._validChars()
+ ']', 'gi'), '').split(this.options.radixPoint);
+            
+            result = parseInt(val[0], this.options.radix);
+            if (val.length > 1) {
+                result += parseInt(val[1], this.options.radix) /
Math.pow(this.options.radix, val[1].length) *
+                    // must test first character of val[0] for minus sign because -0 is
parsed as 0 in result
+                    (val[0][0] == '-' ? -1 : 1);
+            }
+            val = result;            
        }
-        
-        while (this.options.padLength && (result.length <
this.options.padLength)) {
+        return isNaN(val) ? null : val;
+    },
+    _format: function(num) {
+        var regex = /(\d+)(\d{3})/,
+            options = this.options,
+            sym = options.currency ? options.currency : '',
+            dec = options.currency ? 2 : this._precision,
+            radix = options.currency ? 10 : options.radix,
+            group = options.currency ? (options.groupSeparator || ',') :
options.groupSeparator,
+            pt = options.radixPoint;
+            
+        for (
+            num = (
+                isNaN(num)
+                    ? options.value
+                    : radix === 10
+                        ? parseFloat(num, radix).toFixed(dec)
+                        : parseInt(num, radix)
+                ).toString(radix).replace('.', pt);
+            regex.test(num) && group;
+            num = num.replace(regex, '$1'+group+'$2')
+        );
+
+        result = num.replace('-','');
+        while (options.padLength && (result.length < options.padLength)) {
            result = '0' + result;
        }
        
-        return (num < 0 ? '-' : '') + sym + result;
+        this.element.val((num < 0 ? '-' : '') + sym + result);
    },
    
    destroy: function() {