@itfin/components 1.3.95 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/assets/scss/_css_variables.scss +2 -2
- package/src/assets/scss/_variables.scss +18 -7
- package/src/assets/scss/components/_button.scss +10 -0
- package/src/assets/scss/components/_pagination.scss +4 -1
- package/src/assets/scss/components/_select.scss +1 -3
- package/src/assets/scss/components/_text-field.scss +17 -7
- package/src/assets/scss/main.scss +36 -2
- package/src/components/app/message.js +1 -1
- package/src/components/button/Button.vue +4 -2
- package/src/components/filter/FilterAmountRange.vue +50 -42
- package/src/components/filter/FilterBadge.vue +25 -22
- package/src/components/filter/FilterFacetsList.vue +1 -1
- package/src/components/filter/FilterPanel.vue +82 -27
- package/src/components/filter/index.stories.js +0 -2
- package/src/components/icon/Icon.vue +3 -1
- package/src/components/icon/components/fi_fingerprint.vue +4 -0
- package/src/components/icon/components/nomi-arrow-down.vue +4 -0
- package/src/components/icon/components/nomi-arrow-right-top.vue +4 -0
- package/src/components/icon/components/nomi-arrow-up.vue +4 -0
- package/src/components/icon/components/nomi-arrows.vue +7 -0
- package/src/components/icon/components/nomi-calendar-alt.vue +4 -0
- package/src/components/icon/components/nomi-calendar.vue +11 -0
- package/src/components/icon/components/nomi-card.vue +4 -0
- package/src/components/icon/components/nomi-close.vue +5 -0
- package/src/components/icon/components/nomi-eye-close.vue +4 -0
- package/src/components/icon/components/nomi-eye-open.vue +4 -0
- package/src/components/icon/components/nomi-filter.vue +4 -0
- package/src/components/icon/components/nomi-hide.vue +4 -0
- package/src/components/icon/components/nomi-money.vue +4 -0
- package/src/components/icon/components/nomi-move-left.vue +4 -0
- package/src/components/icon/components/nomi-move-right.vue +4 -0
- package/src/components/icon/components/nomi-person.vue +5 -0
- package/src/components/icon/components/nomi-pin.vue +7 -0
- package/src/components/icon/components/nomi-sort-asc.vue +7 -0
- package/src/components/icon/components/nomi-sort-desc.vue +7 -0
- package/src/components/icon/components/nomi-table-view.vue +4 -0
- package/src/components/icon/components/nomi-tag.vue +4 -0
- package/src/components/icon/components/nomi-target.vue +4 -0
- package/src/components/icon/components/nomi-text.vue +6 -0
- package/src/components/icon/components/nomi-unpin.vue +7 -0
- package/src/components/icon/convert-icons.js +11 -0
- package/src/components/icon/icons.js +302 -277
- package/src/components/icon/new-icons/arrow-down.svg +3 -0
- package/src/components/icon/new-icons/arrow-right-top.svg +3 -0
- package/src/components/icon/new-icons/arrow-up.svg +3 -0
- package/src/components/icon/new-icons/arrows.svg +6 -0
- package/src/components/icon/new-icons/calendar-alt.svg +3 -0
- package/src/components/icon/new-icons/calendar.svg +10 -0
- package/src/components/icon/new-icons/card.svg +3 -0
- package/src/components/icon/new-icons/clear.svg +3 -0
- package/src/components/icon/new-icons/close.svg +4 -0
- package/src/components/icon/new-icons/eye-close.svg +3 -0
- package/src/components/icon/new-icons/eye-open.svg +3 -0
- package/src/components/icon/new-icons/filter.svg +3 -0
- package/src/components/icon/new-icons/hide.svg +3 -0
- package/src/components/icon/new-icons/money.svg +3 -0
- package/src/components/icon/new-icons/move-left.svg +3 -0
- package/src/components/icon/new-icons/move-right.svg +3 -0
- package/src/components/icon/new-icons/person.svg +4 -0
- package/src/components/icon/new-icons/pin.svg +6 -0
- package/src/components/icon/new-icons/sort-asc.svg +6 -0
- package/src/components/icon/new-icons/sort-desc.svg +6 -0
- package/src/components/icon/new-icons/table-view.svg +3 -0
- package/src/components/icon/new-icons/tag.svg +3 -0
- package/src/components/icon/new-icons/target.svg +3 -0
- package/src/components/icon/new-icons/text.svg +5 -0
- package/src/components/icon/new-icons/unpin.svg +6 -0
- package/src/components/pagination/Pagination.vue +3 -2
- package/src/components/pagination/Pagination2.vue +176 -0
- package/src/components/panels/Panel.vue +5 -1
- package/src/components/panels/PanelItemEdit.vue +61 -0
- package/src/components/panels/PanelList.vue +2 -0
- package/src/components/select/Select.vue +1 -1
- package/src/components/sortable/draggable.js +2 -1
- package/src/components/table/Table2.vue +24 -1
- package/src/components/table/TableBody.vue +7 -2
- package/src/components/table/TableGroup.vue +8 -4
- package/src/components/table/TableHeader.vue +101 -24
- package/src/components/table/TableRows.vue +5 -3
- package/src/components/table/index.stories.js +22 -200
- package/src/components/table/table2.scss +179 -52
- package/src/components/text-field/MoneyField.vue +2 -2
- package/src/components/text-field/TextField.vue +12 -8
- package/src/components/tree/TreeEditor.vue +602 -0
- package/src/components/view/View.vue +119 -0
- package/src/components/view/index.stories.js +588 -0
- package/src/helpers/formatters.js +14 -1
- package/src/helpers/tree/cdbl.js +32 -0
- package/src/helpers/tree/cint.js +43 -0
- package/src/helpers/tree/domDrag.js +911 -0
- package/src/helpers/tree/domFinds.js +20 -0
- package/src/helpers/tree/domGetPointFromEvent.js +53 -0
- package/src/helpers/tree/domIsClientXYIn.js +65 -0
- package/src/helpers/tree/domRemove.js +50 -0
- package/src/helpers/tree/evem.js +27 -0
- package/src/helpers/tree/genID.js +56 -0
- package/src/helpers/tree/isEle.js +28 -0
- package/src/helpers/tree/isestr.js +35 -0
- package/src/helpers/tree/isint.js +40 -0
- package/src/helpers/tree/isnbr.js +24 -0
- package/src/helpers/tree/isnum.js +38 -0
- package/src/helpers/tree/ispint.js +41 -0
- package/src/helpers/tree/isstr.js +27 -0
- package/src/helpers/tree.js +30 -0
- package/src/helpers/vuetifyColor.js +136 -0
- package/src/locales/en.js +13 -0
- package/src/locales/uk.js +11 -0
- package/src/components/table/TableRow.vue +0 -221
|
@@ -0,0 +1,911 @@
|
|
|
1
|
+
import each from 'lodash/each'
|
|
2
|
+
import get from 'lodash/get'
|
|
3
|
+
import isNumber from 'lodash/isNumber'
|
|
4
|
+
import isBoolean from 'lodash/isBoolean'
|
|
5
|
+
import genID from './genID.js'
|
|
6
|
+
import isestr from './isestr.js'
|
|
7
|
+
import cint from './cint.js'
|
|
8
|
+
import evem from './evem.js'
|
|
9
|
+
import domIsClientXYIn from './domIsClientXYIn.js'
|
|
10
|
+
import domRemove from './domRemove.js'
|
|
11
|
+
import domGetPointFromEvent from './domGetPointFromEvent.js'
|
|
12
|
+
import isElement from "lodash/isElement";
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
function getEles(ele, selectors) {
|
|
16
|
+
let eles = null
|
|
17
|
+
try {
|
|
18
|
+
eles = ele.querySelectorAll(selectors)
|
|
19
|
+
}
|
|
20
|
+
catch (err) { }
|
|
21
|
+
return eles
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
function getAttr(ele, attr) {
|
|
26
|
+
let r = null
|
|
27
|
+
try {
|
|
28
|
+
r = ele.getAttribute(attr)
|
|
29
|
+
}
|
|
30
|
+
catch (err) {}
|
|
31
|
+
return r
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
// function domFindParent(ele, f) {
|
|
36
|
+
// let r = null
|
|
37
|
+
|
|
38
|
+
// //check
|
|
39
|
+
// if (!isEle(ele)) {
|
|
40
|
+
// console.log('ele is not HTMLElement')
|
|
41
|
+
// return r
|
|
42
|
+
// }
|
|
43
|
+
// if (!isfun(f)) {
|
|
44
|
+
// console.log('invalid f')
|
|
45
|
+
// return r
|
|
46
|
+
// }
|
|
47
|
+
|
|
48
|
+
// //while
|
|
49
|
+
// let parent = ele
|
|
50
|
+
// try {
|
|
51
|
+
// while (parent) {
|
|
52
|
+
|
|
53
|
+
// //check
|
|
54
|
+
// if (f(parent)) {
|
|
55
|
+
// r = parent
|
|
56
|
+
// break
|
|
57
|
+
// }
|
|
58
|
+
|
|
59
|
+
// //parentNode
|
|
60
|
+
// parent = parent.parentNode
|
|
61
|
+
|
|
62
|
+
// }
|
|
63
|
+
// }
|
|
64
|
+
// catch (err) {
|
|
65
|
+
// console.log('can not find parent in while', err)
|
|
66
|
+
// }
|
|
67
|
+
// return r
|
|
68
|
+
// }
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
function getBoudRect(ele) {
|
|
72
|
+
try {
|
|
73
|
+
return ele.getBoundingClientRect()
|
|
74
|
+
}
|
|
75
|
+
catch (err) {}
|
|
76
|
+
return null
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
function getPointRefLoc(p, ele) {
|
|
81
|
+
let rt = getBoudRect(ele)
|
|
82
|
+
if (!rt) {
|
|
83
|
+
return null
|
|
84
|
+
}
|
|
85
|
+
let x = p.clientX - rt.left //事件的clientX,Y是基於瀏覽器可視區域左上角的座標
|
|
86
|
+
let y = p.clientY - rt.top
|
|
87
|
+
let w = ele.offsetWidth
|
|
88
|
+
let h = ele.offsetHeight
|
|
89
|
+
return {
|
|
90
|
+
x, y, w, h
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
// function isInner(p, ele) {
|
|
96
|
+
// let rl = getPointRefLoc(p, ele)
|
|
97
|
+
// if (!rl) {
|
|
98
|
+
// return false
|
|
99
|
+
// }
|
|
100
|
+
// return rl.x >= 0 && rl.x <= rl.w && rl.y >= 0 && rl.y <= rl.h
|
|
101
|
+
// }
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
function getIndex(ele, attIndex) {
|
|
105
|
+
let kitem = getAttr(ele, attIndex)
|
|
106
|
+
kitem = cint(kitem)
|
|
107
|
+
return kitem
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
function dragPreview(opt = {}) {
|
|
112
|
+
let _prevName = '_prevName'
|
|
113
|
+
let _ele = null
|
|
114
|
+
let _node = null
|
|
115
|
+
let _cover = null
|
|
116
|
+
let _shell = null
|
|
117
|
+
let _container = null
|
|
118
|
+
|
|
119
|
+
//attIdentify, 產生preview會於preview內刪除, 並偵測該欄位與值是否有存在
|
|
120
|
+
let attIdentify = get(opt, 'attIdentify', null)
|
|
121
|
+
if (!isestr(attIdentify)) {
|
|
122
|
+
attIdentify = 'dragid'
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
//containerOpacity
|
|
126
|
+
let containerOpacity = get(opt, 'containerOpacity', null)
|
|
127
|
+
if (!isNumber(containerOpacity)) {
|
|
128
|
+
containerOpacity = 0.4
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
//containerBackground
|
|
132
|
+
let containerBackground = get(opt, 'containerBackground', null)
|
|
133
|
+
if (!isestr(containerBackground)) {
|
|
134
|
+
containerBackground = 'white'
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
//containerBorderWidth
|
|
138
|
+
let containerBorderWidth = get(opt, 'containerBorderWidth', null)
|
|
139
|
+
if (!isNumber(containerBorderWidth)) {
|
|
140
|
+
containerBorderWidth = 1
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
//containerBorderColor
|
|
144
|
+
let containerBorderColor = get(opt, 'containerBorderColor', null)
|
|
145
|
+
if (!isestr(containerBorderColor)) {
|
|
146
|
+
containerBorderColor = '#f26'
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function cloneNode(ele, x, y) {
|
|
150
|
+
//console.log('cloneNode')
|
|
151
|
+
|
|
152
|
+
//getBoudRect
|
|
153
|
+
let rt = getBoudRect(ele)
|
|
154
|
+
if (!rt) {
|
|
155
|
+
return
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
//備份ele
|
|
159
|
+
_ele = ele
|
|
160
|
+
|
|
161
|
+
//深複製
|
|
162
|
+
let nd = ele.cloneNode(true)
|
|
163
|
+
|
|
164
|
+
//儲存資訊
|
|
165
|
+
nd.tShiftX = x - rt.left
|
|
166
|
+
nd.tShiftY = y - rt.top
|
|
167
|
+
nd.tWidth = ele.offsetWidth
|
|
168
|
+
nd.tHeight = ele.offsetHeight
|
|
169
|
+
nd.tParent = ele.parentNode
|
|
170
|
+
nd.setAttribute(attIdentify, '') //清除attIdentify欄位, 使全域存在唯一識別元素
|
|
171
|
+
|
|
172
|
+
return nd
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function createPreview(ele, x, y) {
|
|
176
|
+
//console.log('createPreview')
|
|
177
|
+
|
|
178
|
+
function core() {
|
|
179
|
+
|
|
180
|
+
//複製ele
|
|
181
|
+
let node = cloneNode(ele, x, y)
|
|
182
|
+
|
|
183
|
+
//創建container
|
|
184
|
+
let container = document.createElement('div')
|
|
185
|
+
container.setAttribute('dragpreview', _prevName)
|
|
186
|
+
|
|
187
|
+
//創建殼層shell
|
|
188
|
+
let shell = document.createElement('div')
|
|
189
|
+
shell.style.position = 'relative'
|
|
190
|
+
|
|
191
|
+
//將複製的ele(node)塞入shell
|
|
192
|
+
shell.appendChild(node)
|
|
193
|
+
|
|
194
|
+
//創建遮罩cover
|
|
195
|
+
let cover = document.createElement('div')
|
|
196
|
+
cover.style.position = 'absolute'
|
|
197
|
+
cover.style.zIndex = 1
|
|
198
|
+
cover.style.top = 0
|
|
199
|
+
cover.style.left = 0
|
|
200
|
+
cover.style.width = '100%'
|
|
201
|
+
cover.style.height = '100%'
|
|
202
|
+
|
|
203
|
+
//將cover塞入shell
|
|
204
|
+
shell.appendChild(cover)
|
|
205
|
+
|
|
206
|
+
//將shell塞入container
|
|
207
|
+
container.appendChild(shell)
|
|
208
|
+
container.style.position = 'fixed'
|
|
209
|
+
container.style.zIndex = 100000
|
|
210
|
+
//container.style.pointerEvents = 'none' //會導致游標樣式失效
|
|
211
|
+
container.style.width = `${node.tWidth + 2 * containerBorderWidth}px`
|
|
212
|
+
container.style.height = `${node.tHeight + 2 * containerBorderWidth}px`
|
|
213
|
+
container.style.opacity = containerOpacity
|
|
214
|
+
container.style.background = containerBackground
|
|
215
|
+
container.style.border = `${containerBorderWidth}px solid ${containerBorderColor}`
|
|
216
|
+
|
|
217
|
+
//將container塞入原本ele的父層內
|
|
218
|
+
node.tParent.appendChild(container)
|
|
219
|
+
|
|
220
|
+
//儲存至全域
|
|
221
|
+
_node = node
|
|
222
|
+
_cover = cover
|
|
223
|
+
_shell = shell
|
|
224
|
+
_container = container
|
|
225
|
+
|
|
226
|
+
//updateDragPreview
|
|
227
|
+
updateDragPreview(x, y, 'createPreview')
|
|
228
|
+
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
//core, 暴力try catch攔錯, 因可能原dom例如是按鈕要自我刪除故會導致出錯
|
|
232
|
+
try {
|
|
233
|
+
core()
|
|
234
|
+
}
|
|
235
|
+
catch (err) {}
|
|
236
|
+
|
|
237
|
+
//檢查原始元素是否存在, 若例如拖曳項目是可自我刪除的按鈕, 就有可能產生preview後原始元素被刪除, 故需跟著清除preview
|
|
238
|
+
let t = setInterval(() => {
|
|
239
|
+
let dragid = getAttr(_ele, 'dragid')
|
|
240
|
+
let draggroup = getAttr(_ele, 'draggroup')
|
|
241
|
+
let ele = document.querySelector(`[dragid='${dragid}'][draggroup='${draggroup}']`)
|
|
242
|
+
if (!ele) {
|
|
243
|
+
clearInterval(t)
|
|
244
|
+
removeDragPreview()
|
|
245
|
+
}
|
|
246
|
+
}, 500)
|
|
247
|
+
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function updateDragPreview(x, y, from) {
|
|
251
|
+
//console.log('updateDragPreview', x, y, from)
|
|
252
|
+
|
|
253
|
+
//check
|
|
254
|
+
if (!_node || !_cover || !_shell || !_container) {
|
|
255
|
+
return
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
//update
|
|
259
|
+
_container.style.top = `${y - _node.tShiftY}px`
|
|
260
|
+
_container.style.left = `${x - _node.tShiftX}px`
|
|
261
|
+
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function removeDragPreview() {
|
|
265
|
+
//console.log('removeDragPreview')
|
|
266
|
+
|
|
267
|
+
//domRemove
|
|
268
|
+
domRemove(`[dragpreview=${_prevName}]`)
|
|
269
|
+
|
|
270
|
+
//clear
|
|
271
|
+
_node = null
|
|
272
|
+
_cover = null
|
|
273
|
+
_shell = null
|
|
274
|
+
_container = null
|
|
275
|
+
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
let evMM = function(e) {
|
|
279
|
+
//console.log('window mousemove', e)
|
|
280
|
+
updateDragPreview(e.clientX, e.clientY, 'window mousemove')
|
|
281
|
+
}
|
|
282
|
+
window.addEventListener('mousemove', evMM)
|
|
283
|
+
|
|
284
|
+
let evTM = function(e) {
|
|
285
|
+
//console.log('window touchmove', e)
|
|
286
|
+
let p = domGetPointFromEvent(e)
|
|
287
|
+
if (p) {
|
|
288
|
+
updateDragPreview(p.clientX, p.clientY, 'window touchmove')
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
window.addEventListener('touchmove', evTM)
|
|
292
|
+
|
|
293
|
+
function setNodeStyle(st) {
|
|
294
|
+
try {
|
|
295
|
+
each(st, (v, k) => {
|
|
296
|
+
_node.style[k] = v
|
|
297
|
+
})
|
|
298
|
+
}
|
|
299
|
+
catch (err) {}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function setCoverStyle(st) {
|
|
303
|
+
try {
|
|
304
|
+
each(st, (v, k) => {
|
|
305
|
+
_cover.style[k] = v
|
|
306
|
+
})
|
|
307
|
+
}
|
|
308
|
+
catch (err) {}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function setSellStyle(st) {
|
|
312
|
+
try {
|
|
313
|
+
each(st, (v, k) => {
|
|
314
|
+
_shell.style[k] = v
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
catch (err) {}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function setContainerStyle(st) {
|
|
321
|
+
try {
|
|
322
|
+
each(st, (v, k) => {
|
|
323
|
+
_container.style[k] = v
|
|
324
|
+
})
|
|
325
|
+
}
|
|
326
|
+
catch (err) {}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function clear() {
|
|
330
|
+
window.removeEventListener('mousemove', evMM)
|
|
331
|
+
window.removeEventListener('touchmove', evTM)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return {
|
|
335
|
+
createPreview,
|
|
336
|
+
updateDragPreview,
|
|
337
|
+
removeDragPreview,
|
|
338
|
+
setNodeStyle,
|
|
339
|
+
setCoverStyle,
|
|
340
|
+
setSellStyle,
|
|
341
|
+
setContainerStyle,
|
|
342
|
+
clear,
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* 前端監聽DOM元素陣列拖曳事件
|
|
349
|
+
*
|
|
350
|
+
* Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/domDrag.test.js Github}
|
|
351
|
+
* @memberOf wsemi
|
|
352
|
+
* @param {HTMLElement} ele 輸入元素
|
|
353
|
+
* @param {Object} [opt={}] 輸入設定物件,預設{}
|
|
354
|
+
* @param {String} [opt.active=true] 輸入是否啟用拖曳功能布林值,預設true
|
|
355
|
+
* @param {String} [opt.attIdentify='dragid'] 輸入標記元素唯一識別用字串,預設'dragid'
|
|
356
|
+
* @param {String} [opt.attIndex='dragindex'] 輸入標記元素順序指標字串,預設'dragindex'
|
|
357
|
+
* @param {String} [opt.attGroup='draggroup'] 輸入標記元素群組字串,預設'draggroup'
|
|
358
|
+
* @param {String} [opt.selectors='[dragtag]'] 輸入查詢元素用字串,主要是給draggable.js用來標記哪些元素可被拖曳之用,預設'[dragtag]'
|
|
359
|
+
* @param {Number} [opt.timeDragStartDelay=120] 輸入標記元素由點擊後延遲出現的時間數字,單位ms,預設120。使用pointerEvents會導致游標樣式失效,故延遲顯示可用來讓點擊事件穿透
|
|
360
|
+
* @param {Number} [opt.previewOpacity=0.4] 輸入標記元素透明度數字,預設0.4
|
|
361
|
+
* @param {String} [opt.previewBackground='white'] 輸入標記元素背景顏色字串,預設'white'
|
|
362
|
+
* @param {Number} [opt.previewBorderWidth=1] 輸入標記元素邊框寬度數字,預設1
|
|
363
|
+
* @param {String} [opt.previewBorderColor='#f26'] 輸入標記元素邊框顏色字串,預設'#f26'
|
|
364
|
+
* @returns {Object} 回傳物件,可使用on與clear函數,on可監聽change、start、move、enter、leave、drop事件,clear為釋放監聽
|
|
365
|
+
* @example
|
|
366
|
+
* need test in browser
|
|
367
|
+
*
|
|
368
|
+
* //監聽dom
|
|
369
|
+
* let dd = domDrag(document.querySelector('#id'), { attIndex: 'dragindex', selectors: '[dragtag]' })
|
|
370
|
+
*
|
|
371
|
+
* //change
|
|
372
|
+
* dd.on('change', (msg) => {
|
|
373
|
+
* console.log('change', msg)
|
|
374
|
+
* })
|
|
375
|
+
* dd.on('start', (msg) => {
|
|
376
|
+
* console.log('start', msg)
|
|
377
|
+
* })
|
|
378
|
+
* dd.on('move', (msg) => {
|
|
379
|
+
* console.log('move', msg)
|
|
380
|
+
* })
|
|
381
|
+
* dd.on('enter', (msg) => {
|
|
382
|
+
* console.log('enter', msg)
|
|
383
|
+
* })
|
|
384
|
+
* dd.on('leave', (msg) => {
|
|
385
|
+
* console.log('leave', msg)
|
|
386
|
+
* })
|
|
387
|
+
* dd.on('drop', (msg) => {
|
|
388
|
+
* console.log('drop', msg)
|
|
389
|
+
* })
|
|
390
|
+
*
|
|
391
|
+
* //釋放監聽
|
|
392
|
+
* dd.clear()
|
|
393
|
+
*
|
|
394
|
+
*/
|
|
395
|
+
function domDrag(ele, opt = {}) {
|
|
396
|
+
let _startInd = null
|
|
397
|
+
let _startEle = null
|
|
398
|
+
let _endInd = null
|
|
399
|
+
let _endEle = null
|
|
400
|
+
let _events = []
|
|
401
|
+
let _dragStartPoint = null
|
|
402
|
+
let _createdPreview = false
|
|
403
|
+
|
|
404
|
+
//check
|
|
405
|
+
if (!isElement(ele)) {
|
|
406
|
+
console.log('ele is not HTMLElement', ele)
|
|
407
|
+
return
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
//attIdentify
|
|
411
|
+
let attIdentify = get(opt, 'attIdentify', null)
|
|
412
|
+
if (!isestr(attIdentify)) {
|
|
413
|
+
attIdentify = 'dragid'
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
//attIndex
|
|
417
|
+
let attIndex = get(opt, 'attIndex', null)
|
|
418
|
+
if (!isestr(attIndex)) {
|
|
419
|
+
attIndex = 'dragindex'
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
//attGroup
|
|
423
|
+
let attGroup = get(opt, 'attGroup', null)
|
|
424
|
+
if (!isestr(attGroup)) {
|
|
425
|
+
attGroup = 'draggroup'
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
//selectors
|
|
429
|
+
let selectors = get(opt, 'selectors', null)
|
|
430
|
+
if (!isestr(selectors)) {
|
|
431
|
+
selectors = '[dragtag]'
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
//active
|
|
435
|
+
let active = get(opt, 'active', null)
|
|
436
|
+
if (!isBoolean(active)) {
|
|
437
|
+
active = true
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
//timeDragStartDelay
|
|
441
|
+
let timeDragStartDelay = get(opt, 'timeDragStartDelay', null)
|
|
442
|
+
if (!isNumber(timeDragStartDelay)) {
|
|
443
|
+
timeDragStartDelay = 120
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
//previewOpacity
|
|
447
|
+
let previewOpacity = get(opt, 'previewOpacity', null)
|
|
448
|
+
|
|
449
|
+
//previewBackground
|
|
450
|
+
let previewBackground = get(opt, 'previewBackground', null)
|
|
451
|
+
|
|
452
|
+
//previewBorderWidth
|
|
453
|
+
let previewBorderWidth = get(opt, 'previewBorderWidth', null)
|
|
454
|
+
|
|
455
|
+
//previewBorderColor
|
|
456
|
+
let previewBorderColor = get(opt, 'previewBorderColor', null)
|
|
457
|
+
|
|
458
|
+
//dragPreview
|
|
459
|
+
let pv = dragPreview({
|
|
460
|
+
attIdentify,
|
|
461
|
+
containerOpacity: previewOpacity,
|
|
462
|
+
containerBackground: previewBackground,
|
|
463
|
+
containerBorderWidth: previewBorderWidth,
|
|
464
|
+
containerBorderColor: previewBorderColor,
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
//eles
|
|
468
|
+
let eles = getEles(ele, selectors)
|
|
469
|
+
if (!eles) {
|
|
470
|
+
console.log('初始化時無法取得拖曳元素')
|
|
471
|
+
return
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
//gid
|
|
475
|
+
let gid = 'dg' + genID(8)
|
|
476
|
+
|
|
477
|
+
//setAttrs
|
|
478
|
+
function setAttrs() {
|
|
479
|
+
each(eles, (ele, k) => {
|
|
480
|
+
ele.setAttribute(attGroup, gid)
|
|
481
|
+
ele.setAttribute(attIdentify, `dg-${genID(8)}`)
|
|
482
|
+
})
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
//bindEvents
|
|
486
|
+
function bindEvents() {
|
|
487
|
+
let f
|
|
488
|
+
let name
|
|
489
|
+
|
|
490
|
+
name = 'mousemove'
|
|
491
|
+
f = function(e) {
|
|
492
|
+
dragMove(e, 'mousemove')
|
|
493
|
+
}
|
|
494
|
+
window.addEventListener(name, f)
|
|
495
|
+
_events.push({ ele: window, name, f })
|
|
496
|
+
|
|
497
|
+
name = 'mouseup'
|
|
498
|
+
f = function(e) {
|
|
499
|
+
dragDrop(e, 'mouseup')
|
|
500
|
+
}
|
|
501
|
+
window.addEventListener(name, f)
|
|
502
|
+
_events.push({ ele: window, name, f })
|
|
503
|
+
|
|
504
|
+
name = 'touchmove'
|
|
505
|
+
f = function(e) {
|
|
506
|
+
dragMove(e, 'touchmove')
|
|
507
|
+
}
|
|
508
|
+
window.addEventListener(name, f)
|
|
509
|
+
_events.push({ ele: window, name, f })
|
|
510
|
+
|
|
511
|
+
name = 'touchend'
|
|
512
|
+
f = function(e) {
|
|
513
|
+
dragDrop(e, 'touchend')
|
|
514
|
+
}
|
|
515
|
+
window.addEventListener(name, f)
|
|
516
|
+
_events.push({ ele: window, name, f })
|
|
517
|
+
|
|
518
|
+
each(eles, (ele, k) => { //k不可信, 而eles綁定成為元素需自動更新, 因例如用vue由數據順序產生元素, 當拖曳完的eles將不會是原始元素順序, 但eles仍為原始數據順序
|
|
519
|
+
let dragEl = ele;
|
|
520
|
+
if (opt.handle) {
|
|
521
|
+
dragEl = ele.querySelector(opt.handle);
|
|
522
|
+
}
|
|
523
|
+
name = 'mousedown'
|
|
524
|
+
f = function(e) {
|
|
525
|
+
dragStart(e, ele, 'mousedown')
|
|
526
|
+
}
|
|
527
|
+
dragEl.addEventListener(name, f, false)
|
|
528
|
+
_events.push({ ele, name, f })
|
|
529
|
+
|
|
530
|
+
name = 'touchstart'
|
|
531
|
+
f = function(e) {
|
|
532
|
+
dragStart(e, ele, 'touchstart')
|
|
533
|
+
}
|
|
534
|
+
dragEl.addEventListener(name, f, false)
|
|
535
|
+
_events.push({ ele, name, f })
|
|
536
|
+
|
|
537
|
+
name = 'touchmove'
|
|
538
|
+
f = function(e) {
|
|
539
|
+
//domCancelEvent(e) //不能使用domCancelEvent, 因其內使用stopPropagation會連window的touchmove無法收到訊息
|
|
540
|
+
if (e.cancelable) { //window捲動中時事件為禁止取消(cancelable=false)狀態
|
|
541
|
+
e.preventDefault() //必要, 需由元素touchmove事件阻止預設拖曳行為, 否則會變成捲動螢幕, 此外由window的touchmove事件來阻止會失效
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
dragEl.addEventListener(name, f, false)
|
|
545
|
+
_events.push({ ele, name, f })
|
|
546
|
+
|
|
547
|
+
})
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
//unbindEvents
|
|
551
|
+
function unbindEvents() {
|
|
552
|
+
each(_events, ({ ele, name, f }) => {
|
|
553
|
+
ele.removeEventListener(name, f)
|
|
554
|
+
})
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function safeCreatePreview() {
|
|
558
|
+
if (_startEle === null) {
|
|
559
|
+
return
|
|
560
|
+
}
|
|
561
|
+
if (!_createdPreview) {
|
|
562
|
+
let p = _dragStartPoint
|
|
563
|
+
pv.createPreview(_startEle, p.clientX, p.clientY)
|
|
564
|
+
_createdPreview = true
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
function findEleFromEvent(e) {
|
|
570
|
+
let eleIn = null
|
|
571
|
+
|
|
572
|
+
//p
|
|
573
|
+
let p = domGetPointFromEvent(e)
|
|
574
|
+
if (!p) {
|
|
575
|
+
return eleIn
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
//each
|
|
579
|
+
for (let i = 0; i < eles.length; i++) {
|
|
580
|
+
let ele = eles[i]
|
|
581
|
+
let b = domIsClientXYIn(p.clientX, p.clientY, ele)
|
|
582
|
+
if (b) {
|
|
583
|
+
eleIn = ele
|
|
584
|
+
break
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
return eleIn
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
function setActive(bol) {
|
|
592
|
+
active = bol
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
function dragStart(e, ele, from) {
|
|
596
|
+
//console.log('dragStart', e, ele, from)
|
|
597
|
+
|
|
598
|
+
//check
|
|
599
|
+
if (!active) {
|
|
600
|
+
return
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
//getIndex
|
|
604
|
+
let kitem = getIndex(ele, attIndex)
|
|
605
|
+
|
|
606
|
+
//check
|
|
607
|
+
if (kitem === null) { //不能用!kitem判斷, 因kitem可能為0
|
|
608
|
+
//console.log('dragStart: 無法取得kitem')
|
|
609
|
+
return
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
_startInd = kitem
|
|
613
|
+
_startEle = ele
|
|
614
|
+
|
|
615
|
+
//emit
|
|
616
|
+
let msg = {
|
|
617
|
+
event: e,
|
|
618
|
+
startInd: _startInd,
|
|
619
|
+
startEle: _startEle,
|
|
620
|
+
}
|
|
621
|
+
ev.emit('change', { mode: 'start', ...msg })
|
|
622
|
+
ev.emit('start', msg)
|
|
623
|
+
|
|
624
|
+
//p
|
|
625
|
+
let p = domGetPointFromEvent(e)
|
|
626
|
+
if (!p) {
|
|
627
|
+
return
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
//save _dragStartPoint
|
|
631
|
+
_dragStartPoint = p
|
|
632
|
+
|
|
633
|
+
//setTimeout, preview不能太快出現導致原本元素例如click事件失效
|
|
634
|
+
setTimeout(() => {
|
|
635
|
+
|
|
636
|
+
//check, 若觸發例如dragDrop事件因已清除故會無_startInd
|
|
637
|
+
if (_startInd === null) {
|
|
638
|
+
return
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
//safeCreatePreview
|
|
642
|
+
safeCreatePreview()
|
|
643
|
+
|
|
644
|
+
//setCoverStyle, 必要, 快速拖曳但只在原拖曳項目時就需要能更改滑鼠游標
|
|
645
|
+
pv.setCoverStyle({ cursor: 'no-drop' })
|
|
646
|
+
|
|
647
|
+
}, timeDragStartDelay)
|
|
648
|
+
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
function dragMove(e, from) {
|
|
652
|
+
//console.log('dragMove', e, from)
|
|
653
|
+
|
|
654
|
+
//check
|
|
655
|
+
if (!active) {
|
|
656
|
+
return
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
//check
|
|
660
|
+
if (_startInd === null) {
|
|
661
|
+
return
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
//p
|
|
665
|
+
let p = domGetPointFromEvent(e)
|
|
666
|
+
if (!p) {
|
|
667
|
+
return
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
function emitEnter(endInd, endEle) {
|
|
671
|
+
_endInd = endInd
|
|
672
|
+
_endEle = endEle
|
|
673
|
+
|
|
674
|
+
//emit
|
|
675
|
+
let msg = {
|
|
676
|
+
event: e,
|
|
677
|
+
startInd: _startInd,
|
|
678
|
+
startEle: _startEle,
|
|
679
|
+
endInd: _endInd,
|
|
680
|
+
endEle: _endEle,
|
|
681
|
+
}
|
|
682
|
+
ev.emit('change', { mode: 'enter', ...msg })
|
|
683
|
+
ev.emit('enter', msg)
|
|
684
|
+
|
|
685
|
+
//safeCreatePreview
|
|
686
|
+
safeCreatePreview()
|
|
687
|
+
|
|
688
|
+
//setCoverStyle
|
|
689
|
+
pv.setCoverStyle({ cursor: 'pointer' })
|
|
690
|
+
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
function emitLeave() {
|
|
694
|
+
|
|
695
|
+
//emit
|
|
696
|
+
let msg = {
|
|
697
|
+
event: e,
|
|
698
|
+
startInd: _startInd,
|
|
699
|
+
startEle: _startEle,
|
|
700
|
+
endInd: _endInd,
|
|
701
|
+
endEle: _endEle,
|
|
702
|
+
}
|
|
703
|
+
ev.emit('change', { mode: 'leave', ...msg })
|
|
704
|
+
ev.emit('leave', msg)
|
|
705
|
+
|
|
706
|
+
//clear, 要放在emit之後才能清除
|
|
707
|
+
_endInd = null
|
|
708
|
+
_endEle = null
|
|
709
|
+
|
|
710
|
+
//setCoverStyle
|
|
711
|
+
pv.setCoverStyle({ cursor: 'no-drop' })
|
|
712
|
+
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
function emitMove(rl, rx, ry) {
|
|
716
|
+
|
|
717
|
+
//emit
|
|
718
|
+
let msg = {
|
|
719
|
+
event: e,
|
|
720
|
+
startInd: _startInd,
|
|
721
|
+
startEle: _startEle,
|
|
722
|
+
endInd: _endInd,
|
|
723
|
+
endEle: _endEle,
|
|
724
|
+
...rl,
|
|
725
|
+
rx,
|
|
726
|
+
ry,
|
|
727
|
+
}
|
|
728
|
+
ev.emit('change', { mode: 'move', ...msg })
|
|
729
|
+
ev.emit('move', msg)
|
|
730
|
+
|
|
731
|
+
//safeCreatePreview
|
|
732
|
+
safeCreatePreview()
|
|
733
|
+
|
|
734
|
+
//setCoverStyle, 必要, 因現在dragStart為延遲觸發會setCoverStyle為no-drop, 當使用者拖曳過快, 就會先觸發完enter內的setCoverStyle, 才換dragStart內延遲觸發setCoverStyle導致游標有誤
|
|
735
|
+
pv.setCoverStyle({ cursor: 'pointer' })
|
|
736
|
+
|
|
737
|
+
//updateDragPreview
|
|
738
|
+
pv.updateDragPreview(p.clientX, p.clientY, 'emitMove')
|
|
739
|
+
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
//eleIn
|
|
743
|
+
let eleIn = findEleFromEvent(e)
|
|
744
|
+
|
|
745
|
+
//check, 滑鼠所在處的可被拖曳元素
|
|
746
|
+
if (!eleIn) {
|
|
747
|
+
|
|
748
|
+
//check
|
|
749
|
+
if (_endInd !== null) {
|
|
750
|
+
|
|
751
|
+
//emitLeave
|
|
752
|
+
emitLeave()
|
|
753
|
+
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
return
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
//getIndex
|
|
760
|
+
let kitem = getIndex(eleIn, attIndex)
|
|
761
|
+
|
|
762
|
+
//check
|
|
763
|
+
if (kitem === null) { //不能用!kitem判斷, 因kitem可能為0
|
|
764
|
+
//console.log('dragMove: 無法取得kitem')
|
|
765
|
+
return
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
//check
|
|
769
|
+
if (kitem === _startInd) { //拖曳至原拖曳項目
|
|
770
|
+
|
|
771
|
+
//由其他拖曳項目拖曳至原拖曳項目內, 需要觸發leave事件
|
|
772
|
+
if (_endInd !== null) {
|
|
773
|
+
|
|
774
|
+
//emitLeave
|
|
775
|
+
emitLeave()
|
|
776
|
+
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
return
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
//check
|
|
783
|
+
if (kitem !== _endInd) { //拖曳至不同於上一個拖曳項目
|
|
784
|
+
//enter
|
|
785
|
+
|
|
786
|
+
//於其他拖曳項目之間拖曳, 且非拖曳至原拖曳項目, 故也需要觸發leave事件
|
|
787
|
+
if (_endInd !== null) {
|
|
788
|
+
|
|
789
|
+
//emitLeave
|
|
790
|
+
emitLeave()
|
|
791
|
+
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
//emitEnter
|
|
795
|
+
emitEnter(kitem, eleIn)
|
|
796
|
+
|
|
797
|
+
}
|
|
798
|
+
else { //move, 於上一個拖曳項目內拖曳
|
|
799
|
+
|
|
800
|
+
//rl
|
|
801
|
+
let rl = getPointRefLoc(p, eleIn)
|
|
802
|
+
|
|
803
|
+
//rx, ry
|
|
804
|
+
let rx = 0
|
|
805
|
+
if (rl.w > 0) {
|
|
806
|
+
rx = rl.x / rl.w
|
|
807
|
+
}
|
|
808
|
+
let ry = 0
|
|
809
|
+
if (rl.h > 0) {
|
|
810
|
+
ry = rl.y / rl.h
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
if (rx >= 0 && rx <= 1 && ry >= 0 && ry <= 1) {
|
|
814
|
+
|
|
815
|
+
//emitMove
|
|
816
|
+
emitMove(rl, rx, ry)
|
|
817
|
+
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
function dragDrop(e, from) {
|
|
825
|
+
//console.log('dragDrop', e, from)
|
|
826
|
+
|
|
827
|
+
//check
|
|
828
|
+
if (!active) {
|
|
829
|
+
return
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
//removeDragPreview
|
|
833
|
+
pv.removeDragPreview()
|
|
834
|
+
_createdPreview = false
|
|
835
|
+
|
|
836
|
+
//check
|
|
837
|
+
if (_startInd === null) {
|
|
838
|
+
//console.log('dragDrop: 無_startInd')
|
|
839
|
+
return
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function emitDrop(endInd, endEle) {
|
|
843
|
+
_endInd = endInd
|
|
844
|
+
_endEle = endEle
|
|
845
|
+
|
|
846
|
+
//emit
|
|
847
|
+
let msg = {
|
|
848
|
+
event: e,
|
|
849
|
+
startInd: _startInd,
|
|
850
|
+
startEle: _startEle,
|
|
851
|
+
endInd: _endInd,
|
|
852
|
+
endEle: _endEle,
|
|
853
|
+
}
|
|
854
|
+
ev.emit('change', { mode: 'drop', ...msg })
|
|
855
|
+
ev.emit('drop', msg)
|
|
856
|
+
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
//eleIn
|
|
860
|
+
let eleIn = findEleFromEvent(e)
|
|
861
|
+
|
|
862
|
+
//check, 釋放時不在拖曳元素內故跳出
|
|
863
|
+
if (!eleIn) {
|
|
864
|
+
//console.log('dragDrop: 釋放時不在拖曳元素內')
|
|
865
|
+
_startInd = null
|
|
866
|
+
_startEle = null
|
|
867
|
+
_endInd = null
|
|
868
|
+
_endEle = null
|
|
869
|
+
return
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
//getIndex
|
|
873
|
+
let kitem = getIndex(eleIn, attIndex)
|
|
874
|
+
|
|
875
|
+
//check
|
|
876
|
+
if (kitem === null) { //不能用!kitem判斷, 因kitem可能為0
|
|
877
|
+
//console.log('dragDrop: 無法取得kitem')
|
|
878
|
+
return
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
//emitDrop, 若拖曳至原拖曳項目上也要能觸發, 否則外部收不到滑鼠放掉訊息, 僅收得到拖曳至非拖曳項目的leave事件
|
|
882
|
+
emitDrop(kitem, eleIn)
|
|
883
|
+
|
|
884
|
+
//clear, 要放在emit之後才能清除
|
|
885
|
+
_startInd = null
|
|
886
|
+
_startEle = null
|
|
887
|
+
_endInd = null
|
|
888
|
+
_endEle = null
|
|
889
|
+
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
//ev
|
|
893
|
+
let ev = evem()
|
|
894
|
+
|
|
895
|
+
//bindEvents, setAttrs
|
|
896
|
+
bindEvents()
|
|
897
|
+
setAttrs()
|
|
898
|
+
|
|
899
|
+
//save
|
|
900
|
+
ev.gid = gid
|
|
901
|
+
ev.setActive = setActive
|
|
902
|
+
ev.clear = function() {
|
|
903
|
+
unbindEvents()
|
|
904
|
+
pv.clear()
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
return ev
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
export default domDrag
|