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