1/* 2 * Bootstrap TouchSpin - v3.1.2 3 * A mobile and touch friendly input spinner component for Bootstrap 3. 4 * http://www.virtuosoft.eu/code/bootstrap-touchspin/ 5 * 6 * Made by István Ujj-Mészáros 7 * Under Apache License v2.0 License 8 */ 9(function($) { 10 'use strict'; 11 12 var _currentSpinnerId = 0; 13 14 function _scopedEventName(name, id) { 15 return name + '.touchspin_' + id; 16 } 17 18 function _scopeEventNames(names, id) { 19 return $.map(names, function(name) { 20 return _scopedEventName(name, id); 21 }); 22 } 23 24 $.fn.TouchSpin = function(options) { 25 26 if (options === 'destroy') { 27 this.each(function() { 28 var originalinput = $(this), 29 originalinput_data = originalinput.data(); 30 $(document).off(_scopeEventNames([ 31 'mouseup', 32 'touchend', 33 'touchcancel', 34 'mousemove', 35 'touchmove', 36 'scroll', 37 'scrollstart'], originalinput_data.spinnerid).join(' ')); 38 }); 39 return; 40 } 41 42 var defaults = { 43 min: 0, 44 max: 100, 45 initval: '', 46 replacementval: '', 47 step: 1, 48 decimals: 0, 49 stepinterval: 100, 50 forcestepdivisibility: 'round', // none | floor | round | ceil 51 stepintervaldelay: 500,
52 verticalbuttons: false, 53 verticalupclass: 'glyphicon glyphicon-chevron-up', 54 verticaldownclass: 'glyphicon glyphicon-chevron-down', 55 prefix: '', 56 postfix: '', 57 prefix_extraclass: '', 58 postfix_extraclass: '', 59 booster: true, 60 boostat: 10, 61 maxboostedstep: false, 62 mousewheel: true, 63 buttondown_class: 'btn btn-default', 64 buttonup_class: 'btn btn-default', 65 buttondown_txt: '-', 66 buttonup_txt: '+' 67 }; 68 69 var attributeMap = { 70 min: 'min', 71 max: 'max', 72 initval: 'init-val', 73 replacementval: 'replacement-val', 74 step: 'step', 75 decimals: 'decimals', 76 stepinterval: 'step-interval', 77 verticalbuttons: 'vertical-buttons', 78 verticalupclass: 'vertical-up-class', 79 verticaldownclass: 'vertical-down-class', 80 forcestepdivisibility: 'force-step-divisibility', 81 stepintervaldelay: 'step-interval-delay', 82 prefix: 'prefix', 83 postfix: 'postfix', 84 prefix_extraclass: 'prefix-extra-class', 85 postfix_extraclass: 'postfix-extra-class', 86 booster: 'booster', 87 boostat: 'boostat', 88 maxboostedstep: 'max-boosted-step', 89 mousewheel: 'mouse-wheel', 90 buttondown_class: 'button-down-class', 91 buttonup_class: 'button-up-class', 92 buttondown_txt: 'button-down-txt', 93 buttonup_txt: 'button-up-txt' 94 }; 95 96 return this.each(function() { 97 98 var settings, 99 originalinput = $(this), 100 originalinput_data = originalinput.data(), 101 container, 102 elements, 103 value, 104 downSpinTimer, 105 upSpinTimer, 106 downDelayTimeout, 107 upDelayTimeout, 108 spincount = 0, 109 spinning = false; 110 111 init(); 112 113 114 function init() { 115 if (originalinput.data('alreadyinitialized')) { 116 return; 117 } 118 119 originalinput.data('alreadyinitialized', true); 120 _currentSpinnerId += 1; 121 originalinput.data('spinnerid', _currentSpinnerId); 122 123 124 if (!originalinput.is('input')) { 125 console.log('Must be an input.'); 126 return; 127 } 128 129 _initSettings(); 130 _setInitval(); 131 _checkValue(); 132 _buildHtml(); 133 _initElements(); 134 _hideEmptyPrefixPostfix(); 135 _bindEvents(); 136 _bindEventsInterface(); 137 elements.input.css('display', 'block'); 138 } 139 140 function _setInitval() { 141 if (settings.initval !== '' && originalinput.val() === '') { 142 originalinput.val(settings.initval); 143 } 144 } 145 146 function changeSettings(newsettings) { 147 _updateSettings(newsettings); 148 _checkValue(); 149 150 var value = elements.input.val(); 151 152 if (value !== '') { 153 value = Number(elements.input.val()); 154 elements.input.val(value.toFixed(settings.decimals)); 155 } 156 } 157 158 function _initSettings() { 159 settings = $.extend({}, defaults, originalinput_data, _parseAttributes(), options); 160 } 161 162 function _parseAttributes() { 163 var data = {}; 164 $.each(attributeMap, function(key, value) { 165 var attrName = 'bts-' + value + ''; 166 if (originalinput.is('[data-' + attrName + ']')) { 167 data[key] = originalinput.data(attrName); 168 } 169 }); 170 return data; 171 } 172 173 function _updateSettings(newsettings) { 174 settings = $.extend({}, settings, newsettings); 175 176 // Update postfix and prefix texts if those settings were changed. 177 if (newsettings.postfix) { 178 originalinput.parent().find('.bootstrap-touchspin-postfix').text(newsettings.postfix); 179 } 180 if (newsettings.prefix) { 181 originalinput.parent().find('.bootstrap-touchspin-prefix').text(newsettings.prefix); 182 } 183 } 184 185 function _buildHtml() { 186 var initval = originalinput.val(), 187 parentelement = originalinput.parent(); 188 189 if (initval !== '') { 190 initval = Number(initval).toFixed(settings.decimals); 191 } 192 193 originalinput.data('initvalue', initval).val(initval); 194 originalinput.addClass('form-control'); 195 196 if (parentelement.hasClass('input-group')) { 197 _advanceInputGroup(parentelement); 198 } 199 else { 200 _buildInputGroup(); 201 } 202 } 203 204 function _advanceInputGroup(parentelement) { 205 parentelement.addClass('bootstrap-touchspin'); 206 207 var prev = originalinput.prev(), 208 next = originalinput.next(); 209 210 var downhtml, 211 uphtml, 212 prefixhtml = '<span class="input-group-addon bootstrap-touchspin-prefix">' + settings.prefix + '</span>', 213 postfixhtml = '<span class="input-group-addon bootstrap-touchspin-postfix">' + settings.postfix + '</span>'; 214 215 if (prev.hasClass('input-group-btn')) { 216 downhtml = '<button class="' + settings.buttondown_class + ' bootstrap-touchspin-down" type="button">' + settings.buttondown_txt + '</button>'; 217 prev.append(downhtml); 218 } 219 else { 220 downhtml = '<span class="input-group-btn"><button class="' + settings.buttondown_class + ' bootstrap-touchspin-down" type="button">' + settings.buttondown_txt + '</button></span>'; 221 $(downhtml).insertBefore(originalinput); 222 } 223 224 if (next.hasClass('input-group-btn')) { 225 uphtml = '<button class="' + settings.buttonup_class + ' bootstrap-touchspin-up" type="button">' + settings.buttonup_txt + '</button>'; 226 next.prepend(uphtml); 227 } 228 else { 229 uphtml = '<span class="input-group-btn"><button class="' + settings.buttonup_class + ' bootstrap-touchspin-up" type="button">' + settings.buttonup_txt + '</button></span>'; 230 $(uphtml).insertAfter(originalinput); 231 } 232 233 $(prefixhtml).insertBefore(originalinput); 234 $(postfixhtml).insertAfter(originalinput); 235 236 container = parentelement; 237 } 238 239 function _buildInputGroup() { 240 var html; 241 242 if (settings.verticalbuttons) { 243 html = '<div class="input-group bootstrap-touchspin"><span class="input-group-addon bootstrap-touchspin-prefix">' + settings.prefix + '</span><span class="input-group-addon bootstrap-touchspin-postfix">' + settings.postfix + '</span><span class="input-group-btn-vertical"><button class="' + settings.buttondown_class + ' bootstrap-touchspin-up" type="button"><i class="' + settings.verticalupclass + '"></i></button><button class="' + settings.buttonup_class + ' bootstrap-touchspin-down" type="button"><i class="' + settings.verticaldownclass + '"></i></button></span></div>'; 244 } 245 else { 246 html = '<div class="input-group bootstrap-touchspin"><span class="input-group-btn"><button class="' + settings.buttondown_class + ' bootstrap-touchspin-down" type="button">' + settings.buttondown_txt + '</button></span><span class="input-group-addon bootstrap-touchspin-prefix">' + settings.prefix + '</span><span class="input-group-addon bootstrap-touchspin-postfix">' + settings.postfix + '</span><span class="input-group-btn"><button class="' + settings.buttonup_class + ' bootstrap-touchspin-up" type="button">' + settings.buttonup_txt + '</button></span></div>'; 247 } 248 249 container = $(html).insertBefore(originalinput); 250 251 $('.bootstrap-touchspin-prefix', container).after(originalinput); 252 253 if (originalinput.hasClass('input-sm')) { 254 container.addClass('input-group-sm'); 255 } 256 else if (originalinput.hasClass('input-lg')) { 257 container.addClass('input-group-lg'); 258 } 259 } 260 261 function _initElements() { 262 elements = { 263 down: $('.bootstrap-touchspin-down', container), 264 up: $('.bootstrap-touchspin-up', container), 265 input: $('input', container), 266 prefix: $('.bootstrap-touchspin-prefix', container).addClass(settings.prefix_extraclass), 267 postfix: $('.bootstrap-touchspin-postfix', container).addClass(settings.postfix_extraclass) 268 }; 269 } 270 271 function _hideEmptyPrefixPostfix() { 272 if (settings.prefix === '') { 273 elements.prefix.hide(); 274 } 275 276 if (settings.postfix === '') { 277 elements.postfix.hide(); 278 } 279 } 280 281 function _bindEvents() { 282 originalinput.on('keydown', function(ev) { 283 var code = ev.keyCode || ev.which; 284 285 if (code === 38) { 286 if (spinning !== 'up') { 287 upOnce(); 288 startUpSpin(); 289 } 290 ev.preventDefault(); 291 } 292 else if (code === 40) { 293 if (spinning !== 'down') { 294 downOnce(); 295 startDownSpin(); 296 } 297 ev.preventDefault(); 298 } 299 }); 300 301 originalinput.on('keyup', function(ev) { 302 var code = ev.keyCode || ev.which; 303 304 if (code === 38) { 305 stopSpin(); 306 } 307 else if (code === 40) { 308 stopSpin(); 309 } 310 }); 311 312 originalinput.on('blur', function() { 313 _checkValue(); 314 }); 315 316 elements.down.on('keydown', function(ev) { 317 var code = ev.keyCode || ev.which; 318 319 if (code === 32 || code === 13) { 320 if (spinning !== 'down') { 321 downOnce(); 322 startDownSpin(); 323 } 324 ev.preventDefault(); 325 } 326 }); 327 328 elements.down.on('keyup', function(ev) { 329 var code = ev.keyCode || ev.which; 330 331 if (code === 32 || code === 13) { 332 stopSpin(); 333 } 334 }); 335 336 elements.up.on('keydown', function(ev) { 337 var code = ev.keyCode || ev.which; 338 339 if (code === 32 || code === 13) { 340 if (spinning !== 'up') { 341 upOnce(); 342 startUpSpin(); 343 } 344 ev.preventDefault(); 345 } 346 }); 347 348 elements.up.on('keyup', function(ev) { 349 var code = ev.keyCode || ev.which; 350 351 if (code === 32 || code === 13) { 352 stopSpin(); 353 } 354 }); 355 356 elements.down.on('mousedown.touchspin', function(ev) { 357 elements.down.off('touchstart.touchspin'); // android 4 workaround 358 359 if (originalinput.is(':disabled')) { 360 return; 361 } 362 363 downOnce(); 364 startDownSpin(); 365 366 ev.preventDefault(); 367 ev.stopPropagation(); 368 }); 369 370 elements.down.on('touchstart.touchspin', function(ev) { 371 elements.down.off('mousedown.touchspin'); // android 4 workaround 372 373 if (originalinput.is(':disabled')) { 374 return; 375 } 376 377 downOnce(); 378 startDownSpin(); 379 380 ev.preventDefault(); 381 ev.stopPropagation(); 382 }); 383 384 elements.up.on('mousedown.touchspin', function(ev) { 385 elements.up.off('touchstart.touchspin'); // android 4 workaround 386 387 if (originalinput.is(':disabled')) { 388 return; 389 } 390 391 upOnce(); 392 startUpSpin(); 393 394 ev.preventDefault(); 395 ev.stopPropagation(); 396 }); 397 398 elements.up.on('touchstart.touchspin', function(ev) { 399 elements.up.off('mousedown.touchspin'); // android 4 workaround 400 401 if (originalinput.is(':disabled')) { 402 return; 403 } 404 405 upOnce(); 406 startUpSpin(); 407 408 ev.preventDefault(); 409 ev.stopPropagation(); 410 }); 411 412 elements.up.on('mouseout touchleave touchend touchcancel', function(ev) { 413 if (!spinning) { 414 return; 415 } 416 417 ev.stopPropagation(); 418 stopSpin(); 419 }); 420 421 elements.down.on('mouseout touchleave touchend touchcancel', function(ev) { 422 if (!spinning) { 423 return; 424 } 425 426 ev.stopPropagation(); 427 stopSpin(); 428 }); 429 430 elements.down.on('mousemove touchmove', function(ev) { 431 if (!spinning) { 432 return; 433 } 434 435 ev.stopPropagation(); 436 ev.preventDefault(); 437 }); 438 439 elements.up.on('mousemove touchmove', function(ev) { 440 if (!spinning) { 441 return; 442 } 443 444 ev.stopPropagation(); 445 ev.preventDefault(); 446 }); 447 448 $(document).on(_scopeEventNames(['mouseup', 'touchend', 'touchcancel'], _currentSpinnerId).join(' '), function(ev) { 449 if (!spinning) { 450 return; 451 } 452 453 ev.preventDefault(); 454 stopSpin(); 455 }); 456 457 $(document).on(_scopeEventNames(['mousemove', 'touchmove', 'scroll', 'scrollstart'], _currentSpinnerId).join(' '), function(ev) { 458 if (!spinning) { 459 return; 460 } 461 462 ev.preventDefault(); 463 stopSpin(); 464 }); 465 466 originalinput.on('mousewheel DOMMouseScroll', function(ev) { 467 if (!settings.mousewheel || !originalinput.is(':focus')) { 468 return; 469 } 470 471 var delta = ev.originalEvent.wheelDelta || -ev.originalEvent.deltaY || -ev.originalEvent.detail; 472 473 ev.stopPropagation(); 474 ev.preventDefault(); 475 476 if (delta < 0) { 477 downOnce(); 478 } 479 else { 480 upOnce(); 481 } 482 }); 483 } 484 485 function _bindEventsInterface() { 486 originalinput.on('touchspin.uponce', function() { 487 stopSpin(); 488 upOnce(); 489 }); 490 491 originalinput.on('touchspin.downonce', function() { 492 stopSpin(); 493 downOnce(); 494 }); 495 496 originalinput.on('touchspin.startupspin', function() { 497 startUpSpin(); 498 }); 499 500 originalinput.on('touchspin.startdownspin', function() { 501 startDownSpin(); 502 }); 503 504 originalinput.on('touchspin.stopspin', function() { 505 stopSpin(); 506 }); 507 508 originalinput.on('touchspin.updatesettings', function(e, newsettings) { 509 changeSettings(newsettings); 510 }); 511 } 512 513 function _forcestepdivisibility(value) { 514 switch (settings.forcestepdivisibility) { 515 case 'round': 516 return (Math.round(value / settings.step) * settings.step).toFixed(settings.decimals); 517 case 'floor': 518 return (Math.floor(value / settings.step) * settings.step).toFixed(settings.decimals);
519 case 'ceil': 520 return (Math.ceil(value / settings.step) * settings.step).toFixed(settings.decimals); 521 default: 522 return value; 523 } 524 } 525 526 function _checkValue() { 527 var val, parsedval, returnval; 528 529 val = originalinput.val(); 530 531 if (val === '') { 532 if (settings.replacementval !== '') { 533 originalinput.val(settings.replacementval); 534 originalinput.trigger('change'); 535 } 536 return; 537 } 538 539 if (settings.decimals > 0 && val === '.') { 540 return; 541 } 542 543 parsedval = parseFloat(val); 544 545 if (isNaN(parsedval)) { 546 if (settings.replacementval !== '') { 547 parsedval = settings.replacementval; 548 } 549 else { 550 parsedval = 0; 551 } 552 } 553 554 returnval = parsedval; 555 556 if (parsedval.toString() !== val) { 557 returnval = parsedval; 558 } 559 560 if (parsedval < settings.min) { 561 returnval = settings.min; 562 } 563 564 if (parsedval > settings.max) { 565 returnval = settings.max; 566 } 567 568 returnval = _forcestepdivisibility(returnval); 569 570 if (Number(val).toString() !== returnval.toString()) { 571 originalinput.val(returnval); 572 originalinput.trigger('change'); 573 } 574 } 575 576 function _getBoostedStep() { 577 if (!settings.booster) { 578 return settings.step; 579 } 580 else { 581 var boosted = Math.pow(2, Math.floor(spincount / settings.boostat)) * settings.step; 582 583 if (settings.maxboostedstep) { 584 if (boosted > settings.maxboostedstep) { 585 boosted = settings.maxboostedstep; 586 value = Math.round((value / boosted)) * boosted; 587 } 588 } 589 590 return Math.max(settings.step, boosted); 591 } 592 } 593 594 function upOnce() { 595 _checkValue(); 596 597 value = parseFloat(elements.input.val()); 598 if (isNaN(value)) { 599 value = 0; 600 } 601 602 var initvalue = value, 603 boostedstep = _getBoostedStep(); 604 605 value = value + boostedstep; 606 607 if (value > settings.max) { 608 value = settings.max; 609 originalinput.trigger('touchspin.on.max'); 610 stopSpin(); 611 } 612 613 elements.input.val(Number(value).toFixed(settings.decimals)); 614 615 if (initvalue !== value) { 616 originalinput.trigger('change'); 617 } 618 } 619 620 function downOnce() { 621 _checkValue(); 622 623 value = parseFloat(elements.input.val()); 624 if (isNaN(value)) { 625 value = 0; 626 } 627 628 var initvalue = value, 629 boostedstep = _getBoostedStep(); 630 631 value = value - boostedstep; 632 633 if (value < settings.min) { 634 value = settings.min; 635 originalinput.trigger('touchspin.on.min'); 636 stopSpin(); 637 } 638 639 elements.input.val(value.toFixed(settings.decimals)); 640 641 if (initvalue !== value) { 642 originalinput.trigger('change'); 643 } 644 } 645 646 function startDownSpin() { 647 stopSpin(); 648 649 spincount = 0; 650 spinning = 'down'; 651 652 originalinput.trigger('touchspin.on.startspin'); 653 originalinput.trigger('touchspin.on.startdownspin'); 654 655 downDelayTimeout = setTimeout(function() { 656 downSpinTimer = setInterval(function() { 657 spincount++; 658 downOnce(); 659 }, settings.stepinterval); 660 }, settings.stepintervaldelay); 661 } 662 663 function startUpSpin() { 664 stopSpin(); 665 666 spincount = 0; 667 spinning = 'up'; 668 669 originalinput.trigger('touchspin.on.startspin'); 670 originalinput.trigger('touchspin.on.startupspin'); 671 672 upDelayTimeout = setTimeout(function() { 673 upSpinTimer = setInterval(function() { 674 spincount++; 675 upOnce(); 676 }, settings.stepinterval); 677 }, settings.stepintervaldelay); 678 } 679 680 function stopSpin() { 681 clearTimeout(downDelayTimeout); 682 clearTimeout(upDelayTimeout); 683 clearInterval(downSpinTimer); 684 clearInterval(upSpinTimer); 685 686 switch (spinning) { 687 case 'up': 688 originalinput.trigger('touchspin.on.stopupspin'); 689 originalinput.trigger('touchspin.on.stopspin'); 690 break; 691 case 'down': 692 originalinput.trigger('touchspin.on.stopdownspin'); 693 originalinput.trigger('touchspin.on.stopspin'); 694 break; 695 } 696 697 spincount = 0; 698 spinning = false; 699 } 700 701 });
702 703 }; 704 705})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.