UNPKG

9.08 kBJavaScriptView Raw
1import BaseComponent from 'bootstrap/js/src/base-component.js'
2
3/*import {
4 //defineJQueryPlugin,
5 //getElementFromSelector,
6 //isVisible,
7 //reflow,
8 //typeCheckConfig,
9 getSelectorFromElement, //in base al bs-target
10} from 'bootstrap/js/src/util'*/
11import EventHandler from 'bootstrap/js/src/dom/event-handler'
12import SelectorEngine from 'bootstrap/js/src/dom/selector-engine'
13//import Manipulator from 'bootstrap/js/src/dom/manipulator'
14
15const NAME = 'transfer'
16const DATA_KEY = 'bs.transfer'
17const EVENT_KEY = `.${DATA_KEY}`
18//const DATA_API_KEY = '.data-api'
19
20//const EVENT_SCROLL = `scroll${EVENT_KEY}`
21const EVENT_CLICK = `click${EVENT_KEY}`
22
23const CLASS_NAME_ACTIVE = 'active'
24const CLASS_NAME_SOURCE = 'source'
25const CLASS_NAME_SEMICHECKED = 'semi-checked'
26
27const SELECTOR_BLOCK = '[data-bs-transfer]' //'.it-transfer-block'
28const SELECTOR_BTN_TRANS = 'a.transfer'
29const SELECTOR_BTN_TRANS_BACK = 'a.backtransfer'
30const SELECTOR_BTN_RESET = 'a.reset'
31const SELECTOR_HEAD = '.transfer-header'
32const SELECTOR_HEAD_INPUT = '.transfer-header input'
33const SELECTOR_HEAD_LABEL = '.transfer-header span.num'
34const SELECTOR_LIST_INPUT = '.transfer-group input'
35const SELECTOR_TRANS_WRAPPER = '.it-transfer-wrapper'
36const SELECTOR_TRANS_GROUP = '.transfer-group'
37const SELECTOR_SOURCE = `${SELECTOR_TRANS_WRAPPER}.source`
38const SELECTOR_TARGET = `${SELECTOR_TRANS_WRAPPER}.target`
39const SELECTOR_FORM_CHECK = '.form-check'
40
41class Transfer extends BaseComponent {
42 constructor(element) {
43 super(element)
44
45 this._addBtnElement = SelectorEngine.findOne(SELECTOR_BTN_TRANS, this._element)
46 this._invBtnElement = SelectorEngine.findOne(SELECTOR_BTN_TRANS_BACK, this._element)
47 this._resetBtnElement = SelectorEngine.findOne(SELECTOR_BTN_RESET, this._element)
48 this._listDefault = {
49 source: SelectorEngine.find(SELECTOR_SOURCE + ' ' + SELECTOR_TRANS_GROUP + ' ' + SELECTOR_FORM_CHECK, this._element),
50 target: SelectorEngine.find(SELECTOR_TARGET + ' ' + SELECTOR_TRANS_GROUP + ' ' + SELECTOR_FORM_CHECK, this._element),
51 }
52
53 this._bindEvents()
54 }
55
56 // Getters
57
58 static get NAME() {
59 return NAME
60 }
61
62 // Public
63
64 // Private
65
66 _bindEvents() {
67 SelectorEngine.find(SELECTOR_HEAD_INPUT, this._element).forEach((input) => {
68 EventHandler.on(input, EVENT_CLICK, () => {
69 this._checkListHeader(input.closest(SELECTOR_TRANS_WRAPPER))
70 })
71 })
72 SelectorEngine.find(SELECTOR_LIST_INPUT, this._element).forEach((input) => {
73 EventHandler.on(input, EVENT_CLICK, () => {
74 this._checkList(input.closest(SELECTOR_TRANS_WRAPPER))
75 })
76 })
77
78 EventHandler.on(this._addBtnElement, EVENT_CLICK, (evt) => {
79 evt.preventDefault()
80 // disattivo il pulsante corrente
81 this._disableElement(this._addBtnElement)
82 this._addItems()
83 })
84 EventHandler.on(this._invBtnElement, EVENT_CLICK, (evt) => {
85 evt.preventDefault()
86 // disattivo il pulsante corrente
87 this._disableElement(this._invBtnElement)
88 this._addItems(true)
89 })
90
91 EventHandler.on(this._resetBtnElement, EVENT_CLICK, (evt) => {
92 evt.preventDefault()
93
94 this._disableElement(this._addBtnElement)
95 this._disableElement(this._invBtnElement)
96 this._disableElement(this._resetBtnElement)
97
98 this._resetAll()
99 })
100 }
101
102 _disableElement(element) {
103 element.classList.remove(CLASS_NAME_ACTIVE)
104 element.setAttribute('disabled', 'disabled')
105 element.setAttribute('aria-disabled', 'true')
106 }
107
108 _enableElement(element) {
109 element.classList.add(CLASS_NAME_ACTIVE)
110 element.removeAttribute('disabled')
111 element.removeAttribute('aria-disabled')
112 }
113
114 _getScopeData(scope) {
115 return {
116 scope,
117 list: SelectorEngine.find(SELECTOR_LIST_INPUT, scope),
118 listChecked: SelectorEngine.find(SELECTOR_LIST_INPUT + ':checked', scope),
119 head: SelectorEngine.findOne(SELECTOR_HEAD, scope),
120 inputHead: SelectorEngine.findOne(SELECTOR_HEAD_INPUT, scope),
121 labelNumHead: SelectorEngine.findOne(SELECTOR_HEAD_LABEL, scope),
122 group: SelectorEngine.findOne(SELECTOR_TRANS_GROUP, scope),
123 }
124 }
125
126 _checkList(scopeElControl) {
127 const scopeData = this._getScopeData(scopeElControl)
128
129 if (scopeData.listChecked.length == 0) {
130 scopeData.inputHead.classList.remove(CLASS_NAME_SEMICHECKED)
131 scopeData.inputHead.checked = true
132 // controllo quale pulsante centrale disattivare
133 if (scopeElControl.classList.contains(CLASS_NAME_SOURCE)) {
134 this._disableElement(this._addBtnElement)
135 } else {
136 this._disableElement(this._invBtnElement)
137 }
138 } else {
139 if (scopeData.listChecked.length == scopeData.list.length) {
140 scopeData.inputHead.classList.remove(CLASS_NAME_SEMICHECKED)
141 scopeData.inputHead.checked = true
142 } else {
143 scopeData.inputHead.classList.add(CLASS_NAME_SEMICHECKED)
144 scopeData.inputHead.checked = false
145 }
146 // controllo quale pulsante centrale disattivare
147 if (scopeElControl.classList.contains(CLASS_NAME_SOURCE)) {
148 this._enableElement(this._addBtnElement)
149 } else {
150 this._enableElement(this._invBtnElement)
151 }
152 }
153 }
154
155 _checkListHeader(scopeElControl) {
156 const scopeData = this._getScopeData(scopeElControl)
157
158 if (scopeData.listChecked.length > 0) {
159 scopeData.list.forEach((item) => {
160 item.checked = false
161 })
162 scopeData.inputHead.classList.remove(CLASS_NAME_SEMICHECKED)
163 scopeData.inputHead.checked = false
164
165 // controllo quale pulsante centrale disattivare
166 if (scopeElControl.classList.contains(CLASS_NAME_SOURCE)) {
167 this._disableElement(this._addBtnElement)
168 } else {
169 this._disableElement(this._invBtnElement)
170 }
171 } else {
172 scopeData.list.forEach((item) => {
173 item.checked = true
174 })
175 // controllo quale pulsante centrale attivare
176 if (scopeElControl.classList.contains(CLASS_NAME_SOURCE)) {
177 this._enableElement(this._addBtnElement)
178 } else {
179 this._enableElement(this._invBtnElement)
180 }
181 }
182 }
183
184 _addItems(inverse) {
185 const sourceData = this._getScopeData(SelectorEngine.findOne(inverse ? SELECTOR_TARGET : SELECTOR_SOURCE, this._element))
186 const targetData = this._getScopeData(SelectorEngine.findOne(inverse ? SELECTOR_SOURCE : SELECTOR_TARGET, this._element))
187
188 const sourceItems = sourceData.listChecked //sourceControl.find('.transfer-group input:checked')
189 //const sourceItemsBlock = SelectorEngine.findOne('.form-check', sourceData.head) //sourceData.head('.form-check')
190 const sourceHeadInput = sourceData.inputHead //sourceControl.find('.transfer-header input')
191 const sourceHeadLabel = sourceData.labelNumHead //sourceControl.find('.transfer-header span.num')
192 const sourceItemsQty = sourceItems.length
193 const sourceTotalQty = sourceData.list.length
194
195 const targetDiv = targetData.group
196 const targetQty = targetData.list.length + sourceItemsQty
197 const targetHeadLabel = targetData.labelNumHead
198 const targetHeadInput = targetData.inputHead
199
200 // ciclo di aggiunta
201 sourceItems.forEach((item) => {
202 const wrapper = item.closest(SELECTOR_FORM_CHECK)
203 wrapper.remove()
204 targetDiv.appendChild(wrapper)
205 item.checked = false
206 })
207
208 // update label
209 const totalSource = sourceTotalQty - sourceItemsQty
210 const totalTarget = targetQty
211
212 sourceHeadLabel.innerText = totalSource
213 targetHeadLabel.innerText = totalTarget
214
215 // disattivazione header input se non ci sono più elementi
216 if (totalSource == 0) {
217 sourceHeadInput.setAttribute('disabled', true)
218 }
219 if (totalTarget > 0) {
220 targetHeadInput.removeAttribute('disabled')
221 }
222
223 // ripristino stato iniziale input header
224 sourceHeadInput.classList.remove(CLASS_NAME_SEMICHECKED)
225 sourceHeadInput.checked = false
226
227 // attivo il pulsante di reset
228 this._enableElement(this._resetBtnElement)
229 }
230
231 _resetAll() {
232 const blocks = {
233 source: this._getScopeData(SelectorEngine.findOne(SELECTOR_SOURCE, this._element)),
234 target: this._getScopeData(SelectorEngine.findOne(SELECTOR_TARGET, this._element)),
235 }
236
237 Object.keys(blocks).forEach((key) => {
238 blocks[key].list.forEach((item) => item.closest(SELECTOR_FORM_CHECK).remove())
239 })
240
241 Object.keys(blocks).forEach((key) => {
242 this._listDefault[key].forEach((item) => {
243 item.checked = false
244 blocks[key].group.appendChild(item)
245 })
246 blocks[key].labelNumHead.innerText = this._listDefault[key].length
247
248 blocks[key].inputHead.removeAttribute('disabled')
249 blocks[key].inputHead.classList.remove(CLASS_NAME_SEMICHECKED)
250 blocks[key].inputHead.checked = false
251 })
252 }
253}
254
255/**
256 * ------------------------------------------------------------------------
257 * Data Api implementation
258 * ------------------------------------------------------------------------
259 */
260
261SelectorEngine.find(SELECTOR_BLOCK).forEach((block) => {
262 Transfer.getOrCreateInstance(block)
263})
264
265export default Transfer