/** * Wraps an HTML5 number field. Example usage: * * new Ext.field.Spinner({ * minValue: 0, * maxValue: 100, * incrementValue: 2, * cycle: true * }); * */ Ext.define('Ext.field.Spinner', { extend: 'Ext.field.Number', alias : 'widget.spinnerfield', alternateClassName: 'Ext.form.Spinner', requires: ['Ext.util.TapRepeater'], /** * @event spin * Fires when the value is changed via either spinner buttons * @param {Ext.field.Spinner} this * @param {Number} value * @param {String} direction 'up' or 'down' */ /** * @event spindown * Fires when the value is changed via the spinner down button * @param {Ext.field.Spinner} this * @param {Number} value */ /** * @event spinup * Fires when the value is changed via the spinner up button * @param {Ext.field.Spinner} this * @param {Number} value */ config: { // @inherit cls: Ext.baseCSSPrefix + 'spinner', /** * @cfg {Number} [minValue=-infinity] The minimum allowed value. * @accessor */ minValue: Number.NEGATIVE_INFINITY, /** * @cfg {Number} [maxValue=infinity] The maximum allowed value. * @accessor */ maxValue: Number.MAX_VALUE, /** * @cfg {Number} incrementValue Value that is added or subtracted from the current value when a spinner is used. * @accessor */ increment: 1, /** * @cfg {Boolean} accelerateOnTapHold True if autorepeating should start slowly and accelerate. * @accessor */ accelerateOnTapHold: true, /** * @cfg {Boolean} cycle When set to true, it will loop the values of a minimum or maximum is reached. * If the maximum value is reached, the value will be set to the minimum. * @accessor */ cycle: false, /** * @cfg {Boolean} clearIcon * @hide * @accessor */ clearIcon: false, defaultValue: 0, /** * @cfg {Number} tabIndex * @hide */ tabIndex: -1 }, constructor: function() { this.callParent(arguments); if (!this.getValue()) { this.setValue(this.getDefaultValue()); } }, /** * Updates the {@link #input} configuration */ updateComponent: function(newComponent) { this.callParent(arguments); var cls = this.getCls(); if (newComponent) { this.spinDownButton = newComponent.element.createChild({ cls : cls + '-button ' + cls + '-button-down', html: '-' }); newComponent.element.insertFirst(this.spinDownButton); this.spinUpButton = newComponent.element.createChild({ cls : cls + '-button ' + cls + '-button-up', html: '+' }); this.downRepeater = this.createRepeater(this.spinDownButton, this.onSpinDown); this.upRepeater = this.createRepeater(this.spinUpButton, this.onSpinUp); } }, // @inherit applyValue: function(value) { value = parseFloat(value); if (isNaN(value)) { value = this.getDefaultValue(); } return this.callParent([value]); }, // @private createRepeater: function(el, fn) { var me = this, repeater = Ext.create('Ext.util.TapRepeater', { el: el, accelerate: me.getAccelerateOnTapHold() }); repeater.on({ tap: fn, touchstart: 'onTouchStart', touchend: 'onTouchEnd', scope: me }); return repeater; }, // @private onSpinDown: function() { if (!this.getDisabled()) { this.spin(true); } }, // @private onSpinUp: function() { if (!this.getDisabled()) { this.spin(false); } }, // @private onTouchStart: function(repeater) { if (!this.getDisabled()) { repeater.getEl().addCls(Ext.baseCSSPrefix + 'button-pressed'); } }, // @private onTouchEnd: function(repeater) { repeater.getEl().removeCls(Ext.baseCSSPrefix + 'button-pressed'); }, // @private spin: function(down) { var me = this, value = parseInt(me.getValue(), 10), increment = me.getIncrement(), direction = down ? 'down' : 'up'; if (down) { value -= increment; } else { value += increment; } me.setValue(value); value = me._value; me.fireAction('spin', [me, value, direction], 'doSpin'); me.fireAction('spin' + direction, [me, value], 'doSpin' + Ext.String.capitalize(direction)); }, doSpin: Ext.emptyFn, doSpinUp: Ext.emptyFn, doSpinDown: Ext.emptyFn, reset: function() { this.setValue(this.getDefaultValue()); }, // @private destroy: function() { var me = this; Ext.destroy(me.downRepeater, me.upRepeater); me.callParent(arguments); } }, function() { //incrementValue });