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