/inventoryBrowser/node_modules/jquery-ui/ui/widgets/spinner.js |
@@ -0,0 +1,575 @@ |
/*! |
* jQuery UI Spinner 1.12.1 |
* http://jqueryui.com |
* |
* Copyright jQuery Foundation and other contributors |
* Released under the MIT license. |
* http://jquery.org/license |
*/ |
|
//>>label: Spinner |
//>>group: Widgets |
//>>description: Displays buttons to easily input numbers via the keyboard or mouse. |
//>>docs: http://api.jqueryui.com/spinner/ |
//>>demos: http://jqueryui.com/spinner/ |
//>>css.structure: ../../themes/base/core.css |
//>>css.structure: ../../themes/base/spinner.css |
//>>css.theme: ../../themes/base/theme.css |
|
( function( factory ) { |
if ( typeof define === "function" && define.amd ) { |
|
// AMD. Register as an anonymous module. |
define( [ |
"jquery", |
"./button", |
"../version", |
"../keycode", |
"../safe-active-element", |
"../widget" |
], factory ); |
} else { |
|
// Browser globals |
factory( jQuery ); |
} |
}( function( $ ) { |
|
function spinnerModifer( fn ) { |
return function() { |
var previous = this.element.val(); |
fn.apply( this, arguments ); |
this._refresh(); |
if ( previous !== this.element.val() ) { |
this._trigger( "change" ); |
} |
}; |
} |
|
$.widget( "ui.spinner", { |
version: "1.12.1", |
defaultElement: "<input>", |
widgetEventPrefix: "spin", |
options: { |
classes: { |
"ui-spinner": "ui-corner-all", |
"ui-spinner-down": "ui-corner-br", |
"ui-spinner-up": "ui-corner-tr" |
}, |
culture: null, |
icons: { |
down: "ui-icon-triangle-1-s", |
up: "ui-icon-triangle-1-n" |
}, |
incremental: true, |
max: null, |
min: null, |
numberFormat: null, |
page: 10, |
step: 1, |
|
change: null, |
spin: null, |
start: null, |
stop: null |
}, |
|
_create: function() { |
|
// handle string values that need to be parsed |
this._setOption( "max", this.options.max ); |
this._setOption( "min", this.options.min ); |
this._setOption( "step", this.options.step ); |
|
// Only format if there is a value, prevents the field from being marked |
// as invalid in Firefox, see #9573. |
if ( this.value() !== "" ) { |
|
// Format the value, but don't constrain. |
this._value( this.element.val(), true ); |
} |
|
this._draw(); |
this._on( this._events ); |
this._refresh(); |
|
// Turning off autocomplete prevents the browser from remembering the |
// value when navigating through history, so we re-enable autocomplete |
// if the page is unloaded before the widget is destroyed. #7790 |
this._on( this.window, { |
beforeunload: function() { |
this.element.removeAttr( "autocomplete" ); |
} |
} ); |
}, |
|
_getCreateOptions: function() { |
var options = this._super(); |
var element = this.element; |
|
$.each( [ "min", "max", "step" ], function( i, option ) { |
var value = element.attr( option ); |
if ( value != null && value.length ) { |
options[ option ] = value; |
} |
} ); |
|
return options; |
}, |
|
_events: { |
keydown: function( event ) { |
if ( this._start( event ) && this._keydown( event ) ) { |
event.preventDefault(); |
} |
}, |
keyup: "_stop", |
focus: function() { |
this.previous = this.element.val(); |
}, |
blur: function( event ) { |
if ( this.cancelBlur ) { |
delete this.cancelBlur; |
return; |
} |
|
this._stop(); |
this._refresh(); |
if ( this.previous !== this.element.val() ) { |
this._trigger( "change", event ); |
} |
}, |
mousewheel: function( event, delta ) { |
if ( !delta ) { |
return; |
} |
if ( !this.spinning && !this._start( event ) ) { |
return false; |
} |
|
this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event ); |
clearTimeout( this.mousewheelTimer ); |
this.mousewheelTimer = this._delay( function() { |
if ( this.spinning ) { |
this._stop( event ); |
} |
}, 100 ); |
event.preventDefault(); |
}, |
"mousedown .ui-spinner-button": function( event ) { |
var previous; |
|
// We never want the buttons to have focus; whenever the user is |
// interacting with the spinner, the focus should be on the input. |
// If the input is focused then this.previous is properly set from |
// when the input first received focus. If the input is not focused |
// then we need to set this.previous based on the value before spinning. |
previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ? |
this.previous : this.element.val(); |
function checkFocus() { |
var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ); |
if ( !isActive ) { |
this.element.trigger( "focus" ); |
this.previous = previous; |
|
// support: IE |
// IE sets focus asynchronously, so we need to check if focus |
// moved off of the input because the user clicked on the button. |
this._delay( function() { |
this.previous = previous; |
} ); |
} |
} |
|
// Ensure focus is on (or stays on) the text field |
event.preventDefault(); |
checkFocus.call( this ); |
|
// Support: IE |
// IE doesn't prevent moving focus even with event.preventDefault() |
// so we set a flag to know when we should ignore the blur event |
// and check (again) if focus moved off of the input. |
this.cancelBlur = true; |
this._delay( function() { |
delete this.cancelBlur; |
checkFocus.call( this ); |
} ); |
|
if ( this._start( event ) === false ) { |
return; |
} |
|
this._repeat( null, $( event.currentTarget ) |
.hasClass( "ui-spinner-up" ) ? 1 : -1, event ); |
}, |
"mouseup .ui-spinner-button": "_stop", |
"mouseenter .ui-spinner-button": function( event ) { |
|
// button will add ui-state-active if mouse was down while mouseleave and kept down |
if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { |
return; |
} |
|
if ( this._start( event ) === false ) { |
return false; |
} |
this._repeat( null, $( event.currentTarget ) |
.hasClass( "ui-spinner-up" ) ? 1 : -1, event ); |
}, |
|
// TODO: do we really want to consider this a stop? |
// shouldn't we just stop the repeater and wait until mouseup before |
// we trigger the stop event? |
"mouseleave .ui-spinner-button": "_stop" |
}, |
|
// Support mobile enhanced option and make backcompat more sane |
_enhance: function() { |
this.uiSpinner = this.element |
.attr( "autocomplete", "off" ) |
.wrap( "<span>" ) |
.parent() |
|
// Add buttons |
.append( |
"<a></a><a></a>" |
); |
}, |
|
_draw: function() { |
this._enhance(); |
|
this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" ); |
this._addClass( "ui-spinner-input" ); |
|
this.element.attr( "role", "spinbutton" ); |
|
// Button bindings |
this.buttons = this.uiSpinner.children( "a" ) |
.attr( "tabIndex", -1 ) |
.attr( "aria-hidden", true ) |
.button( { |
classes: { |
"ui-button": "" |
} |
} ); |
|
// TODO: Right now button does not support classes this is already updated in button PR |
this._removeClass( this.buttons, "ui-corner-all" ); |
|
this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" ); |
this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" ); |
this.buttons.first().button( { |
"icon": this.options.icons.up, |
"showLabel": false |
} ); |
this.buttons.last().button( { |
"icon": this.options.icons.down, |
"showLabel": false |
} ); |
|
// IE 6 doesn't understand height: 50% for the buttons |
// unless the wrapper has an explicit height |
if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) && |
this.uiSpinner.height() > 0 ) { |
this.uiSpinner.height( this.uiSpinner.height() ); |
} |
}, |
|
_keydown: function( event ) { |
var options = this.options, |
keyCode = $.ui.keyCode; |
|
switch ( event.keyCode ) { |
case keyCode.UP: |
this._repeat( null, 1, event ); |
return true; |
case keyCode.DOWN: |
this._repeat( null, -1, event ); |
return true; |
case keyCode.PAGE_UP: |
this._repeat( null, options.page, event ); |
return true; |
case keyCode.PAGE_DOWN: |
this._repeat( null, -options.page, event ); |
return true; |
} |
|
return false; |
}, |
|
_start: function( event ) { |
if ( !this.spinning && this._trigger( "start", event ) === false ) { |
return false; |
} |
|
if ( !this.counter ) { |
this.counter = 1; |
} |
this.spinning = true; |
return true; |
}, |
|
_repeat: function( i, steps, event ) { |
i = i || 500; |
|
clearTimeout( this.timer ); |
this.timer = this._delay( function() { |
this._repeat( 40, steps, event ); |
}, i ); |
|
this._spin( steps * this.options.step, event ); |
}, |
|
_spin: function( step, event ) { |
var value = this.value() || 0; |
|
if ( !this.counter ) { |
this.counter = 1; |
} |
|
value = this._adjustValue( value + step * this._increment( this.counter ) ); |
|
if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) { |
this._value( value ); |
this.counter++; |
} |
}, |
|
_increment: function( i ) { |
var incremental = this.options.incremental; |
|
if ( incremental ) { |
return $.isFunction( incremental ) ? |
incremental( i ) : |
Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); |
} |
|
return 1; |
}, |
|
_precision: function() { |
var precision = this._precisionOf( this.options.step ); |
if ( this.options.min !== null ) { |
precision = Math.max( precision, this._precisionOf( this.options.min ) ); |
} |
return precision; |
}, |
|
_precisionOf: function( num ) { |
var str = num.toString(), |
decimal = str.indexOf( "." ); |
return decimal === -1 ? 0 : str.length - decimal - 1; |
}, |
|
_adjustValue: function( value ) { |
var base, aboveMin, |
options = this.options; |
|
// Make sure we're at a valid step |
// - find out where we are relative to the base (min or 0) |
base = options.min !== null ? options.min : 0; |
aboveMin = value - base; |
|
// - round to the nearest step |
aboveMin = Math.round( aboveMin / options.step ) * options.step; |
|
// - rounding is based on 0, so adjust back to our base |
value = base + aboveMin; |
|
// Fix precision from bad JS floating point math |
value = parseFloat( value.toFixed( this._precision() ) ); |
|
// Clamp the value |
if ( options.max !== null && value > options.max ) { |
return options.max; |
} |
if ( options.min !== null && value < options.min ) { |
return options.min; |
} |
|
return value; |
}, |
|
_stop: function( event ) { |
if ( !this.spinning ) { |
return; |
} |
|
clearTimeout( this.timer ); |
clearTimeout( this.mousewheelTimer ); |
this.counter = 0; |
this.spinning = false; |
this._trigger( "stop", event ); |
}, |
|
_setOption: function( key, value ) { |
var prevValue, first, last; |
|
if ( key === "culture" || key === "numberFormat" ) { |
prevValue = this._parse( this.element.val() ); |
this.options[ key ] = value; |
this.element.val( this._format( prevValue ) ); |
return; |
} |
|
if ( key === "max" || key === "min" || key === "step" ) { |
if ( typeof value === "string" ) { |
value = this._parse( value ); |
} |
} |
if ( key === "icons" ) { |
first = this.buttons.first().find( ".ui-icon" ); |
this._removeClass( first, null, this.options.icons.up ); |
this._addClass( first, null, value.up ); |
last = this.buttons.last().find( ".ui-icon" ); |
this._removeClass( last, null, this.options.icons.down ); |
this._addClass( last, null, value.down ); |
} |
|
this._super( key, value ); |
}, |
|
_setOptionDisabled: function( value ) { |
this._super( value ); |
|
this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value ); |
this.element.prop( "disabled", !!value ); |
this.buttons.button( value ? "disable" : "enable" ); |
}, |
|
_setOptions: spinnerModifer( function( options ) { |
this._super( options ); |
} ), |
|
_parse: function( val ) { |
if ( typeof val === "string" && val !== "" ) { |
val = window.Globalize && this.options.numberFormat ? |
Globalize.parseFloat( val, 10, this.options.culture ) : +val; |
} |
return val === "" || isNaN( val ) ? null : val; |
}, |
|
_format: function( value ) { |
if ( value === "" ) { |
return ""; |
} |
return window.Globalize && this.options.numberFormat ? |
Globalize.format( value, this.options.numberFormat, this.options.culture ) : |
value; |
}, |
|
_refresh: function() { |
this.element.attr( { |
"aria-valuemin": this.options.min, |
"aria-valuemax": this.options.max, |
|
// TODO: what should we do with values that can't be parsed? |
"aria-valuenow": this._parse( this.element.val() ) |
} ); |
}, |
|
isValid: function() { |
var value = this.value(); |
|
// Null is invalid |
if ( value === null ) { |
return false; |
} |
|
// If value gets adjusted, it's invalid |
return value === this._adjustValue( value ); |
}, |
|
// Update the value without triggering change |
_value: function( value, allowAny ) { |
var parsed; |
if ( value !== "" ) { |
parsed = this._parse( value ); |
if ( parsed !== null ) { |
if ( !allowAny ) { |
parsed = this._adjustValue( parsed ); |
} |
value = this._format( parsed ); |
} |
} |
this.element.val( value ); |
this._refresh(); |
}, |
|
_destroy: function() { |
this.element |
.prop( "disabled", false ) |
.removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" ); |
|
this.uiSpinner.replaceWith( this.element ); |
}, |
|
stepUp: spinnerModifer( function( steps ) { |
this._stepUp( steps ); |
} ), |
_stepUp: function( steps ) { |
if ( this._start() ) { |
this._spin( ( steps || 1 ) * this.options.step ); |
this._stop(); |
} |
}, |
|
stepDown: spinnerModifer( function( steps ) { |
this._stepDown( steps ); |
} ), |
_stepDown: function( steps ) { |
if ( this._start() ) { |
this._spin( ( steps || 1 ) * -this.options.step ); |
this._stop(); |
} |
}, |
|
pageUp: spinnerModifer( function( pages ) { |
this._stepUp( ( pages || 1 ) * this.options.page ); |
} ), |
|
pageDown: spinnerModifer( function( pages ) { |
this._stepDown( ( pages || 1 ) * this.options.page ); |
} ), |
|
value: function( newVal ) { |
if ( !arguments.length ) { |
return this._parse( this.element.val() ); |
} |
spinnerModifer( this._value ).call( this, newVal ); |
}, |
|
widget: function() { |
return this.uiSpinner; |
} |
} ); |
|
// DEPRECATED |
// TODO: switch return back to widget declaration at top of file when this is removed |
if ( $.uiBackCompat !== false ) { |
|
// Backcompat for spinner html extension points |
$.widget( "ui.spinner", $.ui.spinner, { |
_enhance: function() { |
this.uiSpinner = this.element |
.attr( "autocomplete", "off" ) |
.wrap( this._uiSpinnerHtml() ) |
.parent() |
|
// Add buttons |
.append( this._buttonHtml() ); |
}, |
_uiSpinnerHtml: function() { |
return "<span>"; |
}, |
|
_buttonHtml: function() { |
return "<a></a><a></a>"; |
} |
} ); |
} |
|
return $.ui.spinner; |
|
} ) ); |