UNPKG

4.78 kBJavaScriptView Raw
1import BaseComponent from 'bootstrap/js/src/base-component'
2import EventHandler from 'bootstrap/js/src/dom/event-handler'
3import SelectorEngine from 'bootstrap/js/src/dom/selector-engine'
4//import Manipulator from 'bootstrap/js/src/dom/manipulator'
5
6import InputLabel from './input-label'
7
8const NAME = 'inputnumber'
9const DATA_KEY = 'bs.inputnumber'
10const EVENT_KEY = `.${DATA_KEY}`
11const DATA_API_KEY = '.data-api'
12
13const EVENT_CLICK = `click${EVENT_KEY}`
14const EVENT_CHANGE = `change${EVENT_KEY}`
15const EVENT_FOCUS_DATA_API = `focus${EVENT_KEY}${DATA_API_KEY}`
16const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
17
18const CLASS_NAME_ADAPTIVE = 'input-number-adaptive'
19const CLASS_NAME_PERCENTAGE = 'input-number-percentage'
20const CLASS_NAME_CURRENCY = 'input-number-currency'
21const CLASS_NAME_INCREMENT = 'input-number-add'
22const CLASS_NAME_DECREMENT = 'input-number-sub'
23
24const SELECTOR_WRAPPER = '.input-number'
25const SELECTOR_INPUT = 'input[data-bs-input][type="number"]'
26const SELECTOR_BTN = 'button'
27
28class InputNumber extends BaseComponent {
29 constructor(element) {
30 super(element)
31
32 this._wrapperElement = this._element.closest(SELECTOR_WRAPPER)
33
34 this._label = new InputLabel(element)
35
36 this._init()
37 this._bindEvents()
38 }
39
40 // Getters
41
42 static get NAME() {
43 return NAME
44 }
45
46 // Public
47
48 // Private
49 _init() {
50 if (this._wrapperElement) {
51 this._inputResize()
52 }
53 }
54
55 _bindEvents() {
56 if (this._wrapperElement) {
57 SelectorEngine.find(SELECTOR_BTN, this._wrapperElement).forEach((btn) => {
58 EventHandler.on(btn, EVENT_CLICK, (evt) => {
59 evt.preventDefault()
60 this._incrDecr(btn.classList.contains(CLASS_NAME_DECREMENT))
61 })
62 })
63
64 EventHandler.on(this._element, EVENT_CHANGE, () => this._checkLimit())
65 }
66 }
67
68 _inputResize() {
69 if (this._wrapperElement.classList.contains(CLASS_NAME_ADAPTIVE)) {
70 let newWidth = null
71 //let newWidthIE = null
72 if (!this._wrapperElement.classList.contains(CLASS_NAME_PERCENTAGE)) {
73 newWidth = 'calc(44px + ' + this._element.value.length + 'ch)'
74 //newWidthIE = 'calc(44px + (1.5 * ' + this._element.value.length + 'ch))'
75 }
76 if (this._wrapperElement.classList.contains(CLASS_NAME_CURRENCY)) {
77 newWidth = 'calc(40px + 44px + ' + this._element.value.length + 'ch)'
78 //newWidthIE = 'calc(40px + 44px + (1.5 * ' + this._element.value.length + 'ch))'
79 }
80
81 if (newWidth) {
82 this._element.style.width = newWidth
83 //IE - this._element.style.width = calcIe
84 }
85 }
86 }
87
88 _incrDecr(isDecr) {
89 const inputVal = parseFloat(this._element.value)
90
91 if (!isNaN(inputVal)) {
92 //get step
93 let step = parseFloat(this._element.getAttribute('step'))
94 if (!step) {
95 step = 1
96 }
97
98 this._element.value = inputVal + step * (isDecr ? -1 : 1)
99 EventHandler.trigger(this._element, EVENT_CHANGE)
100 }
101 }
102
103 _checkLimit() {
104 const inputVal = parseFloat(this._element.value)
105
106 if (!isNaN(inputVal)) {
107 let val = inputVal
108 const max = parseFloat(this._element.getAttribute('max'))
109 const min = parseFloat(this._element.getAttribute('min'))
110
111 if (min && inputVal < min) {
112 val = min
113 }
114 //limit max
115 if (max && inputVal > max) {
116 val = max
117 }
118
119 this._element.value = val
120 }
121
122 this._inputResize()
123 }
124}
125
126/**
127 * ------------------------------------------------------------------------
128 * Data Api implementation
129 * ------------------------------------------------------------------------
130 */
131
132const inputs = SelectorEngine.find(SELECTOR_INPUT)
133inputs.forEach((input) => {
134 /*const prevInst = BaseComponent.getInstance(input)
135 if (prevInst.NAME === 'input') {
136 prevInst.dispose()
137 }
138 InputNumber.getOrCreateInstance(input)*/
139
140 EventHandler.one(input, EVENT_FOCUS_DATA_API, (evt) => {
141 evt.preventDefault()
142 InputNumber.getOrCreateInstance(input)
143 EventHandler.trigger(input, 'focus')
144 })
145})
146
147const inputsButtons = SelectorEngine.find(SELECTOR_WRAPPER + ' ' + SELECTOR_BTN)
148inputsButtons.forEach((button) => {
149 EventHandler.one(button, EVENT_CLICK_DATA_API, (evt) => {
150 if (button.classList.contains(CLASS_NAME_INCREMENT) || button.classList.contains(CLASS_NAME_DECREMENT)) {
151 const wrapper = button.closest(SELECTOR_WRAPPER)
152 if (wrapper) {
153 const input = SelectorEngine.findOne(SELECTOR_INPUT, wrapper)
154 if (input) {
155 const inputNumber = InputNumber.getInstance(input)
156 if (!inputNumber) {
157 evt.preventDefault()
158 InputNumber.getOrCreateInstance(input)
159 EventHandler.trigger(button, 'click')
160 }
161 }
162 }
163 }
164 })
165})
166
167export default InputNumber