Built files from Bizgaze WebServer
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

bootstrap-input-spinner.js 8.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /**
  2. * Author and copyright: Stefan Haack (https://shaack.com)
  3. * Repository: https://github.com/shaack/bootstrap-input-spinner
  4. * License: MIT, see file 'LICENSE'
  5. */
  6. (function ($) {
  7. "use strict"
  8. var spacePressed = false
  9. var originalVal = $.fn.val
  10. $.fn.val = function (value) {
  11. if (arguments.length >= 1) {
  12. if (this[0]["bootstrap-input-spinner"] && this[0].setValue) {
  13. this[0].setValue(value)
  14. }
  15. }
  16. return originalVal.apply(this, arguments)
  17. }
  18. $.fn.InputSpinner = $.fn.inputSpinner = function (options) {
  19. var config = {
  20. decrementButton: "<strong>-</strong>", // button text
  21. incrementButton: "<strong>+</strong>", // ..
  22. groupClass: "", // css class of the input-group (sizing with input-group-sm, input-group-lg)
  23. buttonsClass: "btn-outline-secondary",
  24. buttonsWidth: "2.5em",
  25. textAlign: "center",
  26. autoDelay: 500, // ms holding before auto value change
  27. autoInterval: 100, // speed of auto value change
  28. boostThreshold: 10, // boost after these steps
  29. boostMultiplier: "auto", // you can also set a constant number as multiplier
  30. locale: null // the locale for number rendering; if null, the browsers language is used
  31. }
  32. Object.assign(config, options)
  33. var html = '<div class="input-group ' + config.groupClass + '">' +
  34. '<div class="input-group-prepend">' +
  35. '<button style="min-width: ' + config.buttonsWidth + '" class="btn btn-decrement ' + config.buttonsClass + '" type="button">' + config.decrementButton + '</button>' +
  36. '</div>' +
  37. '<input type="text" style="text-align: ' + config.textAlign + '" class="form-control"/>' +
  38. '<div class="input-group-append">' +
  39. '<button style="min-width: ' + config.buttonsWidth + '" class="btn btn-increment ' + config.buttonsClass + '" type="button">' + config.incrementButton + '</button>' +
  40. '</div>' +
  41. '</div>'
  42. var locale = config.locale || navigator.language || "en-US"
  43. this.each(function () {
  44. var $original = $(this)
  45. $original[0]["bootstrap-input-spinner"] = true
  46. $original.hide()
  47. var autoDelayHandler = null
  48. var autoIntervalHandler = null
  49. var autoMultiplier = config.boostMultiplier === "auto"
  50. var boostMultiplier = autoMultiplier ? 1 : config.boostMultiplier
  51. var $inputGroup = $(html)
  52. var $buttonDecrement = $inputGroup.find(".btn-decrement")
  53. var $buttonIncrement = $inputGroup.find(".btn-increment")
  54. var $input = $inputGroup.find("input")
  55. var min = parseFloat($original.prop("min")) || 0
  56. var max = isNaN($original.prop("max")) || $original.prop("max") === "" ? Infinity : parseFloat($original.prop("max"))
  57. var step = parseFloat($original.prop("step")) || 1
  58. var decimals = parseInt($original.attr("data-decimals")) || 0
  59. var numberFormat = new Intl.NumberFormat(locale, {
  60. minimumFractionDigits: decimals,
  61. maximumFractionDigits: decimals
  62. })
  63. var value = parseFloat($original[0].value)
  64. var boostStepsCount = 0
  65. $original[0].setValue = function (newValue) {
  66. setValue(newValue)
  67. }
  68. if ($original.prop("class").indexOf("is-invalid") !== -1) { // TODO dynamically copy all classes
  69. $input.addClass("is-invalid")
  70. }
  71. if ($original.prop("class").indexOf("is-valid") !== -1) {
  72. $input.addClass("is-valid")
  73. }
  74. if ($original.prop("required")) {
  75. $input.prop("required", true)
  76. }
  77. if ($original.prop("placeholder")) {
  78. $input.prop("placeholder", $original.prop("placeholder"))
  79. }
  80. $original.after($inputGroup)
  81. if (isNaN(value)) {
  82. $original[0].value = ""
  83. $input[0].value = ""
  84. } else {
  85. $original[0].value = value
  86. $input[0].value = numberFormat.format(value)
  87. }
  88. $input.on("paste keyup change", function () {
  89. var inputValue = $input[0].value
  90. if (locale === "en-US" || locale === "en-GB" || locale === "th-TH") {
  91. value = parseFloat(inputValue)
  92. } else {
  93. value = parseFloat(inputValue.replace(/[. ]/g, '').replace(/,/g, '.')) // i18n
  94. }
  95. if (isNaN(value)) {
  96. $original[0].value = ""
  97. } else {
  98. $original[0].value = value
  99. }
  100. dispatchChangeEvents($original)
  101. })
  102. onPointerDown($buttonDecrement[0], function () {
  103. stepHandling(-step)
  104. })
  105. onPointerDown($buttonIncrement[0], function () {
  106. stepHandling(step)
  107. })
  108. onPointerUp(document.body, function () {
  109. resetTimer()
  110. })
  111. function setValue(newValue) {
  112. if (isNaN(newValue) || newValue === "") {
  113. $original[0].value = ""
  114. $input[0].value = ""
  115. value = 0.0
  116. } else {
  117. $original[0].value = newValue
  118. $input[0].value = numberFormat.format(newValue)
  119. value = parseFloat(newValue)
  120. }
  121. }
  122. function dispatchChangeEvents($element) {
  123. setTimeout(function () {
  124. var changeEvent = new Event("change", {bubbles: true})
  125. var inputEvent = new Event("input", {bubbles: true})
  126. $element[0].dispatchEvent(changeEvent)
  127. $element[0].dispatchEvent(inputEvent)
  128. })
  129. }
  130. function stepHandling(step) {
  131. calcStep(step)
  132. resetTimer()
  133. autoDelayHandler = setTimeout(function () {
  134. autoIntervalHandler = setInterval(function () {
  135. if (boostStepsCount > config.boostThreshold) {
  136. if (autoMultiplier) {
  137. calcStep(step * parseInt(boostMultiplier, 10))
  138. boostMultiplier = Math.min(1000000, boostMultiplier * 1.1)
  139. } else {
  140. calcStep(step * boostMultiplier)
  141. }
  142. } else {
  143. calcStep(step)
  144. }
  145. boostStepsCount++
  146. }, config.autoInterval)
  147. }, config.autoDelay)
  148. }
  149. function calcStep(step) {
  150. if (isNaN(value)) {
  151. value = 0
  152. }
  153. value = Math.round(value / step) * step
  154. value = Math.min(Math.max(value + step, min), max)
  155. $input[0].value = numberFormat.format(value)
  156. $original[0].value = Math.round(value * Math.pow(10, decimals)) / Math.pow(10, decimals)
  157. dispatchChangeEvents($original)
  158. }
  159. function resetTimer() {
  160. boostStepsCount = 0
  161. boostMultiplier = boostMultiplier = autoMultiplier ? 1 : config.boostMultiplier
  162. clearTimeout(autoDelayHandler)
  163. clearTimeout(autoIntervalHandler)
  164. }
  165. })
  166. }
  167. function onPointerUp(element, callback) {
  168. element.addEventListener("mouseup", function (e) {
  169. callback(e)
  170. })
  171. element.addEventListener("touchend", function (e) {
  172. callback(e)
  173. })
  174. element.addEventListener("keyup", function (e) {
  175. if (e.keyCode === 32) {
  176. spacePressed = false
  177. callback(e)
  178. }
  179. })
  180. }
  181. function onPointerDown(element, callback) {
  182. element.addEventListener("mousedown", function (e) {
  183. e.preventDefault()
  184. callback(e)
  185. })
  186. element.addEventListener("touchstart", function (e) {
  187. e.preventDefault()
  188. callback(e)
  189. })
  190. element.addEventListener("keydown", function (e) {
  191. if (e.keyCode === 32 && !spacePressed) {
  192. spacePressed = true
  193. callback(e)
  194. }
  195. })
  196. }
  197. }(jQuery))