mirror of
https://github.com/jquery/jquery-ui.git
synced 2025-01-07 20:34:24 +00:00
Added enhancements to ui.spinner as seen at http://yelotofu.com/labs/jquery/UI/spinner/spinner.html
Enhancements include: - removal of all hardcoded styling for better theming capability - visual test page made more appealing supporting browser zooming - added utility functions to disable, enable and destroy ui.spinner - up/down buttons listens to more mouse and keyboard events - support for decimal and currency format - ui.spinner now restricts input on keydown - cleanup occurs when the input textbox loses focus. this seems to be a better approach for future scalability
This commit is contained in:
parent
b4e2e0e9ca
commit
198d809f9b
BIN
tests/images/spinner-bg.gif
Normal file
BIN
tests/images/spinner-bg.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 218 B |
@ -1,37 +1,97 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
|
||||
<title>Untitled Document</title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>jQuery UI Spinner Test page</title>
|
||||
<script type="text/javascript" src="../../jquery-1.2.6.js"></script>
|
||||
<script type="text/javascript" src="../../ui/ui.core.js"></script>
|
||||
<script type="text/javascript" src="../../ui/ui.spinner.js"></script>
|
||||
|
||||
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
<script type="text/javascript">
|
||||
$(function(){
|
||||
|
||||
$("input").spinner();
|
||||
var opts = {
|
||||
's1': {},
|
||||
's2': {stepping: 0.25},
|
||||
's3': {currency: '$'}
|
||||
};
|
||||
|
||||
for (var n in opts)
|
||||
$("#"+n).spinner(opts[n]);
|
||||
|
||||
$("button").click(function(e){
|
||||
var ns = $(this).attr('id').match(/(s\d)\-(\w+)$/);
|
||||
if (ns != null)
|
||||
$('#'+ns[1]).spinner( (ns[2] == 'create') ? opts[ns[1]] : ns[2]);
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
|
||||
<style type="text/css">
|
||||
body {
|
||||
body
|
||||
{
|
||||
background: #fff;
|
||||
color:#333;
|
||||
font-size:11px;
|
||||
font-family:"lucida grande", tahoma, verdana, arial, sans-serif;
|
||||
font-family: Arial;
|
||||
}
|
||||
|
||||
.ui-spinner-down, .ui-spinner-up {
|
||||
background: #999;
|
||||
width: 100%;
|
||||
label {
|
||||
float: left;
|
||||
margin-right: .5em;
|
||||
padding: .15em 0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ui-spinner {
|
||||
border: 1px solid black;
|
||||
width: 15em;
|
||||
display: block;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: 1px solid #999;
|
||||
background: #FEFEFE url(../images/spinner-bg.gif) repeat-x left bottom;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.ui-spinner-disabled {
|
||||
background: #F4F4F4;
|
||||
}
|
||||
|
||||
.ui-spinner-box {
|
||||
width: 90%;
|
||||
height: 100%;
|
||||
float: left;
|
||||
font-size: 125%;
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.ui-spinner-up,
|
||||
.ui-spinner-down {
|
||||
width: 10%;
|
||||
height: 50%;
|
||||
font-size: 0.5em;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
z-index: 100;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
cursor: default;
|
||||
border: 1px solid #999;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.ui-spinner-down {
|
||||
bottom: 0;
|
||||
border-bottom: 0;
|
||||
}
|
||||
|
||||
.ui-spinner-pressed {
|
||||
background: #FEFEFE;
|
||||
}
|
||||
|
||||
</style>
|
||||
@ -39,7 +99,45 @@ font-family:"lucida grande", tahoma, verdana, arial, sans-serif;
|
||||
|
||||
<body>
|
||||
|
||||
<input type="text" id="input" />
|
||||
<h1>jQuery UI Spinner Test Page</h1>
|
||||
|
||||
<p>This is a visual test page for developers and demonstrates some of the features included in ui.spinner. Mousewheel support is provided by the <a href="http://plugins.jquery.com/project/mousewheel">mousewheel plugin</a>.</p>
|
||||
|
||||
<p><label for="s1">Basic: </label>
|
||||
<input type="text" id="s1" value="10" /></p>
|
||||
|
||||
<p>
|
||||
<button id="s1-disable">disable</button>
|
||||
<button id="s1-enable">enable</button>
|
||||
<button id="s1-destroy">destroy</button>
|
||||
<button id="s1-create">create</button>
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<p><label for="s2">Decimal: </label>
|
||||
<input type="text" id="s2" value="10.25" /></p>
|
||||
|
||||
<p>
|
||||
<button id="s2-disable">disable</button>
|
||||
<button id="s2-enable">enable</button>
|
||||
<button id="s2-destroy">destroy</button>
|
||||
<button id="s2-create">create</button>
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<p><label for="s3">Currency: </label>
|
||||
<input type="text" id="s3" /></p>
|
||||
|
||||
<p>
|
||||
<button id="s3-disable">disable</button>
|
||||
<button id="s3-enable">enable</button>
|
||||
<button id="s3-destroy">destroy</button>
|
||||
<button id="s3-create">create</button>
|
||||
</p>
|
||||
|
||||
<hr />
|
||||
|
||||
</body>
|
||||
</html>
|
288
ui/ui.spinner.js
288
ui/ui.spinner.js
@ -12,127 +12,295 @@
|
||||
*/
|
||||
(function($) {
|
||||
|
||||
$.widget("ui.spinner", {
|
||||
$.widget('ui.spinner', {
|
||||
_init: function() {
|
||||
if($.data(this.element[0], 'spinner')) return;
|
||||
|
||||
// check for decimals in steppinng and set _decimals as internal (needs cleaning up)
|
||||
var decimals = 0;
|
||||
if (this.options.stepping.toString().indexOf('.') != -1) {
|
||||
var s = this.options.stepping.toString();
|
||||
decimals = s.slice(s.indexOf('.')+1, s.length).length;
|
||||
}
|
||||
$.extend(this.options, {
|
||||
_decimals: decimals
|
||||
});
|
||||
|
||||
//Initialize needed constants
|
||||
var self = this;
|
||||
this.element.addClass("ui-spinner");
|
||||
this.element[0].value = this.options.start;
|
||||
|
||||
var pickerHeight = this.element.innerHeight() / 2 - parseInt(this.element.css("borderTopWidth"),10) - 2;
|
||||
this.element
|
||||
.wrap("<div>")
|
||||
.addClass('ui-spinner-box')
|
||||
.attr('autocomplete', 'off'); // switch off autocomplete in opera
|
||||
|
||||
this._setValue( isNaN(this._getValue()) ? this.options.start : this._getValue() );
|
||||
|
||||
this.element
|
||||
.wrap('<div>')
|
||||
.parent()
|
||||
.css({
|
||||
position: this.element.css("position") == "static" ? "relative" : this.element.css("position"),
|
||||
left: this.element.css("left"),
|
||||
top: this.element.css("top"),
|
||||
width: this.element.outerWidth(),
|
||||
height: this.element.outerHeight()
|
||||
.addClass('ui-spinner')
|
||||
.append('<button class="ui-spinner-up">▲</button>')
|
||||
.find('.ui-spinner-up')
|
||||
.bind('mousedown', function(e) {
|
||||
$(this).addClass('ui-spinner-pressed');
|
||||
if(!self.counter) self.counter = 1;
|
||||
self._mousedown(100, '_up', e);
|
||||
})
|
||||
.bind('mouseup', function(e) {
|
||||
$(this).removeClass('ui-spinner-pressed');
|
||||
if(self.counter == 1) self._up(e);
|
||||
self._mouseup(e);
|
||||
})
|
||||
.bind('mouseout', function(e) {
|
||||
$(this).removeClass('ui-spinner-pressed');
|
||||
self._mouseup(e);
|
||||
})
|
||||
// mousedown/mouseup capture first click, now handle second click
|
||||
.bind('dblclick', function(e) {
|
||||
$(this).removeClass('ui-spinner-pressed');
|
||||
self._up(e);
|
||||
})
|
||||
.bind('keydown.spinner', function(e) {
|
||||
var KEYS = $.ui.spinner.keys;
|
||||
if (e.keyCode == KEYS.SPACE || e.keyCode == KEYS.RETURN) {
|
||||
$(this).addClass('ui-spinner-pressed');
|
||||
if(!self.counter) self.counter = 1;
|
||||
self._up.call(self, e);
|
||||
} else if (e.keyCode == KEYS.DOWN || e.keyCode == KEYS.RIGHT) {
|
||||
self.element.siblings('.ui-spinner-down').focus();
|
||||
} else if (e.keyCode == KEYS.LEFT) {
|
||||
self.element.focus();
|
||||
}
|
||||
})
|
||||
.bind('keyup.spinner', function(e) {
|
||||
$(this).removeClass('ui-spinner-pressed');
|
||||
self.counter = 0;
|
||||
self._propagate('change', e);
|
||||
})
|
||||
.css("float", this.element.css("float"))
|
||||
.prepend('<div class="ui-spinner-up"></div>')
|
||||
.find("div.ui-spinner-up")
|
||||
.bind("mousedown", function() { if(!self.counter) self.counter = 1; self._mousedown(100, "_up"); })
|
||||
.bind("mouseup", function(e) { if(self.counter == 1) self._up(); self.counter = 0; if(self.timer) window.clearInterval(self.timer); self.element[0].focus(); self._propagate("change", e); })
|
||||
.bind("dblclick", function(e) { self._up(); }) // mousedown/mouseup capture first click, now handle second click
|
||||
.css({ height: pickerHeight, top: parseInt(this.element.css("borderTopWidth"),10)+1, right: parseInt(this.element.css("borderRightWidth"),10)+1 })
|
||||
.end()
|
||||
.append('<div class="ui-spinner-down"></div>')
|
||||
.find("div.ui-spinner-down")
|
||||
.bind("mousedown", function() { if(!self.counter) self.counter = 1; self._mousedown(100, "_down"); })
|
||||
.bind("mouseup", function(e) { if(self.counter == 1) self._down(); self.counter = 0; if(self.timer) window.clearInterval(self.timer); self.element[0].focus(); self._propagate("change", e); })
|
||||
.bind("dblclick", function(e) { self._down(); }) // mousedown/mouseup capture first click, now handle second click
|
||||
.css({ height: pickerHeight, bottom: parseInt(this.element.css("borderBottomWidth"),10)+1, right: parseInt(this.element.css("borderRightWidth"),10)+1 })
|
||||
.end()
|
||||
;
|
||||
.append('<button class="ui-spinner-down">▼</button>')
|
||||
.find('.ui-spinner-down')
|
||||
.bind('mousedown', function(e) {
|
||||
$(this).addClass('ui-spinner-pressed');
|
||||
if(!self.counter) self.counter = 1;
|
||||
self._mousedown(100, '_down', e);
|
||||
})
|
||||
.bind('mouseup', function(e) {
|
||||
$(this).removeClass('ui-spinner-pressed');
|
||||
if(self.counter == 1) self._down();
|
||||
self._mouseup(e);
|
||||
})
|
||||
.bind('mouseout', function(e) {
|
||||
$(this).removeClass('ui-spinner-pressed');
|
||||
self._mouseup(e);
|
||||
})
|
||||
// mousedown/mouseup capture first click, now handle second click
|
||||
.bind('dblclick', function(e) {
|
||||
$(this).removeClass('ui-spinner-pressed');
|
||||
self._down(e);
|
||||
})
|
||||
.bind('keydown.spinner', function(e) {
|
||||
var KEYS = $.ui.spinner.keys;
|
||||
if (e.keyCode == KEYS.SPACE || e.keyCode == KEYS.RETURN) {
|
||||
$(this).addClass('ui-spinner-pressed');
|
||||
if(!self.counter) self.counter = 1;
|
||||
self._down.call(self, e);
|
||||
} else if (e.keyCode == KEYS.UP || e.keyCode == KEYS.LEFT) {
|
||||
self.element.siblings('.ui-spinner-up').focus();
|
||||
}
|
||||
})
|
||||
.bind('keyup.spinner', function(e) {
|
||||
$(this).removeClass('ui-spinner-pressed');
|
||||
self.counter = 0;
|
||||
self._propagate('change', e);
|
||||
})
|
||||
.end();
|
||||
|
||||
this.element
|
||||
.bind("keydown.spinner", function(e) {
|
||||
.bind('keydown.spinner', function(e) {
|
||||
if(!self.counter) self.counter = 1;
|
||||
self._keydown.call(self, e);
|
||||
return self._keydown.call(self, e);
|
||||
})
|
||||
.bind("keyup.spinner", function(e) {
|
||||
.bind('keyup.spinner', function(e) {
|
||||
self.counter = 0;
|
||||
self._cleanUp();
|
||||
self._propagate("change", e);
|
||||
self._propagate('change', e);
|
||||
})
|
||||
;
|
||||
if ($.fn.mousewheel) {
|
||||
this.element.mousewheel(function(e, delta) { self._mousewheel(e, delta); });
|
||||
}
|
||||
.bind('blur.spinner', function(e) {
|
||||
self._cleanUp()
|
||||
});
|
||||
|
||||
if ($.fn.mousewheel) {
|
||||
this.element.mousewheel(function(e, delta) {
|
||||
self._mousewheel(e, delta);
|
||||
});
|
||||
}
|
||||
},
|
||||
plugins: {},
|
||||
|
||||
_constrain: function() {
|
||||
if(this.options.min != undefined && this.element[0].value < this.options.min) this.element[0].value = this.options.min;
|
||||
if(this.options.max != undefined && this.element[0].value > this.options.max) this.element[0].value = this.options.max;
|
||||
if(this.options.min != undefined && this._getValue() < this.options.min) this._setValue(this.options.min);
|
||||
if(this.options.max != undefined && this._getValue() > this.options.max) this._setValue(this.options.max);
|
||||
},
|
||||
_cleanUp: function() {
|
||||
this.element[0].value = this.element[0].value.replace(/[^0-9\-]/g, '');
|
||||
this._setValue(this._getValue());
|
||||
this._constrain();
|
||||
},
|
||||
_spin: function(d, e) {
|
||||
if(isNaN(parseInt(this.element[0].value,10))) this.element[0].value = this.options.start;
|
||||
this.element[0].value = parseFloat(this.element[0].value) + ( d == "up" ? 1 : -1 ) * (this.options.incremental && this.counter > 100 ? (this.counter > 200 ? 100 : 10) : 1) * this.options.stepping;
|
||||
if (this.disabled) return;
|
||||
|
||||
if(isNaN(this._getValue())) this._setValue(this.options.start);
|
||||
this._setValue(this._getValue() + (d == 'up' ? 1:-1) * (this.options.incremental && this.counter > 100 ? (this.counter > 200 ? 100 : 10) : 1) * this.options.stepping);
|
||||
this._constrain();
|
||||
if(this.counter) this.counter++;
|
||||
this._propagate("spin", e);
|
||||
this._propagate('spin', e);
|
||||
|
||||
},
|
||||
_down: function(e) {
|
||||
this._spin("down", e);
|
||||
this._spin('down', e);
|
||||
this._propagate('down', e);
|
||||
},
|
||||
_up: function(e) {
|
||||
this._spin("up", e);
|
||||
this._spin('up', e);
|
||||
this._propagate('up', e);
|
||||
},
|
||||
_mousedown: function(i, d) {
|
||||
_mousedown: function(i, d, e) {
|
||||
var self = this;
|
||||
i = i || 100;
|
||||
if(this.timer) window.clearInterval(this.timer);
|
||||
this.timer = window.setInterval(function() {
|
||||
self[d]();
|
||||
if(self.counter > 20) self._mousedown(20, d);
|
||||
self[d](e);
|
||||
if(self.counter > 20) self._mousedown(20, d, e);
|
||||
}, i);
|
||||
},
|
||||
_mouseup: function(e) {
|
||||
this.counter = 0;
|
||||
if(this.timer) window.clearInterval(this.timer);
|
||||
this.element[0].focus();
|
||||
this._propagate('change', e);
|
||||
},
|
||||
_keydown: function(e) {
|
||||
if(e.keyCode == 38 || e.keyCode == 39) this._up(e);
|
||||
if(e.keyCode == 40 || e.keyCode == 37) this._down(e);
|
||||
if(e.keyCode == 36) this.element[0].value = this.options.min || this.options.start; //Home key goes to min, if defined, else to start
|
||||
if(e.keyCode == 35 && this.options.max != undefined) this.element[0].value = this.options.max; //End key goes to maximum
|
||||
var KEYS = $.ui.spinner.keys;
|
||||
|
||||
if(e.keyCode == KEYS.UP) this._up(e);
|
||||
if(e.keyCode == KEYS.DOWN) this._down(e);
|
||||
if(e.keyCode == KEYS.HOME) this._setValue(this.options.min || this.options.start); //Home key goes to min, if defined, else to start
|
||||
if(e.keyCode == KEYS.END && this.options.max != undefined) this._setValue(this.options.max); //End key goes to maximum
|
||||
return (e.keyCode == KEYS.TAB || e.keyCode == KEYS.BACKSPACE ||
|
||||
e.keyCode == KEYS.LEFT || e.keyCode == KEYS.RIGHT || e.keyCode == KEYS.PERIOD ||
|
||||
(/[0-9\-\.]/).test(String.fromCharCode(e.keyCode))) ? true : false;
|
||||
},
|
||||
_mousewheel: function(e, delta) {
|
||||
delta = ($.browser.opera ? -delta / Math.abs(delta) : delta);
|
||||
delta > 0 ? this._up(e) : this._down(e);
|
||||
e.preventDefault();
|
||||
},
|
||||
_getValue: function() {
|
||||
return parseFloat(this.element[0].value.replace(/[^0-9\-\.]/g, ''));
|
||||
},
|
||||
_setValue: function(newVal) {
|
||||
if(isNaN(newVal)) newVal = this.options.start;
|
||||
this.element[0].value = (
|
||||
this.options.currency ?
|
||||
$.ui.spinner.format.currency(newVal, this.options.currency) :
|
||||
$.ui.spinner.format.number(newVal, this.options._decimals)
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
plugins: {},
|
||||
ui: function(e) {
|
||||
return {
|
||||
instance: this,
|
||||
options: this.options,
|
||||
element: this.element
|
||||
element: this.element,
|
||||
value: this._getValue()
|
||||
};
|
||||
},
|
||||
_propagate: function(n,e) {
|
||||
$.ui.plugin.call(this, n, [e, this.ui()]);
|
||||
return this.element.triggerHandler(n == "spin" ? n : "spin"+n, [e, this.ui()], this.options[n]);
|
||||
return this.element.triggerHandler(n == 'spin' ? n : 'spin'+n, [e, this.ui()], this.options[n]);
|
||||
},
|
||||
destroy: function() {
|
||||
if(!$.data(this.element[0], 'spinner')) return;
|
||||
|
||||
this.element
|
||||
.removeClass("ui-spinner ui-spinner-disabled")
|
||||
.removeData("spinner")
|
||||
.unbind(".spinner");
|
||||
.removeClass('ui-spinner-box')
|
||||
.removeAttr('disabled')
|
||||
.removeData('spinner')
|
||||
.unbind('.spinner')
|
||||
.siblings()
|
||||
.remove()
|
||||
.end()
|
||||
.parent()
|
||||
.removeClass('ui-spinner ui-spinner-disabled')
|
||||
.before(this.element.clone())
|
||||
.remove()
|
||||
.end();
|
||||
|
||||
if ($.fn.mousewheel) {
|
||||
this.element.unmousewheel();
|
||||
}
|
||||
},
|
||||
enable: function() {
|
||||
this.element
|
||||
.removeAttr('disabled')
|
||||
.siblings()
|
||||
.removeAttr('disabled')
|
||||
.parent()
|
||||
.removeClass('ui-spinner-disabled');
|
||||
this.disabled = false;
|
||||
},
|
||||
disable: function() {
|
||||
this.element
|
||||
.attr('disabled', true)
|
||||
.siblings()
|
||||
.attr('disabled', true)
|
||||
.parent()
|
||||
.addClass('ui-spinner-disabled');
|
||||
this.disabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
$.ui.spinner.defaults = {
|
||||
$.extend($.ui.spinner, {
|
||||
defaults: {
|
||||
stepping: 1,
|
||||
start: 0,
|
||||
incremental: true
|
||||
};
|
||||
incremental: true,
|
||||
currency: false
|
||||
},
|
||||
format: {
|
||||
number: function(num, dec) {
|
||||
return this.round(num, dec);
|
||||
},
|
||||
currency: function(num, sym) {
|
||||
return (num !== Math.abs(num) ? '-' : '') + sym + this.round(Math.abs(num), 2);
|
||||
},
|
||||
round: function(num, dec) {
|
||||
if (dec > 0) {
|
||||
var s = num + ((num.toString().indexOf('.') == -1) ? '.' : '') + '0000000001';
|
||||
s = s.substr(0, s.indexOf('.')+1+dec);
|
||||
} else {
|
||||
var s = Math.round(num);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
},
|
||||
keys: {
|
||||
BACKSPACE: 8,
|
||||
TAB: 9,
|
||||
RETURN: 13,
|
||||
ESC: 27,
|
||||
SPACE: 32,
|
||||
PAGEUP: 33,
|
||||
PAGEDOWN: 34,
|
||||
END: 35,
|
||||
HOME: 36,
|
||||
LEFT: 37,
|
||||
UP: 38,
|
||||
RIGHT: 39,
|
||||
DOWN: 40,
|
||||
DEL: 46,
|
||||
COMMA: 188,
|
||||
PERIOD: 190
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
Loading…
Reference in New Issue
Block a user