r2581 - Spinner: added autoHide option to hide spinner on blur/mouseout, disable spinner if input...
Author: btburnett3
Date: Sat May 16 14:28:55 2009
New Revision: 2581
Added:
branches/dev/spinner/demos/spinner/autohide.html
Modified:
branches/dev/spinner/demos/spinner/index.html
branches/dev/spinner/ui/ui.spinner.js
Log:
Spinner: added autoHide option to hide spinner on blur/mouseout, disable
spinner if input is disabled on create, added hover effects to buttons,
minor changes to improve minimization
Added: branches/dev/spinner/demos/spinner/autohide.html
==============================================================================
--- (empty file)
+++ branches/dev/spinner/demos/spinner/autohide.html Sat May 16 14:28:55
2009
@@ -0,0 +1,54 @@
+<!doctype html>
+<html lang="en">
+<head>
+ <title>jQuery UI Spinner - Hiding</title>
+ <link type="text/css" href="../../themes/base/ui.all.css"
rel="stylesheet" />
+ <script type="text/javascript" src="../../jquery-1.3.2.js"></script>
+ <script type="text/javascript"
src="../../external/mousewheel/jquery.mousewheel.min.js"></script>
+ <script type="text/javascript" src="../../ui/ui.core.js"></script>
+ <script type="text/javascript" src="../../ui/ui.spinner.js"></script>
+ <link type="text/css" href="../demos.css" rel="stylesheet" />
+ <script type="text/javascript">
+ $(function() {
+ $("#s1, #s2").spinner({autoHide: true});
+
+ $("#autohide").toggle(function() {
+ $("#s1, #s2").spinner("option", "autoHide", false);
+ }, function() {
+ $("#s1, #s2").spinner("option", "autoHide", true);
+ });
+ $("#hide").click(function() {
+ $("#s1, #s2").spinner("hideButtons");
+ });
+ $("#show").click(function() {
+ $("#s1, #s2").spinner("showButtons");
+ });
+ });
+ </script>
+</head>
+<body>
+
+<div class="demo">
+
+<label for="s1">Select a value:</label>
+<input id="s1" name="value" />
+
+<label for="s2">Select a value:</label>
+<input id="s2" name="value" />
+
+
+<button id="autohide" class="ui-button ui-state-default
ui-corner-all">Toggle auto hide</button>
+<button id="hide" class="ui-button ui-state-default ui-corner-all">Hide
buttons</button>
+<button id="show" class="ui-button ui-state-default ui-corner-all">Show
buttons</button>
+
+
+</div><!-- End demo -->
+
+<div class="demo-description">
+
+Hiding spinner.
+
+</div><!-- End demo-description -->
+
+</body>
+</html>
Modified: branches/dev/spinner/demos/spinner/index.html
==============================================================================
--- branches/dev/spinner/demos/spinner/index.html (original)
+++ branches/dev/spinner/demos/spinner/index.html Sat May 16 14:28:55 2009
@@ -14,6 +14,7 @@
<li><a href="list.html">List</a></li>
<li><a href="incremental.html">Incremental</a></li>
<li><a href="mousewheel-disabled.html">Mousewheel Disabled</a></li>
+ <li><a href="autohide.html">Hiding</a></li>
</ul>
</div>
</body>
Modified: branches/dev/spinner/ui/ui.spinner.js
==============================================================================
--- branches/dev/spinner/ui/ui.spinner.js (original)
+++ branches/dev/spinner/ui/ui.spinner.js Sat May 16 14:28:55 2009
@@ -12,9 +12,22 @@
*/
(function($) {
+// shortcut constants
+var hover = 'ui-state-hover',
+ active= 'ui-state-active',
+ namespace = '.spinner';
+
$.widget('ui.spinner', {
_init: function() {
- this._trigger('init', null, this.ui(null));
+ var self = this;
+
+ self._trigger('init', null, self.ui(null));
+
+ // initialize variables
+ // this can't be initialized as part of the prototype because all
widgets would share the same object
+ self._curDelay = {};
+ self.focused = false;
+ self.hovered = false;
// perform data bind on generic objects
if (this.options.items != null && typeof this.options.items[0]
== 'object' && !this.element.is('input')) {
@@ -32,15 +45,14 @@
}
//Initialize needed constants
- var self = this;
- this.element
+ self.element
.addClass('ui-spinner-box')
.attr('autocomplete', 'off') // switch off autocomplete in opera
.width(this.options.width);
- this._setValue( isNaN(this._getValue()) ? this.options.start :
this._getValue() );
+ self._setValue( isNaN(self._getValue()) ? self.options.start :
self._getValue() );
- this.element
+ var widget = self.element
.wrap('<div>')
.parent()
.addClass('ui-spinner ui-widget ui-widget-content ui-corner-all')
@@ -51,38 +63,38 @@
.append('<button class="ui-spinner-up ui-state-default ui-corner-tr"
type="button"><span class="ui-icon
ui-icon-triangle-1-n">▲</span></button>')
.find('.ui-spinner-up')
.bind('mouseover', function(event) {
- $(this).addClass('ui-state-hover');
+ $(this).addClass(hover);
})
.bind('mousedown', function(event) {
- $(this).addClass('ui-state-active');
+ $(this).addClass(active);
if (!self.counter) {
self.counter = 1;
}
self._mousedown(100, '_up', event);
})
.bind('mouseup', function(event) {
- $(this).removeClass('ui-state-active');
+ $(this).removeClass(active);
if (self.counter == 1) {
self._up(event);
}
self._mouseup(event);
})
.bind('mouseout', function(event) {
- $(this).removeClass('ui-state-active ui-state-hover');
+ $(this).removeClass(active + ' ' + hover);
if (self.timer) {
self._mouseup(event);
}
})
// mousedown/mouseup capture first click, now handle second click
.bind('dblclick', function(event) {
- $(this).removeClass('ui-state-active');
+ $(this).removeClass(active);
self._up(event);
self._mouseup(event);
})
- .bind('keydown.spinner', function(event) {
+ .bind('keydown'+namespace, function(event) {
var KEYS = $.ui.keyCode;
if (event.keyCode == KEYS.SPACE || event.keyCode == KEYS.ENTER) {
- $(this).addClass('ui-state-active');
+ $(this).addClass(active);
if (!self.counter) {
self.counter = 1;
}
@@ -93,8 +105,8 @@
self.element.focus();
}
})
- .bind('keyup.spinner', function(event) {
- $(this).removeClass('ui-state-active');
+ .bind('keyup'+namespace, function(event) {
+ $(this).removeClass(active);
self.counter = 0;
self._trigger('change', event);
})
@@ -102,38 +114,38 @@
.append('<button class="ui-spinner-down ui-state-default ui-corner-br"
type="button"><span class="ui-icon
ui-icon-triangle-1-s">▼</span></button>')
.find('.ui-spinner-down')
.bind('mouseover', function(event) {
- $(this).addClass('ui-state-hover');
+ $(this).addClass(hover);
})
.bind('mousedown', function(event) {
- $(this).addClass('ui-state-active');
+ $(this).addClass(active);
if (!self.counter) {
self.counter = 1;
}
self._mousedown(100, '_down', event);
})
.bind('mouseup', function(event) {
- $(this).removeClass('ui-state-active');
+ $(this).removeClass(active);
if (self.counter == 1) {
self._down();
}
self._mouseup(event);
})
.bind('mouseout', function(event) {
- $(this).removeClass('ui-state-active ui-state-hover');
+ $(this).removeClass(active + ' ' + hover);
if (self.timer) {
self._mouseup(event);
}
})
// mousedown/mouseup capture first click, now handle second click
.bind('dblclick', function(event) {
- $(this).removeClass('ui-state-active');
+ $(this).removeClass(active);
self._down(event);
self._mouseup(event);
})
- .bind('keydown.spinner', function(event) {
+ .bind('keydown'+namespace, function(event) {
var KEYS = $.ui.keyCode;
if (event.keyCode == KEYS.SPACE || event.keyCode == KEYS.ENTER) {
- $(this).addClass('ui-state-active');
+ $(this).addClass(active);
if (!self.counter) {
self.counter = 1;
}
@@ -142,16 +154,34 @@
self.element.siblings('.ui-spinner-up').focus();
}
})
- .bind('keyup.spinner', function(event) {
- $(this).removeClass('ui-state-active');
+ .bind('keyup'+namespace, function(event) {
+ $(this).removeClass(active);
self.counter = 0;
self._trigger('change', event);
})
- .end();
+ .end()
+ .hover(function() {
+ self.hovered = true;
+ if (self.options.autoHide && !self.focused)
+ self._delay(self.showButtons, 100, 'hide');
+ }, function() {
+ self.hovered = false;
+ if (self.options.autoHide && !self.focused)
+ self._delay(self.hideButtons, 100, 'hide');
+ });
+
+ self.buttons = widget.find('button')
+ .hover(function() {
+ $(this).addClass(hover);
+ }, function() {
+ $(this).removeClass(hover);
+ });
+ if (self.options.autoHide)
+ self.hideButtons(true);
// Give the spinner casing a unique id only if one exists in original
input
// - this should aid targetted customisations if a page contains
multiple instances
- this.element.attr('id', function(){
+ self.element.attr('id', function(){
if (this.id) {
$(this).parent().attr('id', this.id+'-ui-spinner');
}
@@ -159,12 +189,12 @@
// DataList: Set contraints for object length and step size.
// Manipulate height of spinner.
- this._items = this.element.children().length;
- if (this._items > 1) {
- var margins = this.element.outerHeight(true) -
this.element.outerHeight();
- var height = this.element.outerHeight()/this._items + margins*2;
- //var height = this.options.height;
- this.element
+ self._items = self.element.children().length;
+ if (self._items > 1) {
+ var margins = self.element.outerHeight(true) -
self.element.outerHeight();
+ var height = self.element.outerHeight()/self._items + margins*2;
+ //var height = self.options.height;
+ self.element
.addClass('ui-spinner-list')
.height(height)
.children()
@@ -175,29 +205,41 @@
.parent()
.height(height)
.end();
- this.options.stepping = 1;
- this.options.min = 0;
- this.options.max = this._items-1;
+ self.options.stepping = 1;
+ self.options.min = 0;
+ self.options.max = self._items-1;
}
- this.element
- .bind('keydown.spinner', function(event) {
+ self.element
+ .bind('keydown'+namespace, function(event) {
if (!self.counter) {
self.counter = 1;
}
return self._keydown.call(self, event);
})
- .bind('keyup.spinner', function(event) {
+ .bind('keyup'+namespace, function(event) {
self.counter = 0;
self._trigger('change', event);
})
- .bind('blur.spinner', function(event) {
+ .bind('focus'+namespace, function() {
+ self.focused = true;
+ if (!self.hovered && self.options.autoHide)
+ self._delay(self.showButtons, 100, 'hide');
+ })
+ .bind('blur'+namespace, function(event) {
+ self.focused = false;
+ if (!self.hovered && self.options.autoHide)
+ self._delay(self.hideButtons, 100, 'hide');
self._cleanUp();
});
- if ($.fn.mousewheel && this.options.mouseWheel) {
- this.element.mousewheel(self._mousewheel);
+ if ($.fn.mousewheel && self.options.mouseWheel) {
+ self.element.mousewheel(self._mousewheel);
}
+
+ // disable spinner if element was already disabled
+ if (self.element.disabled)
+ self.disable();
},
_constrain: function() {
@@ -349,9 +391,38 @@
this.element.append('<'+ wrapper +' class="ui-spinner-dyn">'+ html
+ '</'+ wrapper +'>');
}
},
+ // delays a function call, allowing only one at a time of the same type
+ _delay: function(callback, delay, type) {
+ type = type || 'a';
+
+ var self = this,
+ curDelay = self._curDelay[type] || {},
+ args = Array.prototype.slice.call(arguments, 3);
+
+ // reassign in case it's a new delay
+ self._curDelay[type] = curDelay;
+
+ if (curDelay.i) {
+ // don't do anything if resetting the same delay
+ if (curDelay.f === callback) return;
+ clearTimeout(curDelay.i);
+ }
+
+ curDelay.f = callback;
+ curDelay.i = setTimeout(function() {
+ curDelay.i = 0;
+ curDelay.f.apply(self, args);
+ }, delay);
+ },
_setData: function(key, value) {
if ((key == 'mouseWheel') && (value != this.options.mouseWheel) &&
$.fn.mousewheel)
this.element[value ? 'mousewheel' : 'unmousewheel'](this._mousewheel);
+ else if (key == 'autoHide') {
+ if (!value)
+ this.showButtons(true);
+ else if (!this.hovered && !this.focused)
+ this.hideButtons(true);
+ }
$.widget.prototype._setData.call(this, key, value);
},
@@ -381,7 +452,7 @@
.removeAttr('disabled')
.removeAttr('autocomplete')
.removeData('spinner')
- .unbind('.spinner')
+ .unbind(namespace)
.siblings()
.remove()
.end()
@@ -403,6 +474,7 @@
.parent()
.removeClass('ui-state-disabled');
this.disabled = false;
+ return this;
},
disable: function() {
this.element
@@ -412,6 +484,7 @@
.parent()
.addClass('ui-state-disabled');
this.disabled = true;
+ return this;
},
value: function(newVal) {
if (!arguments.length)
@@ -419,6 +492,24 @@
this._setValue(newVal);
return this;
+ },
+ showButtons: function(immediate) {
+ var buttons = this.buttons.stop();
+ if (immediate)
+ buttons.css('opacity', 1);
+ else
+ buttons.fadeTo('fast', 1);
+ return this;
+ },
+
+ hideButtons: function(immediate) {
+ // also removeClass(hover) in case it was left despite losing mouse hover
+ var buttons = this.buttons.stop().removeClass(hover);
+ if (immediate)
+ buttons.css('opacity', 0);
+ else
+ buttons.fadeTo('fast', 0);
+ return this;
}
});
@@ -437,7 +528,8 @@
items: null,
max: null,
min: null,
- width: 'auto'
+ width: 'auto',
+ autoHide: false
},
format: {
currency: function(num, sym, group, pt) {