/*jshint undef: true, unused:true */ /*global jquery: true */ /*!========================================================================= * bootstrap touchspin * v2.5.0 * * a mobile and touch friendly input spinner component for bootstrap 3. * * https://github.com/istvan-meszaros/bootstrap-touchspin * http://www.virtuosoft.eu/code/bootstrap-touchspin/ * * copyright 2013 istván ujj-mészáros * * thanks for the contributors: * stefan bauer - https://github.com/sba * amid2887 - https://github.com/amid2887 * * licensed under the apache license, version 2.0 (the "license"); * you may not use this file except in compliance with the license. * you may obtain a copy of the license at * * http://www.apache.org/licenses/license-2.0 * * unless required by applicable law or agreed to in writing, software * distributed under the license is distributed on an "as is" basis, * without warranties or conditions of any kind, either express or implied. * see the license for the specific language governing permissions and * limitations under the license. * * ====================================================================== */ (function($) { "use strict"; $.fn.touchspin = function(options) { var defaults = { min: 0, max: 100, initval: "", step: 1, decimals: 0, stepinterval: 100, forcestepdivisibility: 'round', // none | floor | round | ceil stepintervaldelay: 500, prefix: "", postfix: "", prefix_extraclass: "", postfix_extraclass: "", booster: true, boostat: 10, maxboostedstep: false, mousewheel: true, buttondown_class: "btn btn-default", buttonup_class: "btn btn-default" }; return this.each(function() { var settings, originalinput = $(this), originalinput_data = originalinput.data(), container, elements, value, downspintimer, upspintimer, downdelaytimeout, updelaytimeout, spincount = 0, spinning = false; init(); function init() { if (originalinput.data("alreadyinitialized")) { return; } originalinput.data("alreadyinitialized", true); if (!originalinput.is("input")) { console.log("must be an input."); return; } _initsettings(); _setinitval(); _checkvalue(); _buildhtml(); _initelements(); _bindevents(); _bindeventsinterface(); } function _setinitval() { if (settings.initval !== "" && originalinput.val() === "") { originalinput.val(settings.initval); } } function changesettings(newsettings) { _updatesettings(newsettings); _checkvalue(); var value = number(elements.input.val()); elements.input.val(value.tofixed(settings.decimals)); } function _initsettings() { settings = $.extend({}, defaults, originalinput_data, options); } function _updatesettings(newsettings) { settings = $.extend({}, settings, newsettings); } function _buildhtml() { var initval = originalinput.val(), parentelement = originalinput.parent(); if (initval !== "") { initval = number(initval).tofixed(settings.decimals); } originalinput.data("initvalue", initval).val(initval); originalinput.addclass("form-control"); $("").appendto("head"); if (parentelement.hasclass("input-group")) { _advanceinputgroup(parentelement); } else { _buildinputgroup(); } } function _advanceinputgroup(parentelement) { parentelement.addclass("bootstrap-touchspin"); var prev = originalinput.prev(), next = originalinput.next(); var downhtml, uphtml, prefixhtml = '' + settings.prefix + '', postfixhtml = '' + settings.postfix + ''; if (prev.hasclass("input-group-btn")) { downhtml = '', prev.append(downhtml); } else { downhtml = ''; $(downhtml).insertbefore(originalinput); } if (next.hasclass("input-group-btn")) { uphtml = '', next.prepend(uphtml); } else { uphtml = ''; $(uphtml).insertafter(originalinput); } $(prefixhtml).insertbefore(originalinput); $(postfixhtml).insertafter(originalinput); container = parentelement; } function _buildinputgroup() { var html = '
' + settings.prefix + '' + settings.postfix + '
'; container = $(html).insertbefore(originalinput); $(".bootstrap-touchspin-prefix", container).after(originalinput); if (originalinput.hasclass("input-sm")) { container.addclass("input-group-sm"); } else if (originalinput.hasclass("input-lg")) { container.addclass("input-group-lg"); } } function _initelements() { elements = { down: $(".bootstrap-touchspin-down", container), up: $(".bootstrap-touchspin-up", container), input: $("input", container), prefix: $(".bootstrap-touchspin-prefix", container).addclass(settings.prefix_extraclass), postfix: $(".bootstrap-touchspin-postfix", container).addclass(settings.postfix_extraclass) }; } function _bindevents() { originalinput.on("keydown", function(ev) { var code = ev.keycode || ev.which; if (code === 38) { if (spinning !== "up") { uponce(); startupspin(); } ev.preventdefault(); } else if (code === 40) { if (spinning !== "down") { downonce(); startdownspin(); } ev.preventdefault(); } }); originalinput.on("keyup", function(ev) { var code = ev.keycode || ev.which; if (code === 38) { stopspin(); } else if (code === 40) { stopspin(); } }); originalinput.on("blur", function() { _checkvalue(); }); elements.down.on("keydown", function(ev) { var code = ev.keycode || ev.which; if (code === 32 || code === 13) { if (spinning !== "down") { downonce(); startdownspin(); } ev.preventdefault(); } }); elements.down.on("keyup", function(ev) { var code = ev.keycode || ev.which; if (code === 32 || code === 13) { stopspin(); } }); elements.up.on("keydown", function(ev) { var code = ev.keycode || ev.which; if (code === 32 || code === 13) { if (spinning !== "up") { uponce(); startupspin(); } ev.preventdefault(); } }); elements.up.on("keyup", function(ev) { var code = ev.keycode || ev.which; if (code === 32 || code === 13) { stopspin(); } }); elements.down.on("mousedown touchstart", function(ev) { downonce(); startdownspin(); ev.preventdefault(); ev.stoppropagation(); }); elements.up.on("mousedown touchstart", function(ev) { uponce(); startupspin(); ev.preventdefault(); ev.stoppropagation(); }); elements.up.on("mouseout touchleave touchend touchcancel", function(ev) { if (!spinning) { return; } ev.stoppropagation(); stopspin(); }); elements.down.on("mouseout touchleave touchend touchcancel", function(ev) { if (!spinning) { return; } ev.stoppropagation(); stopspin(); }); elements.down.on("mousemove touchmove", function(ev) { if (!spinning) { return; } ev.stoppropagation(); ev.preventdefault(); }); elements.up.on("mousemove touchmove", function(ev) { if (!spinning) { return; } ev.stoppropagation(); ev.preventdefault(); }); $(document).on("mouseup touchend touchcancel", function(ev) { if (!spinning) { return; } ev.preventdefault(); stopspin(); }); $(document).on("mousemove touchmove scroll scrollstart", function(ev) { if (!spinning) { return; } ev.preventdefault(); stopspin(); }); if (settings.mousewheel) { originalinput.on("mousewheel dommousescroll", function(ev) { var delta = ev.originalevent.wheeldelta || -ev.originalevent.detail; ev.stoppropagation(); ev.preventdefault(); if (delta < 0) { downonce(); } else { uponce(); } }); } } function _bindeventsinterface() { originalinput.on('touchspin.uponce', function() { stopspin(); uponce(); }); originalinput.on('touchspin.downonce', function() { stopspin(); downonce(); }); originalinput.on('touchspin.startupspin', function() { startupspin(); }); originalinput.on('touchspin.startdownspin', function() { startdownspin(); }); originalinput.on('touchspin.stopspin', function() { stopspin(); }); originalinput.on('touchspin.updatesettings', function(e, newsettings) { changesettings(newsettings); }); } function _forcestepdivisibility(value) { switch(settings.forcestepdivisibility) { case 'round': return (math.round(value / settings.step) * settings.step).tofixed(settings.decimals); break; case 'floor': return (math.floor(value / settings.step) * settings.step).tofixed(settings.decimals); break; case 'ceil': return (math.ceil(value / settings.step) * settings.step).tofixed(settings.decimals); break; default: return value; } } function _checkvalue() { var val, parsedval, returnval; val = originalinput.val(); if (val === "") { return; } if (settings.decimals > 0 && val === ".") { return; } parsedval = parsefloat(val); if (isnan(parsedval)) { parsedval = 0; } returnval = parsedval; if (parsedval.tostring() !== val) { returnval = parsedval; } if (parsedval < settings.min) { returnval = settings.min; } if (parsedval > settings.max) { returnval = settings.max; } returnval = _forcestepdivisibility(returnval); if (number(val).tostring() !== returnval.tostring()) { originalinput.val(returnval); originalinput.trigger("change"); } } function _getboostedstep() { if (!settings.booster) { return settings.step; } else { var boosted = math.pow(2,math.floor(spincount / settings.boostat)) * settings.step; if (settings.maxboostedstep) { if (boosted > settings.maxboostedstep) { boosted = settings.maxboostedstep; value = math.round((value / boosted) * boosted); } } return math.max(settings.step, boosted); } } function uponce() { _checkvalue(); value = parsefloat(elements.input.val()); if (isnan(value)) { value = 0; } var initvalue = value, boostedstep = _getboostedstep(); value = value + boostedstep; if (value > settings.max) { stopspin(); value = settings.max; originalinput.trigger("touchspin.max"); } elements.input.val(number(value).tofixed(settings.decimals)); if (initvalue !== value) { originalinput.trigger("change"); } } function downonce() { _checkvalue(); value = parsefloat(elements.input.val()); if (isnan(value)) { value = 0; } var initvalue = value, boostedstep = _getboostedstep(); value = value - boostedstep; if (value < settings.min) { stopspin(); value = settings.min; originalinput.trigger("touchspin.min"); } elements.input.val(value.tofixed(settings.decimals)); if (initvalue !== value) { originalinput.trigger("change"); } } function startdownspin() { stopspin(); spincount = 0; spinning = "down"; downdelaytimeout = settimeout(function() { downspintimer = setinterval(function() { spincount++; downonce(); }, settings.stepinterval); }, settings.stepintervaldelay); } function startupspin() { stopspin(); spincount = 0; spinning = "up"; updelaytimeout = settimeout(function() { upspintimer = setinterval(function() { spincount++; uponce(); }, settings.stepinterval); }, settings.stepintervaldelay); } function stopspin() { cleartimeout(downdelaytimeout); cleartimeout(updelaytimeout); clearinterval(downspintimer); clearinterval(upspintimer); spincount = 0; spinning = false; } }); }; })(jquery);