1 | import BaseComponent from 'bootstrap/js/src/base-component'
|
2 | import EventHandler from 'bootstrap/js/src/dom/event-handler'
|
3 | import SelectorEngine from 'bootstrap/js/src/dom/selector-engine'
|
4 |
|
5 |
|
6 | import InputLabel from './input-label'
|
7 |
|
8 | const NAME = 'inputnumber'
|
9 | const DATA_KEY = 'bs.inputnumber'
|
10 | const EVENT_KEY = `.${DATA_KEY}`
|
11 | const DATA_API_KEY = '.data-api'
|
12 |
|
13 | const EVENT_CLICK = `click${EVENT_KEY}`
|
14 | const EVENT_CHANGE = `change${EVENT_KEY}`
|
15 | const EVENT_FOCUS_DATA_API = `focus${EVENT_KEY}${DATA_API_KEY}`
|
16 | const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
|
17 |
|
18 | const CLASS_NAME_ADAPTIVE = 'input-number-adaptive'
|
19 | const CLASS_NAME_PERCENTAGE = 'input-number-percentage'
|
20 | const CLASS_NAME_CURRENCY = 'input-number-currency'
|
21 | const CLASS_NAME_INCREMENT = 'input-number-add'
|
22 | const CLASS_NAME_DECREMENT = 'input-number-sub'
|
23 |
|
24 | const SELECTOR_WRAPPER = '.input-number'
|
25 | const SELECTOR_INPUT = 'input[data-bs-input][type="number"]'
|
26 | const SELECTOR_BTN = 'button'
|
27 |
|
28 | class 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 |
|
41 |
|
42 | static get NAME() {
|
43 | return NAME
|
44 | }
|
45 |
|
46 |
|
47 |
|
48 |
|
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 |
|
72 | if (!this._wrapperElement.classList.contains(CLASS_NAME_PERCENTAGE)) {
|
73 | newWidth = 'calc(44px + ' + this._element.value.length + 'ch)'
|
74 |
|
75 | }
|
76 | if (this._wrapperElement.classList.contains(CLASS_NAME_CURRENCY)) {
|
77 | newWidth = 'calc(40px + 44px + ' + this._element.value.length + 'ch)'
|
78 |
|
79 | }
|
80 |
|
81 | if (newWidth) {
|
82 | this._element.style.width = newWidth
|
83 |
|
84 | }
|
85 | }
|
86 | }
|
87 |
|
88 | _incrDecr(isDecr) {
|
89 | const inputVal = parseFloat(this._element.value)
|
90 |
|
91 | if (!isNaN(inputVal)) {
|
92 |
|
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 |
|
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 |
|
129 |
|
130 |
|
131 |
|
132 | const inputs = SelectorEngine.find(SELECTOR_INPUT)
|
133 | inputs.forEach((input) => {
|
134 | |
135 |
|
136 |
|
137 |
|
138 |
|
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 |
|
147 | const inputsButtons = SelectorEngine.find(SELECTOR_WRAPPER + ' ' + SELECTOR_BTN)
|
148 | inputsButtons.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 |
|
167 | export default InputNumber
|