├── .gitignore ├── Gruntfile.js ├── LICENSE ├── README.md ├── bower.json ├── dist ├── bootstrap-spinner.js ├── bootstrap-spinner.min.js ├── mousehold.js └── mousehold.min.js ├── package.json └── src ├── bootstrap-spinner.js └── mousehold.js /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /bower_components 3 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | "use strict"; 3 | 4 | // Force use of Unix newlines 5 | grunt.util.linefeed = '\n'; 6 | 7 | grunt.initConfig({ 8 | clean: { 9 | dist: ['dist'] 10 | }, 11 | 12 | copy: { 13 | dist: { 14 | expand: true, 15 | flatten: true, 16 | src: [ 17 | 'src/bootstrap-spinner.js', 18 | 'src/mousehold.js' 19 | ], 20 | dest: 'dist/' 21 | } 22 | }, 23 | 24 | uglify: { 25 | options: { 26 | report: 'min' 27 | }, 28 | spinner: { 29 | src: 'dist/bootstrap-spinner.js', 30 | dest: 'dist/bootstrap-spinner.min.js' 31 | }, 32 | mousehold: { 33 | src: 'dist/mousehold.js', 34 | dest: 'dist/mousehold.min.js' 35 | } 36 | } 37 | 38 | }); 39 | 40 | require('load-grunt-tasks')(grunt); 41 | 42 | grunt.registerTask('default', ['clean', 'copy', 'uglify']); 43 | }; 44 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013-2014 Indigo Development Team 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bootstrap Spinner 2 | 3 | Bootstrap-style spinner plugin 4 | 5 | 6 | ## Install 7 | 8 | Via Bower (soon) 9 | 10 | ``` bash 11 | bower install bootstrap-spinner 12 | ``` 13 | 14 | ## Usage 15 | 16 | See an example [here](http://indigojs.github.io/bootstrap-spinner/). 17 | 18 | 19 | ## Credits 20 | 21 | - [Márk Sági-Kazár](https://github.com/sagikazarmark) 22 | - [All Contributors](https://github.com/indigojs/bootstrap-spinner/contributors) 23 | 24 | 25 | ## Special Thanks 26 | 27 | Remy Sharp: Original mousehold plugin [link](http://remysharp.com/2006/12/15/jquery-mousehold-event/) 28 | 29 | 30 | ## License 31 | 32 | The MIT License (MIT). Please see [License File](https://github.com/indigojs/bootstrap-spinner/blob/develop/LICENSE) for more information. -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-spinner", 3 | "version": "1.0.0", 4 | "main": [ 5 | "./dist/spinner.js" 6 | ], 7 | "authors": [ 8 | "Márk Sági-Kazár " 9 | ], 10 | "description": "Bootstrap-style spinner plugin", 11 | "license": "MIT", 12 | "homepage": "http://indigojs.github.io/bootstrap-spinner", 13 | "ignore": [ 14 | "**/.*", 15 | "node_modules", 16 | "bower_components" 17 | ], 18 | "dependencies": { 19 | "jquery": ">= 1.9.0" 20 | }, 21 | "devDependencies": { 22 | "bootstrap": "3.1.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dist/bootstrap-spinner.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: spinner.js v3.1.1 3 | * http://github.com/indigojs 4 | * ======================================================================== 5 | * Copyright 2014 Márk Sági-Kazár 6 | * Licensed under MIT (https://github.com/indigojs/bootstrap-spinner/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | +function ($) { 10 | 'use strict'; 11 | 12 | // SPINNER CLASS DEFINITION 13 | // ========================= 14 | 15 | var Spinner = function (element, options) { 16 | var $this = this; 17 | this.$element = $(element) 18 | this.options = $.extend({}, Spinner.DEFAULTS, this.$element.data(), options) 19 | 20 | // Check for insane values 21 | var value = new Number(this.$element.val()) 22 | if (isNaN(value)) this.$element.val(this.options.min) 23 | 24 | // Strict check entered value 25 | if (this.options.strict == true) { 26 | this.$element.on('keypress', function (e) { 27 | var prevent = false 28 | 29 | if (e.which == 45 || e.keyCode == 40) { 30 | $this.decrease() 31 | return false 32 | } else if (e.which == 43 || e.keyCode == 38) { 33 | $this.increase() 34 | return false 35 | } 36 | 37 | // Allow: backspace, delete, tab, escape, enter, home, end, left, right 38 | // Allow: Ctrl+A 39 | // Allow: home, end, left, right 40 | // Allow . if precision is gt 0 41 | if ($.inArray(e.keyCode, [8, 46, 9, 27, 13, 36, 35, 37, 39]) !== -1 || 42 | (e.which == 65 && e.ctrlKey === true) || 43 | ($this.options.precision > 0 && $this.$element.val().indexOf('.') == -1 && e.which == 46)) { 44 | return 45 | } 46 | 47 | // Ensure that it is a number and stop the keypress 48 | if (e.which < 48 || e.which > 57) return false 49 | }); 50 | 51 | // Validate after focus lost 52 | this.$element.on('blur', function (e) { 53 | $this.change($this.$element.val()) 54 | }) 55 | } 56 | } 57 | 58 | Spinner.DEFAULTS = { 59 | step: 1, 60 | min: 0, 61 | max: Infinity, 62 | precision: 0, 63 | strict: true 64 | } 65 | 66 | Spinner.prototype.increase = function() { 67 | this.step(this.options.step) 68 | } 69 | 70 | Spinner.prototype.decrease = function() { 71 | this.step(-this.options.step) 72 | } 73 | 74 | Spinner.prototype.step = function (value) { 75 | if (typeof value !== 'number') value = new Number(value) 76 | if (isNaN(value)) return 77 | 78 | var current = new Number(this.$element.val()) 79 | if (isNaN(current)) current = this.options.min 80 | 81 | this.change(current + value) 82 | } 83 | 84 | Spinner.prototype.change = function(value) { 85 | if (typeof value !== 'number') value = new Number(value) 86 | if (isNaN(value)) value = this.options.min 87 | 88 | if (value < this.options.min) value = this.options.min 89 | if (value > this.options.max) value = this.options.max 90 | 91 | var e = $.Event('change.bs.spinner', { value: value }) 92 | this.$element.trigger(e) 93 | 94 | e = $.Event('changed.bs.spinner') 95 | 96 | this.$element.val(value.toFixed(this.options.precision)).change().trigger(e) 97 | } 98 | 99 | Spinner.prototype.setOptions = function(options) { 100 | if (typeof options == 'object') this.options = $.extend({}, this.options, options) 101 | } 102 | 103 | // SPINNER PLUGIN DEFINITION 104 | // ========================= 105 | 106 | var old = $.fn.spinner 107 | 108 | $.fn.spinner = function (option, arg) { 109 | return this.each(function () { 110 | var $this = $(this) 111 | var data = $this.data('bs.spinner') 112 | var isNew = (typeof data == 'object') 113 | var options = typeof option == 'object' && option 114 | 115 | if (!data) $this.data('bs.spinner', (data = new Spinner(this, options))) 116 | 117 | if (typeof option == 'object' && isNew == false) data.setOptions(option) 118 | else if (typeof option == 'number') data.step(option) 119 | else if (typeof option == 'string') data[option](arg) 120 | }) 121 | } 122 | 123 | $.fn.spinner.Constructor = Spinner 124 | 125 | // SPINNER NO CONFLICT 126 | // =================== 127 | 128 | var trigger = function (event) { 129 | var $this = $(this) 130 | var href = $this.attr('href') 131 | var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7 132 | var value = $this.data('value') 133 | 134 | if ($this.is('a')) event.preventDefault() 135 | 136 | $target.spinner(value) 137 | } 138 | 139 | $.fn.spinner.noConflict = function () { 140 | $.fn.spinner = old 141 | return this 142 | } 143 | 144 | // SPINNER DATA-API 145 | // ================ 146 | 147 | $(document) 148 | .on('click.bs.spinner.data-api', '[data-toggle="spinner"][data-on!="mousehold"]', trigger) 149 | .on('mousehold.bs.spinner.data-api', '[data-toggle="spinner"]', trigger) 150 | 151 | $(window).on('load', function () { 152 | $('[data-ride="spinner"]').each(function () { 153 | $(this).spinner() 154 | }) 155 | }) 156 | 157 | }(jQuery); 158 | -------------------------------------------------------------------------------- /dist/bootstrap-spinner.min.js: -------------------------------------------------------------------------------- 1 | +function(a){"use strict";var b=function(c,d){var e=this;this.$element=a(c),this.options=a.extend({},b.DEFAULTS,this.$element.data(),d);var f=new Number(this.$element.val());isNaN(f)&&this.$element.val(this.options.min),1==this.options.strict&&(this.$element.on("keypress",function(b){if(45==b.which||40==b.keyCode)return e.decrease(),!1;if(43==b.which||38==b.keyCode)return e.increase(),!1;if(!(-1!==a.inArray(b.keyCode,[8,46,9,27,13,36,35,37,39])||65==b.which&&b.ctrlKey===!0||e.options.precision>0&&-1==e.$element.val().indexOf(".")&&46==b.which))return b.which<48||b.which>57?!1:void 0}),this.$element.on("blur",function(){e.change(e.$element.val())}))};b.DEFAULTS={step:1,min:0,max:1/0,precision:0,strict:!0},b.prototype.increase=function(){this.step(this.options.step)},b.prototype.decrease=function(){this.step(-this.options.step)},b.prototype.step=function(a){if("number"!=typeof a&&(a=new Number(a)),!isNaN(a)){var b=new Number(this.$element.val());isNaN(b)&&(b=this.options.min),this.change(b+a)}},b.prototype.change=function(b){"number"!=typeof b&&(b=new Number(b)),isNaN(b)&&(b=this.options.min),bthis.options.max&&(b=this.options.max);var c=a.Event("change.bs.spinner",{value:b});this.$element.trigger(c),c=a.Event("changed.bs.spinner"),this.$element.val(b.toFixed(this.options.precision)).change().trigger(c)},b.prototype.setOptions=function(b){"object"==typeof b&&(this.options=a.extend({},this.options,b))};var c=a.fn.spinner;a.fn.spinner=function(c,d){return this.each(function(){var e=a(this),f=e.data("bs.spinner"),g="object"==typeof f,h="object"==typeof c&&c;f||e.data("bs.spinner",f=new b(this,h)),"object"==typeof c&&0==g?f.setOptions(c):"number"==typeof c?f.step(c):"string"==typeof c&&f[c](d)})},a.fn.spinner.Constructor=b;var d=function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=c.data("value");c.is("a")&&b.preventDefault(),e.spinner(f)};a.fn.spinner.noConflict=function(){return a.fn.spinner=c,this},a(document).on("click.bs.spinner.data-api",'[data-toggle="spinner"][data-on!="mousehold"]',d).on("mousehold.bs.spinner.data-api",'[data-toggle="spinner"]',d),a(window).on("load",function(){a('[data-ride="spinner"]').each(function(){a(this).spinner()})})}(jQuery); -------------------------------------------------------------------------------- /dist/mousehold.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * mousehold.js v1.0.0 3 | * http://github.com/indigojs 4 | * ======================================================================== 5 | * Copyright 2014 Márk Sági-Kazár 6 | * Original author 2006 Remy Sharp (leftlogic.com) 7 | * Licensed under MIT (https://github.com/indigojs/bootstrap-spinner/blob/master/LICENSE) 8 | * ======================================================================== */ 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // MOUSEHOLD PLUGIN DEFINITION 14 | // =========================== 15 | 16 | $.fn.mousehold = function(timeout) { 17 | timeout = typeof timeout !== 'undefined' ? timeout : 100; 18 | var interval = 0 19 | var fireStep = 0 20 | var clearMousehold = undefined; 21 | var e = $.Event('mousehold', { counter: 0 }) 22 | 23 | return this.each(function() { 24 | $(this).mousedown(function() { 25 | fireStep = 1 26 | var t = this 27 | 28 | interval = setInterval(function() { 29 | e.counter++ 30 | $(t).trigger(e) 31 | fireStep = 2 32 | }, timeout) 33 | }) 34 | 35 | clearMousehold = function() { 36 | clearInterval(interval) 37 | if (fireStep == 1) { 38 | e.counter = 1 39 | $(this).trigger(e) 40 | } 41 | 42 | fireStep = 0 43 | } 44 | 45 | $(this).mouseout(clearMousehold) 46 | $(this).mouseup(clearMousehold) 47 | }) 48 | } 49 | 50 | $(window).on('load', function () { 51 | $('[data-on="mousehold"]').each(function() { 52 | var $this = $(this) 53 | 54 | $this.mousehold($this.data('timeout')) 55 | }) 56 | }) 57 | 58 | }(jQuery); 59 | -------------------------------------------------------------------------------- /dist/mousehold.min.js: -------------------------------------------------------------------------------- 1 | +function(a){"use strict";a.fn.mousehold=function(b){b="undefined"!=typeof b?b:100;var c=0,d=0,e=void 0,f=a.Event("mousehold",{counter:0});return this.each(function(){a(this).mousedown(function(){d=1;var e=this;c=setInterval(function(){f.counter++,a(e).trigger(f),d=2},b)}),e=function(){clearInterval(c),1==d&&(f.counter=1,a(this).trigger(f)),d=0},a(this).mouseout(e),a(this).mouseup(e)})},a(window).on("load",function(){a('[data-on="mousehold"]').each(function(){var b=a(this);b.mousehold(b.data("timeout"))})})}(jQuery); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bootstrap-spinner", 3 | "description": "Bootstrap-style spinner plugin", 4 | "version": "1.0.0", 5 | "homepage": "http://indigojs.github.io/bootstrap-spinner", 6 | "author": "Márk Sági-Kazár", 7 | "license": { 8 | "type": "MIT", 9 | "url": "https://github.com/indigojs/bootstrap-spinner/blob/master/LICENSE" 10 | }, 11 | "devDependencies": { 12 | "grunt": "~0.4.4", 13 | "grunt-contrib-clean": "~0.5.0", 14 | "grunt-contrib-copy": "~0.5.0", 15 | "grunt-contrib-uglify": "~0.4.0", 16 | "load-grunt-tasks": "~0.4.0" 17 | } 18 | } -------------------------------------------------------------------------------- /src/bootstrap-spinner.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * Bootstrap: spinner.js v3.1.1 3 | * http://github.com/indigojs 4 | * ======================================================================== 5 | * Copyright 2014 Márk Sági-Kazár 6 | * Licensed under MIT (https://github.com/indigojs/bootstrap-spinner/blob/master/LICENSE) 7 | * ======================================================================== */ 8 | 9 | +function ($) { 10 | 'use strict'; 11 | 12 | // SPINNER CLASS DEFINITION 13 | // ========================= 14 | 15 | var Spinner = function (element, options) { 16 | var $this = this; 17 | this.$element = $(element) 18 | this.options = $.extend({}, Spinner.DEFAULTS, this.$element.data(), options) 19 | 20 | // Check for insane values 21 | var value = new Number(this.$element.val()) 22 | if (isNaN(value)) this.$element.val(this.options.min) 23 | 24 | // Strict check entered value 25 | if (this.options.strict == true) { 26 | this.$element.on('keypress', function (e) { 27 | var prevent = false 28 | 29 | if (e.which == 45 || e.keyCode == 40) { 30 | $this.decrease() 31 | return false 32 | } else if (e.which == 43 || e.keyCode == 38) { 33 | $this.increase() 34 | return false 35 | } 36 | 37 | // Allow: backspace, delete, tab, escape, enter, home, end, left, right 38 | // Allow: Ctrl+A 39 | // Allow: home, end, left, right 40 | // Allow . if precision is gt 0 41 | if ($.inArray(e.keyCode, [8, 46, 9, 27, 13, 36, 35, 37, 39]) !== -1 || 42 | (e.which == 65 && e.ctrlKey === true) || 43 | ($this.options.precision > 0 && $this.$element.val().indexOf('.') == -1 && e.which == 46)) { 44 | return 45 | } 46 | 47 | // Ensure that it is a number and stop the keypress 48 | if (e.which < 48 || e.which > 57) return false 49 | }); 50 | 51 | // Validate after focus lost 52 | this.$element.on('blur', function (e) { 53 | $this.change($this.$element.val()) 54 | }) 55 | } 56 | } 57 | 58 | Spinner.DEFAULTS = { 59 | step: 1, 60 | min: 0, 61 | max: Infinity, 62 | precision: 0, 63 | strict: true 64 | } 65 | 66 | Spinner.prototype.increase = function() { 67 | this.step(this.options.step) 68 | } 69 | 70 | Spinner.prototype.decrease = function() { 71 | this.step(-this.options.step) 72 | } 73 | 74 | Spinner.prototype.step = function (value) { 75 | if (typeof value !== 'number') value = new Number(value) 76 | if (isNaN(value)) return 77 | 78 | var current = new Number(this.$element.val()) 79 | if (isNaN(current)) current = this.options.min 80 | 81 | this.change(current + value) 82 | } 83 | 84 | Spinner.prototype.change = function(value) { 85 | if (typeof value !== 'number') value = new Number(value) 86 | if (isNaN(value)) value = this.options.min 87 | 88 | if (value < this.options.min) value = this.options.min 89 | if (value > this.options.max) value = this.options.max 90 | 91 | var e = $.Event('change.bs.spinner', { value: value }) 92 | this.$element.trigger(e) 93 | 94 | e = $.Event('changed.bs.spinner') 95 | 96 | this.$element.val(value.toFixed(this.options.precision)).change().trigger(e) 97 | } 98 | 99 | Spinner.prototype.setOptions = function(options) { 100 | if (typeof options == 'object') this.options = $.extend({}, this.options, options) 101 | } 102 | 103 | // SPINNER PLUGIN DEFINITION 104 | // ========================= 105 | 106 | var old = $.fn.spinner 107 | 108 | $.fn.spinner = function (option, arg) { 109 | return this.each(function () { 110 | var $this = $(this) 111 | var data = $this.data('bs.spinner') 112 | var isNew = (typeof data == 'object') 113 | var options = typeof option == 'object' && option 114 | 115 | if (!data) $this.data('bs.spinner', (data = new Spinner(this, options))) 116 | 117 | if (typeof option == 'object' && isNew == false) data.setOptions(option) 118 | else if (typeof option == 'number') data.step(option) 119 | else if (typeof option == 'string') data[option](arg) 120 | }) 121 | } 122 | 123 | $.fn.spinner.Constructor = Spinner 124 | 125 | // SPINNER NO CONFLICT 126 | // =================== 127 | 128 | var trigger = function (event) { 129 | var $this = $(this) 130 | var href = $this.attr('href') 131 | var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) //strip for ie7 132 | var value = $this.data('value') 133 | 134 | if ($this.is('a')) event.preventDefault() 135 | 136 | $target.spinner(value) 137 | } 138 | 139 | $.fn.spinner.noConflict = function () { 140 | $.fn.spinner = old 141 | return this 142 | } 143 | 144 | // SPINNER DATA-API 145 | // ================ 146 | 147 | $(document) 148 | .on('click.bs.spinner.data-api', '[data-toggle="spinner"][data-on!="mousehold"]', trigger) 149 | .on('mousehold.bs.spinner.data-api', '[data-toggle="spinner"]', trigger) 150 | 151 | $(window).on('load', function () { 152 | $('[data-ride="spinner"]').each(function () { 153 | $(this).spinner() 154 | }) 155 | }) 156 | 157 | }(jQuery); 158 | -------------------------------------------------------------------------------- /src/mousehold.js: -------------------------------------------------------------------------------- 1 | /* ======================================================================== 2 | * mousehold.js v1.0.0 3 | * http://github.com/indigojs 4 | * ======================================================================== 5 | * Copyright 2014 Márk Sági-Kazár 6 | * Original author 2006 Remy Sharp (leftlogic.com) 7 | * Licensed under MIT (https://github.com/indigojs/bootstrap-spinner/blob/master/LICENSE) 8 | * ======================================================================== */ 9 | 10 | +function ($) { 11 | 'use strict'; 12 | 13 | // MOUSEHOLD PLUGIN DEFINITION 14 | // =========================== 15 | 16 | $.fn.mousehold = function(timeout) { 17 | timeout = typeof timeout !== 'undefined' ? timeout : 100; 18 | var interval = 0 19 | var fireStep = 0 20 | var clearMousehold = undefined; 21 | var e = $.Event('mousehold', { counter: 0 }) 22 | 23 | return this.each(function() { 24 | $(this).mousedown(function() { 25 | fireStep = 1 26 | var t = this 27 | 28 | interval = setInterval(function() { 29 | e.counter++ 30 | $(t).trigger(e) 31 | fireStep = 2 32 | }, timeout) 33 | }) 34 | 35 | clearMousehold = function() { 36 | clearInterval(interval) 37 | if (fireStep == 1) { 38 | e.counter = 1 39 | $(this).trigger(e) 40 | } 41 | 42 | fireStep = 0 43 | } 44 | 45 | $(this).mouseout(clearMousehold) 46 | $(this).mouseup(clearMousehold) 47 | }) 48 | } 49 | 50 | $(window).on('load', function () { 51 | $('[data-on="mousehold"]').each(function() { 52 | var $this = $(this) 53 | 54 | $this.mousehold($this.data('timeout')) 55 | }) 56 | }) 57 | 58 | }(jQuery); 59 | --------------------------------------------------------------------------------