@bildvitta/quasar-ui-asteroid 3.17.0-beta.12 → 3.17.0-beta.14
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 +2 -2
- package/src/components/board-generator/QasBoardGenerator.vue +407 -40
- package/src/components/board-generator/QasBoardGenerator.yml +53 -12
- package/src/components/card/QasCard.vue +2 -2
- package/src/components/grabbable/QasGrabbable.vue +14 -6
- package/src/components/grabbable/QasGrabbable.yml +4 -0
- package/src/components/header/QasHeader.vue +5 -5
- package/src/components/infinite-scroll/QasInfiniteScroll.vue +16 -17
- package/src/components/infinite-scroll/QasInfiniteScroll.yml +7 -0
- package/src/components/list-view/QasListView.vue +13 -1
- package/src/components/list-view/QasListView.yml +9 -0
- package/src/components/stepper-form-view/QasStepperFormView.yml +1 -1
- package/src/helpers/set-scroll-on-grab.js +9 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bildvitta/quasar-ui-asteroid",
|
|
3
3
|
"description": "Asteroid",
|
|
4
|
-
"version": "3.17.0-beta.
|
|
4
|
+
"version": "3.17.0-beta.14",
|
|
5
5
|
"author": "Bild & Vitta <systemteam@bild.com.br>",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"main": "dist/asteroid.cjs.min.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"lodash-es": "^4.17.21",
|
|
55
55
|
"pica": "^9.0.1",
|
|
56
56
|
"signature_pad": "^4.1.5",
|
|
57
|
-
"sortablejs": "^1.15.
|
|
57
|
+
"sortablejs": "^1.15.3"
|
|
58
58
|
},
|
|
59
59
|
"browserslist": [
|
|
60
60
|
"defaults"
|
|
@@ -1,39 +1,40 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<qas-grabbable class="qas-board-generator"
|
|
2
|
+
<qas-grabbable class="qas-board-generator" v-bind="grabbableProps">
|
|
3
3
|
<div class="no-wrap q-col-gutter-sm q-px-xl row">
|
|
4
4
|
<div v-for="(header, index) in headers" :key="index" class="q-mr-sm">
|
|
5
|
-
<qas-box class="q-mb-md">
|
|
6
|
-
<slot :fields="getFieldsByHeader(header)" :header="header" name="header-column" />
|
|
5
|
+
<qas-box class="q-mb-md" v-bind="headerBoxProps">
|
|
6
|
+
<slot :fields="getFieldsByHeader(header)" :header="header" :index="index" name="header-column" />
|
|
7
7
|
</qas-box>
|
|
8
8
|
|
|
9
|
-
<div ref="columnContainer" class="qas-board-generator__column secondary-scroll" :style="containerStyle">
|
|
10
|
-
<
|
|
9
|
+
<div ref="columnContainer" class="qas-board-generator__column secondary-scroll" :data-header-key="getKeyByHeader(header)" :style="containerStyle">
|
|
10
|
+
<div v-for="item in getItemsByHeader(header)" :id="item[props.itemIdKey]" :key="item[props.itemIdKey]" class="qas-board-generator__item">
|
|
11
|
+
<slot :column-index="index" :fields="getFieldsByHeader(header)" :item="item" name="column-item" />
|
|
12
|
+
</div>
|
|
11
13
|
|
|
12
|
-
<div class="full-width justify-center
|
|
14
|
+
<div class="full-width justify-center row">
|
|
13
15
|
<qas-btn v-if="hasSeeMore(header)" icon="sym_r_add" label="Ver mais" :use-label-on-small-screen="false" variant="tertiary" @click="fetchColumn(header)" />
|
|
14
16
|
|
|
15
|
-
<q-spinner v-if="columnsLoading[getKeyByHeader(header)]" color="grey-4" size="3em" />
|
|
16
|
-
|
|
17
|
-
<qas-empty-result-text v-if="hasEmptyResultText(header)" />
|
|
17
|
+
<q-spinner v-if="columnsLoading[getKeyByHeader(header)]" class="q-mb-md" color="grey-4" size="3em" />
|
|
18
18
|
</div>
|
|
19
|
+
|
|
20
|
+
<qas-empty-result-text v-if="hasEmptyResultText(header)" />
|
|
19
21
|
</div>
|
|
20
22
|
</div>
|
|
21
23
|
</div>
|
|
24
|
+
|
|
25
|
+
<qas-dialog v-model="showConfirmDialog" v-bind="defaultConfirmDialogProps" />
|
|
22
26
|
</qas-grabbable>
|
|
23
27
|
</template>
|
|
24
28
|
|
|
25
29
|
<script setup>
|
|
26
|
-
import
|
|
27
|
-
import promiseHandler from '../../helpers/promise-handler'
|
|
30
|
+
import QasDialog from '../dialog/QasDialog.vue'
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
import { ref, watch, computed, onUnmounted, markRaw, inject, onMounted } from 'vue'
|
|
33
|
+
import promiseHandler from '../../helpers/promise-handler'
|
|
30
34
|
|
|
31
|
-
|
|
32
|
-
const columnsPagination = ref({})
|
|
33
|
-
const columnsLoading = ref({})
|
|
34
|
-
const columnsFieldsModel = ref({})
|
|
35
|
+
import Sortable from 'sortablejs'
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
defineOptions({ name: 'QasBoardGenerator' })
|
|
37
38
|
|
|
38
39
|
const props = defineProps({
|
|
39
40
|
headers: {
|
|
@@ -46,6 +47,11 @@ const props = defineProps({
|
|
|
46
47
|
default: () => ({})
|
|
47
48
|
},
|
|
48
49
|
|
|
50
|
+
headerBoxProps: {
|
|
51
|
+
type: Object,
|
|
52
|
+
default: () => ({})
|
|
53
|
+
},
|
|
54
|
+
|
|
49
55
|
columnIdKey: {
|
|
50
56
|
type: String,
|
|
51
57
|
required: true
|
|
@@ -61,11 +67,21 @@ const props = defineProps({
|
|
|
61
67
|
required: true
|
|
62
68
|
},
|
|
63
69
|
|
|
70
|
+
confirmDialogProps: {
|
|
71
|
+
type: Object,
|
|
72
|
+
default: () => ({})
|
|
73
|
+
},
|
|
74
|
+
|
|
64
75
|
height: {
|
|
65
76
|
type: String,
|
|
66
77
|
default: ''
|
|
67
78
|
},
|
|
68
79
|
|
|
80
|
+
itemIdKey: {
|
|
81
|
+
type: String,
|
|
82
|
+
default: ''
|
|
83
|
+
},
|
|
84
|
+
|
|
69
85
|
limitPerColumn: {
|
|
70
86
|
type: Number,
|
|
71
87
|
default: 12
|
|
@@ -76,11 +92,34 @@ const props = defineProps({
|
|
|
76
92
|
default: '300px'
|
|
77
93
|
},
|
|
78
94
|
|
|
95
|
+
sortableConfig: {
|
|
96
|
+
type: Object,
|
|
97
|
+
default: () => ({})
|
|
98
|
+
},
|
|
99
|
+
|
|
79
100
|
useMarkRaw: {
|
|
80
101
|
type: Boolean,
|
|
81
102
|
default: true
|
|
82
103
|
},
|
|
83
104
|
|
|
105
|
+
useDragAndDropX: {
|
|
106
|
+
type: Boolean
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
useDragAndDropY: {
|
|
110
|
+
type: Boolean
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
updatePositionUrl: {
|
|
114
|
+
type: String,
|
|
115
|
+
default: ''
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
updatePositionParams: {
|
|
119
|
+
type: Object,
|
|
120
|
+
default: () => ({})
|
|
121
|
+
},
|
|
122
|
+
|
|
84
123
|
lazyLoadingFieldsKeys: {
|
|
85
124
|
type: Array,
|
|
86
125
|
default: () => []
|
|
@@ -92,28 +131,93 @@ const emit = defineEmits([
|
|
|
92
131
|
'fetch-column-success',
|
|
93
132
|
'fetch-column-error',
|
|
94
133
|
'fetch-columns-success',
|
|
95
|
-
'fetch-columns-error'
|
|
134
|
+
'fetch-columns-error',
|
|
135
|
+
'update-success'
|
|
96
136
|
])
|
|
97
137
|
|
|
138
|
+
defineExpose({ fetchColumns, fetchColumn, reset })
|
|
139
|
+
|
|
140
|
+
// Inject
|
|
141
|
+
const axios = inject('axios')
|
|
142
|
+
|
|
143
|
+
const isFetchSuccessHeader = inject('isFetchListSucceeded', false)
|
|
144
|
+
|
|
145
|
+
const isInsideListView = inject('isListView', false)
|
|
146
|
+
|
|
147
|
+
// Refs
|
|
148
|
+
const columnContainer = ref(null)
|
|
149
|
+
const columnsPagination = ref({})
|
|
150
|
+
const columnsLoading = ref({})
|
|
151
|
+
const columnsFieldsModel = ref({})
|
|
152
|
+
const showConfirmDialog = ref(false)
|
|
153
|
+
const isDragging = ref(false)
|
|
154
|
+
const isLoadingUpdatePosition = ref(false)
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Instâncias do sortable, que são utilizadas para realizar o destroy ao sair da página
|
|
158
|
+
*/
|
|
159
|
+
const sortableInstances = ref([])
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Callbacks que recebe o event de movimentação
|
|
163
|
+
*/
|
|
164
|
+
const onCancelDrop = ref(() => {})
|
|
165
|
+
const onConfirmDrop = ref(() => {})
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Variável auxiliar que controla quando estou atualizando o header em caso de drag and drop
|
|
169
|
+
*/
|
|
170
|
+
const isUpdatingPosition = ref(false)
|
|
171
|
+
|
|
172
|
+
// Consts
|
|
173
|
+
const hasDragAndDrop = !!props.useDragAndDropX || !!props.useDragAndDropY
|
|
174
|
+
|
|
175
|
+
const grabbableProps = {
|
|
176
|
+
useScrollBar: true,
|
|
177
|
+
|
|
178
|
+
...(hasDragAndDrop && {
|
|
179
|
+
cancelMouseDownTarget: 'qas-board-generator__item'
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Watchers
|
|
184
|
+
watch(
|
|
185
|
+
() => isFetchSuccessHeader.value,
|
|
186
|
+
value => {
|
|
187
|
+
/**
|
|
188
|
+
* isFetchSuccessHeader é uma variavel que pego do listView por inject/provide, no qual caso eu faça request do header e dê sucesso, eu chamo as demais funções.
|
|
189
|
+
* Valido se não houve sucesso na requisição do header ou se não é uma atualização de posição, para assim não bater novamente nas colunas apenas no header.
|
|
190
|
+
*/
|
|
191
|
+
if (!value || isUpdatingPosition.value) return
|
|
192
|
+
|
|
193
|
+
fetchColumnsValues()
|
|
194
|
+
}
|
|
195
|
+
)
|
|
196
|
+
|
|
98
197
|
watch(
|
|
99
198
|
() => props.headers,
|
|
100
199
|
() => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
fetchColumns()
|
|
200
|
+
if (isUpdatingPosition.value) return
|
|
201
|
+
|
|
202
|
+
isUpdatingPosition.value = false
|
|
105
203
|
}
|
|
106
204
|
)
|
|
107
205
|
|
|
108
206
|
watch(columnContainer, setColumnHeightContainer)
|
|
109
207
|
|
|
208
|
+
// Lifecycles
|
|
110
209
|
onMounted(() => {
|
|
111
|
-
|
|
112
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Caso eu use o listView (valor pego por provide), a request é feito pelo watch quando se ocorre o sucesso do `fetchList`
|
|
212
|
+
*/
|
|
213
|
+
if (isInsideListView) return
|
|
214
|
+
|
|
215
|
+
fetchColumnsValues()
|
|
113
216
|
})
|
|
114
217
|
|
|
115
|
-
|
|
218
|
+
onUnmounted(destroySortable)
|
|
116
219
|
|
|
220
|
+
// Computeds
|
|
117
221
|
const columnsResultsModel = computed({
|
|
118
222
|
get () {
|
|
119
223
|
return props.results
|
|
@@ -124,10 +228,32 @@ const columnsResultsModel = computed({
|
|
|
124
228
|
}
|
|
125
229
|
})
|
|
126
230
|
|
|
127
|
-
const hasColumnsLength = computed(() => Object.keys(columnsResultsModel.value).length)
|
|
231
|
+
const hasColumnsLength = computed(() => !!Object.keys(columnsResultsModel.value).length)
|
|
128
232
|
|
|
129
233
|
const containerStyle = computed(() => `width: ${props.columnWidth};`)
|
|
130
234
|
|
|
235
|
+
const hasConfirmDialogProps = computed(() => !!Object.keys(props.confirmDialogProps).length)
|
|
236
|
+
|
|
237
|
+
const defaultConfirmDialogProps = computed(() => {
|
|
238
|
+
const defaultProps = {
|
|
239
|
+
ok: {
|
|
240
|
+
label: 'Confirmar',
|
|
241
|
+
onClick: onConfirmDrop.value,
|
|
242
|
+
loading: isLoadingUpdatePosition.value
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
cancel: {
|
|
246
|
+
onClick: onCancelDrop.value
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return {
|
|
251
|
+
...props.confirmDialogProps,
|
|
252
|
+
...defaultProps
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
// functions
|
|
131
257
|
/*
|
|
132
258
|
* Setar o tamanho do container do board, onde deverá ser a altura passada via prop, ou o default será ocupar o maximo
|
|
133
259
|
* de espaço que ele conseguir considerando a altura do container em relação ao topo.
|
|
@@ -157,6 +283,8 @@ async function fetchColumns () {
|
|
|
157
283
|
}
|
|
158
284
|
|
|
159
285
|
emit('fetch-columns-success')
|
|
286
|
+
|
|
287
|
+
if (hasDragAndDrop) handleElementsList()
|
|
160
288
|
}
|
|
161
289
|
|
|
162
290
|
/*
|
|
@@ -189,22 +317,25 @@ async function fetchColumn (header) {
|
|
|
189
317
|
throw error
|
|
190
318
|
}
|
|
191
319
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
* {
|
|
196
|
-
* '2024-02-15': [...],
|
|
197
|
-
* '2024-02-16': [...]
|
|
198
|
-
* }
|
|
199
|
-
*
|
|
200
|
-
* onde cada item do objeto é uma coluna no board. O mesmo vale para "columnsFieldsModel", "columnsLoading" e
|
|
201
|
-
* "columnPagination", organizando os fields, loadings e o controle de paginação por chave identificadora do header.
|
|
202
|
-
*/
|
|
320
|
+
const newValues = response.data?.results || []
|
|
321
|
+
const resultsModel = columnsResultsModel.value[headerKey] || []
|
|
322
|
+
|
|
203
323
|
const newColumnValues = [
|
|
204
|
-
...
|
|
205
|
-
...
|
|
324
|
+
...resultsModel,
|
|
325
|
+
...newValues
|
|
206
326
|
]
|
|
207
327
|
|
|
328
|
+
/**
|
|
329
|
+
* exemplo de como columnsResultsModel irá ficar:
|
|
330
|
+
*
|
|
331
|
+
* {
|
|
332
|
+
* '2024-02-15': [...],
|
|
333
|
+
* '2024-02-16': [...]
|
|
334
|
+
* }
|
|
335
|
+
*
|
|
336
|
+
* onde cada item do objeto é uma coluna no board. O mesmo vale para "columnsFieldsModel", "columnsLoading" e
|
|
337
|
+
* "columnPagination", organizando os fields, loadings e o controle de paginação por chave identificadora do header.
|
|
338
|
+
*/
|
|
208
339
|
columnsResultsModel.value[headerKey] = props.useMarkRaw ? markRaw(newColumnValues) : newColumnValues
|
|
209
340
|
|
|
210
341
|
/*
|
|
@@ -293,8 +424,24 @@ function setColumnsPagination () {
|
|
|
293
424
|
})
|
|
294
425
|
}
|
|
295
426
|
|
|
427
|
+
function fetchColumnsValues () {
|
|
428
|
+
reset()
|
|
429
|
+
setColumnHeightContainer()
|
|
430
|
+
setColumnsPagination()
|
|
431
|
+
fetchColumns()
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* Descricao:
|
|
436
|
+
* Exibe o texto quando:
|
|
437
|
+
* - Nao esta carregando a coluna
|
|
438
|
+
* - Nao tem itens na coluna
|
|
439
|
+
* - Nao estou fazendo o drag and drop
|
|
440
|
+
*
|
|
441
|
+
* @param {Object} header
|
|
442
|
+
*/
|
|
296
443
|
function hasEmptyResultText (header) {
|
|
297
|
-
return !columnsLoading.value[getKeyByHeader(header)] && !getItemsByHeader(header)?.length
|
|
444
|
+
return !columnsLoading.value[getKeyByHeader(header)] && !getItemsByHeader(header)?.length && !isDragging.value
|
|
298
445
|
}
|
|
299
446
|
|
|
300
447
|
/*
|
|
@@ -319,6 +466,221 @@ function getFieldsByHeader (header) {
|
|
|
319
466
|
|
|
320
467
|
return columnsFieldsModel.value[headerKey] || {}
|
|
321
468
|
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Loopa todos os itens da coluna com base no ref para pegar o elemento HTML e setar e instaciar o sortable.
|
|
472
|
+
*/
|
|
473
|
+
function handleElementsList () {
|
|
474
|
+
columnContainer.value.forEach((element, index) => {
|
|
475
|
+
const sortable = setSortable(element, index)
|
|
476
|
+
|
|
477
|
+
sortableInstances.value.push(sortable)
|
|
478
|
+
})
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Descricao:
|
|
483
|
+
* Seta a instancia do sortable, no qual varia de acordo com as props passadas.
|
|
484
|
+
*
|
|
485
|
+
* @param {HTMLElement} element
|
|
486
|
+
* @param {Number} index
|
|
487
|
+
*/
|
|
488
|
+
function setSortable (element, index) {
|
|
489
|
+
const defaultSortableConfig = {
|
|
490
|
+
animation: 500,
|
|
491
|
+
swapThreshold: 1,
|
|
492
|
+
delay: 50,
|
|
493
|
+
delayOnTouchOnly: true,
|
|
494
|
+
emptyInsertThreshold: 0
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Caso seja apenas drag and drop no eixo Y
|
|
499
|
+
*/
|
|
500
|
+
const useOnlyDragAndDropY = !!props.useDragAndDropY && !props.useDragAndDropX
|
|
501
|
+
|
|
502
|
+
const sortable = new Sortable(element, {
|
|
503
|
+
sort: props.useDragAndDropY,
|
|
504
|
+
|
|
505
|
+
...defaultSortableConfig,
|
|
506
|
+
|
|
507
|
+
...props.sortableConfig,
|
|
508
|
+
|
|
509
|
+
group: useOnlyDragAndDropY ? `column-${index}` : 'shared',
|
|
510
|
+
|
|
511
|
+
direction: useOnlyDragAndDropY ? 'vertical' : 'horizontal',
|
|
512
|
+
|
|
513
|
+
onStart: toggleIsDragging,
|
|
514
|
+
|
|
515
|
+
onAdd: event => onDropCard(event),
|
|
516
|
+
|
|
517
|
+
...(props.useDragAndDropY && {
|
|
518
|
+
onSort: event => onDropCard(event)
|
|
519
|
+
})
|
|
520
|
+
})
|
|
521
|
+
|
|
522
|
+
return sortable
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function toggleIsDragging () {
|
|
526
|
+
isDragging.value = !isDragging.value
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function onDropCard (event) {
|
|
530
|
+
onCancelDrop.value = () => cancelDrop(event)
|
|
531
|
+
|
|
532
|
+
onConfirmDrop.value = () => confirmDrop(event)
|
|
533
|
+
|
|
534
|
+
hasConfirmDialogProps.value
|
|
535
|
+
? openConfirmDialog()
|
|
536
|
+
: confirmDrop(event)
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
function openConfirmDialog () {
|
|
540
|
+
showConfirmDialog.value = true
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
function closeConfirmDialog () {
|
|
544
|
+
showConfirmDialog.value = false
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* @param {event} event
|
|
549
|
+
*/
|
|
550
|
+
function cancelDrop (event) {
|
|
551
|
+
/**
|
|
552
|
+
* Insere na posição antiga que pertencia (event.oldIndex) dentro do seu antigo pai (event.from)
|
|
553
|
+
*/
|
|
554
|
+
if (props.useDragAndDropX) event.from.insertBefore(event.item, event.from.children[event.oldIndex])
|
|
555
|
+
|
|
556
|
+
if (props.useDragAndDropY) {
|
|
557
|
+
const oldIndex = event.oldIndex
|
|
558
|
+
|
|
559
|
+
/**
|
|
560
|
+
* Se oldIndex for 0, o targetIndex deverá ser 0, pois isso indica que se o item é o primeiro da lista, ele não será movido para outra posição.
|
|
561
|
+
*
|
|
562
|
+
* Caso o oldIndex for diferente, devo incrementar 1 para adicionar, pois isso permite que o item seja inserido logo após sua posição original.
|
|
563
|
+
*/
|
|
564
|
+
const targetIndex = oldIndex === 0 ? oldIndex : oldIndex + 1
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Verifica se o índice alvo é válido, caso contrário, define como o final
|
|
568
|
+
*/
|
|
569
|
+
const insertBeforeElement = targetIndex < event.from.children.length
|
|
570
|
+
? event.from.children[targetIndex]
|
|
571
|
+
: null
|
|
572
|
+
|
|
573
|
+
event.from.insertBefore(event.item, insertBeforeElement)
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
if (hasConfirmDialogProps.value) closeConfirmDialog()
|
|
577
|
+
|
|
578
|
+
toggleIsDragging()
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
function confirmDrop (event) {
|
|
582
|
+
const { from, to, item: { id: itemId } } = event
|
|
583
|
+
|
|
584
|
+
const { headerKey: newHeaderKey } = to.dataset
|
|
585
|
+
const { headerKey: oldHeaderKey } = from.dataset
|
|
586
|
+
|
|
587
|
+
updatePosition({ newHeaderKey, oldHeaderKey, itemId, event })
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
*
|
|
592
|
+
* @param {{
|
|
593
|
+
* headerKey: string,
|
|
594
|
+
* itemId: string
|
|
595
|
+
* }}
|
|
596
|
+
*/
|
|
597
|
+
function removeItemFromList ({ headerKey, itemId }) {
|
|
598
|
+
/**
|
|
599
|
+
* Coluna referente ao model de resultado
|
|
600
|
+
*/
|
|
601
|
+
const columnItemList = columnsResultsModel.value[headerKey]
|
|
602
|
+
|
|
603
|
+
/**
|
|
604
|
+
* Busca o item com base em seu ID na lista de itens da coluna
|
|
605
|
+
*/
|
|
606
|
+
const itemIndex = columnItemList.findIndex(itemContent => itemContent[props.itemIdKey] === itemId)
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Remove o item da listagem com base no index, sendo que preciso subtrair 1 para pegar o index correto
|
|
610
|
+
*/
|
|
611
|
+
columnItemList.splice(itemIndex, 1)
|
|
612
|
+
|
|
613
|
+
/**
|
|
614
|
+
* Remove o item do count da coluna para não mostrar o botão de "Ver mais¨.
|
|
615
|
+
*/
|
|
616
|
+
columnsPagination.value[headerKey].count -= 1
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/**
|
|
620
|
+
* Descricao:
|
|
621
|
+
* Metodo que realiza a request de update
|
|
622
|
+
*
|
|
623
|
+
* @param {{
|
|
624
|
+
* newHeaderKey: string - ID da coluna de destino,
|
|
625
|
+
* oldHeaderKey: string - ID da antiga coluna,
|
|
626
|
+
* itemId: string - ID do meu item a ser movimento,
|
|
627
|
+
* event: event
|
|
628
|
+
* }}
|
|
629
|
+
*/
|
|
630
|
+
async function updatePosition ({ newHeaderKey, oldHeaderKey, itemId, event }) {
|
|
631
|
+
const params = {
|
|
632
|
+
[props.columnIdKey]: newHeaderKey,
|
|
633
|
+
...(props.useDragAndDropY && { newIndex: event.newIndex }),
|
|
634
|
+
...props.updatePositionParams
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
const { data, error } = await promiseHandler(
|
|
638
|
+
axios.patch(`${props.updatePositionUrl}/${itemId}/update-position`, params),
|
|
639
|
+
{
|
|
640
|
+
errorMessage: 'Ocorreu um erro ao atualizar a posição de seu item.',
|
|
641
|
+
useLoading: false,
|
|
642
|
+
onLoading: value => {
|
|
643
|
+
isLoadingUpdatePosition.value = value
|
|
644
|
+
|
|
645
|
+
columnsLoading.value[newHeaderKey] = value
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
)
|
|
649
|
+
|
|
650
|
+
if (error) {
|
|
651
|
+
onCancelDrop.value()
|
|
652
|
+
|
|
653
|
+
return
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
removeItemFromList({ headerKey: oldHeaderKey, itemId })
|
|
657
|
+
|
|
658
|
+
setItemList({ headerKey: newHeaderKey, data: data.data, index: event.newIndex })
|
|
659
|
+
|
|
660
|
+
isUpdatingPosition.value = true
|
|
661
|
+
|
|
662
|
+
toggleIsDragging()
|
|
663
|
+
|
|
664
|
+
closeConfirmDialog()
|
|
665
|
+
|
|
666
|
+
emit('update-success')
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function setItemList ({ headerKey, data, index }) {
|
|
670
|
+
/**
|
|
671
|
+
* Coluna referente ao model de resultado
|
|
672
|
+
*/
|
|
673
|
+
const columnItemList = columnsResultsModel.value[headerKey]
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Adiciona o item na posição do event escolhido.
|
|
677
|
+
*/
|
|
678
|
+
columnItemList.splice(index, 0, data.result)
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function destroySortable () {
|
|
682
|
+
sortableInstances.value.forEach(sortable => sortable.destroy())
|
|
683
|
+
}
|
|
322
684
|
</script>
|
|
323
685
|
|
|
324
686
|
<style lang="scss">
|
|
@@ -341,5 +703,10 @@ function getFieldsByHeader (header) {
|
|
|
341
703
|
display: none;
|
|
342
704
|
}
|
|
343
705
|
}
|
|
706
|
+
|
|
707
|
+
// 60px é o valor do padding definido no container da column.
|
|
708
|
+
&__column-items {
|
|
709
|
+
height: calc(100% - 60px);
|
|
710
|
+
}
|
|
344
711
|
}
|
|
345
712
|
</style>
|
|
@@ -20,19 +20,33 @@ props:
|
|
|
20
20
|
required: true
|
|
21
21
|
|
|
22
22
|
column-width:
|
|
23
|
-
desc: Largura da coluna
|
|
23
|
+
desc: Largura da coluna.
|
|
24
24
|
type: String
|
|
25
25
|
default: 288
|
|
26
26
|
|
|
27
|
+
confirm-dialog-props:
|
|
28
|
+
desc: Propriedade repassada ao `QasDialog` para confirmar um drag and drop. Caso não seja passado, não é usado dialog de confirmação. As ações de confirmar e cancelar são feitas por padrão no componente.
|
|
29
|
+
type: Object
|
|
30
|
+
default: {}
|
|
31
|
+
|
|
32
|
+
header-box-props:
|
|
33
|
+
desc: Propriedades repassadas ao `QasBox` do header.
|
|
34
|
+
type: Object
|
|
35
|
+
default: {}
|
|
36
|
+
|
|
27
37
|
headers:
|
|
28
38
|
desc: Lista de itens sendo cada um o header de cada coluna.
|
|
29
39
|
default: []
|
|
30
40
|
type: Array
|
|
31
|
-
|
|
41
|
+
|
|
32
42
|
height:
|
|
33
|
-
desc: Altura do container do board. Caso não seja passado um height, o
|
|
43
|
+
desc: Altura do container do board. Caso não seja passado um height, o cálculo é feito para ocupar a maior altura possível da página.
|
|
44
|
+
type: String
|
|
45
|
+
|
|
46
|
+
item-id-key:
|
|
47
|
+
desc: Identificador único do item a ser movido, sendo que será usado nas requisições realizadas pelo drop.
|
|
34
48
|
type: String
|
|
35
|
-
|
|
49
|
+
|
|
36
50
|
lazy-loading-fields-keys:
|
|
37
51
|
desc: Chaves dos campos que são lazy loading para o tratamento de merge das options.
|
|
38
52
|
type: Array
|
|
@@ -44,7 +58,7 @@ props:
|
|
|
44
58
|
default: 12
|
|
45
59
|
|
|
46
60
|
use-mark-raw:
|
|
47
|
-
desc: Define se os valores dos itens das colunas
|
|
61
|
+
desc: Define se os valores dos itens das colunas irão ser atribuídos utilizando o "markRaw", onde somente a primeira camada do model será reativa. (https://vuejs.org/api/reactivity-advanced.html#markraw)
|
|
48
62
|
type: Boolean
|
|
49
63
|
default: true
|
|
50
64
|
|
|
@@ -55,6 +69,30 @@ props:
|
|
|
55
69
|
examples: [v-model:results="resultsColumns"]
|
|
56
70
|
model: true
|
|
57
71
|
|
|
72
|
+
sortable-config:
|
|
73
|
+
desc: Configuração passada para a instância do SortableJS.
|
|
74
|
+
type: Object
|
|
75
|
+
default: "{ animation: 500, swapThreshold: 1, delay: 50, delayOnTouchOnly: true, emptyInsertThreshold: 0 }"
|
|
76
|
+
debugger: true
|
|
77
|
+
|
|
78
|
+
use-drag-and-drop-x:
|
|
79
|
+
desc: Controla se irá ter drag and drop no eixo X (entre colunas).
|
|
80
|
+
type: Boolean
|
|
81
|
+
|
|
82
|
+
use-drag-and-drop-y:
|
|
83
|
+
desc: Controla se irá ter drag and drop no eixo Y (mesma coluna, utilizado para ordenação de itens).
|
|
84
|
+
type: Boolean
|
|
85
|
+
|
|
86
|
+
update-position-url:
|
|
87
|
+
desc: URL usada para realizar o PATCH do drag and drop.
|
|
88
|
+
type: String
|
|
89
|
+
default: ''
|
|
90
|
+
|
|
91
|
+
update-position-params:
|
|
92
|
+
desc: Parâmetros customizados caso precise passar para a API de PATCH.
|
|
93
|
+
type: Object
|
|
94
|
+
default: {}
|
|
95
|
+
|
|
58
96
|
slots:
|
|
59
97
|
header-column:
|
|
60
98
|
desc: Slot para acessar o card do header de cada coluna.
|
|
@@ -63,9 +101,9 @@ slots:
|
|
|
63
101
|
desc: Fields referente à coluna atual do template.
|
|
64
102
|
type: Object
|
|
65
103
|
default: {}
|
|
66
|
-
|
|
104
|
+
|
|
67
105
|
header:
|
|
68
|
-
desc: Informações de cada item do header que foi fornecido através da prop "headers"
|
|
106
|
+
desc: Informações de cada item do header que foi fornecido através da prop "headers".
|
|
69
107
|
type: Object
|
|
70
108
|
default: {}
|
|
71
109
|
|
|
@@ -76,7 +114,7 @@ slots:
|
|
|
76
114
|
desc: Fields referente à coluna atual do template.
|
|
77
115
|
type: Object
|
|
78
116
|
default: {}
|
|
79
|
-
|
|
117
|
+
|
|
80
118
|
item:
|
|
81
119
|
desc: Informações de cada item da coluna que foi buscado através da API.
|
|
82
120
|
type: Object
|
|
@@ -98,14 +136,14 @@ events:
|
|
|
98
136
|
type: Object
|
|
99
137
|
|
|
100
138
|
header:
|
|
101
|
-
desc:
|
|
139
|
+
desc: Header da coluna atual.
|
|
102
140
|
type: Object
|
|
103
141
|
|
|
104
142
|
'@update:fetch-column-error -> function(error)':
|
|
105
143
|
desc: Dispara quando o "fetchColumn" cai em uma exceção.
|
|
106
144
|
params:
|
|
107
145
|
error:
|
|
108
|
-
desc: Retorna todos os dados "
|
|
146
|
+
desc: Retorna todos os dados "crus" respondidos na exceção do fetch.
|
|
109
147
|
type: Object
|
|
110
148
|
|
|
111
149
|
'@update:fetch-columns-success -> function()':
|
|
@@ -115,12 +153,15 @@ events:
|
|
|
115
153
|
desc: Dispara quando algum "fetchColumn" cai em uma exceção.
|
|
116
154
|
params:
|
|
117
155
|
error:
|
|
118
|
-
desc: Retorna todos os dados "
|
|
156
|
+
desc: Retorna todos os dados "crus" respondidos na exceção do fetch.
|
|
119
157
|
type: Object
|
|
120
158
|
|
|
159
|
+
'@update-success -> function()':
|
|
160
|
+
desc: Dispara quando o PATCH do drag and drop é com sucesso.
|
|
161
|
+
|
|
121
162
|
methods:
|
|
122
163
|
'fetchColumns: () => void':
|
|
123
164
|
desc: Busca todas colunas com base nos headers fornecidos.
|
|
124
165
|
|
|
125
166
|
'fetchColumn: (header) => void':
|
|
126
|
-
desc: Busca uma coluna
|
|
167
|
+
desc: Busca uma coluna específica com base no header fornecido.
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<qas-box class="rounded-borders-right" v-bind="boxProps">
|
|
4
4
|
<q-card class="column full-height overflow-hidden shadow-0">
|
|
5
5
|
<div class="items-center justify-between row">
|
|
6
|
-
<component :is="titleComponent" class="text-
|
|
6
|
+
<component :is="titleComponent" class="text-h5 text-no-decoration" :class="titleClasses" :to="route">
|
|
7
7
|
<slot name="title">
|
|
8
8
|
{{ props.title }}
|
|
9
9
|
</slot>
|
|
@@ -89,7 +89,7 @@ const titleClasses = computed(() => {
|
|
|
89
89
|
}
|
|
90
90
|
})
|
|
91
91
|
|
|
92
|
-
const titleComponent = computed(() => hasRoute.value ? 'router-link' : '
|
|
92
|
+
const titleComponent = computed(() => hasRoute.value ? 'router-link' : 'h5')
|
|
93
93
|
|
|
94
94
|
const style = computed(() => {
|
|
95
95
|
if (!props.statusColor) return
|
|
@@ -19,6 +19,11 @@ defineOptions({ name: 'QasGrabbable' })
|
|
|
19
19
|
const props = defineProps({
|
|
20
20
|
useScrollBar: {
|
|
21
21
|
type: Boolean
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
cancelMouseDownTarget: {
|
|
25
|
+
type: String,
|
|
26
|
+
default: ''
|
|
22
27
|
}
|
|
23
28
|
})
|
|
24
29
|
|
|
@@ -61,17 +66,20 @@ function handleEnableScrollOnGrab () {
|
|
|
61
66
|
function initScrollOnGrab () {
|
|
62
67
|
if (hasScrollOnGrab.value) return
|
|
63
68
|
|
|
64
|
-
scrollOnGrab.value = setScrollOnGrab(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
scrollOnGrab.value = setScrollOnGrab(
|
|
70
|
+
grabContainer.value,
|
|
71
|
+
{
|
|
72
|
+
onGrabFn: onGrab,
|
|
73
|
+
onMoveFn: setGrabPosition,
|
|
74
|
+
onScrollFn: setGrabPosition
|
|
75
|
+
},
|
|
76
|
+
props.cancelMouseDownTarget
|
|
77
|
+
)
|
|
69
78
|
}
|
|
70
79
|
|
|
71
80
|
function destroyScrollOnGrab () {
|
|
72
81
|
if (!hasScrollOnGrab.value) return
|
|
73
82
|
|
|
74
|
-
scrollOnGrab.value.destroyEvents()
|
|
75
83
|
scrollOnGrab.value.element.style.cursor = 'auto'
|
|
76
84
|
scrollOnGrab.value = {}
|
|
77
85
|
|
|
@@ -13,11 +13,11 @@
|
|
|
13
13
|
</div>
|
|
14
14
|
</div>
|
|
15
15
|
|
|
16
|
-
<
|
|
17
|
-
<
|
|
16
|
+
<div v-if="hasActionsSection" class="text-right">
|
|
17
|
+
<slot name="actions">
|
|
18
18
|
<component :is="actionsComponent.is" v-if="hasActionsComponent" v-bind="actionsComponent.props" />
|
|
19
|
-
</
|
|
20
|
-
</
|
|
19
|
+
</slot>
|
|
20
|
+
</div>
|
|
21
21
|
</div>
|
|
22
22
|
|
|
23
23
|
<div class="items-start no-wrap q-col-gutter-sm row" :class="descriptionSectionClasses">
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
</slot>
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
|
-
<div v-if="!hasLabelSection" class="justify-end row">
|
|
30
|
+
<div v-if="!hasLabelSection" class="justify-end row text-right">
|
|
31
31
|
<slot name="actions">
|
|
32
32
|
<component :is="actionsComponent.is" v-if="hasActionsComponent" v-bind="actionsComponent.props" />
|
|
33
33
|
</slot>
|
|
@@ -33,6 +33,11 @@ const props = defineProps({
|
|
|
33
33
|
default: () => []
|
|
34
34
|
},
|
|
35
35
|
|
|
36
|
+
fields: {
|
|
37
|
+
type: Object,
|
|
38
|
+
default: () => ({})
|
|
39
|
+
},
|
|
40
|
+
|
|
36
41
|
limitPerPage: {
|
|
37
42
|
type: Number,
|
|
38
43
|
default: 12
|
|
@@ -62,7 +67,10 @@ const props = defineProps({
|
|
|
62
67
|
|
|
63
68
|
defineExpose({ refresh, remove })
|
|
64
69
|
|
|
65
|
-
const emit = defineEmits(['
|
|
70
|
+
const emit = defineEmits(['fetch-success', 'fetch-error'])
|
|
71
|
+
|
|
72
|
+
const modelList = defineModel('list', { type: Array, default: () => [] })
|
|
73
|
+
const modelFields = defineModel('fields', { type: Object, default: () => ({}) })
|
|
66
74
|
|
|
67
75
|
const axios = inject('axios')
|
|
68
76
|
|
|
@@ -74,7 +82,7 @@ const hasMadeFirstFetch = ref(false)
|
|
|
74
82
|
const count = ref(0)
|
|
75
83
|
const offset = ref(0)
|
|
76
84
|
|
|
77
|
-
const listLength = computed(() =>
|
|
85
|
+
const listLength = computed(() => modelList.value.length)
|
|
78
86
|
|
|
79
87
|
const attributes = computed(() => ({
|
|
80
88
|
offset: 100,
|
|
@@ -91,16 +99,6 @@ const containerStyle = computed(() => ({
|
|
|
91
99
|
...(props.maxHeight && { maxHeight: props.maxHeight, overflow: 'auto' })
|
|
92
100
|
}))
|
|
93
101
|
|
|
94
|
-
const model = computed({
|
|
95
|
-
get () {
|
|
96
|
-
return props.list
|
|
97
|
-
},
|
|
98
|
-
|
|
99
|
-
set (newList) {
|
|
100
|
-
emit('update:list', newList)
|
|
101
|
-
}
|
|
102
|
-
})
|
|
103
|
-
|
|
104
102
|
async function onLoad (_, done) {
|
|
105
103
|
const hasMadeFirstFetchAndHasNoData = hasMadeFirstFetch.value && !listLength.value
|
|
106
104
|
const hasFetchAllData = listLength.value && listLength.value >= count.value
|
|
@@ -124,11 +122,12 @@ async function fetchList () {
|
|
|
124
122
|
params: { offset: offset.value, limit: props.limitPerPage, ...props.params }
|
|
125
123
|
})
|
|
126
124
|
|
|
127
|
-
const newList = [...
|
|
125
|
+
const newList = [...modelList.value, ...(data.results || [])]
|
|
128
126
|
|
|
129
|
-
|
|
127
|
+
modelList.value = newList
|
|
130
128
|
offset.value = newList.length
|
|
131
129
|
count.value = data.count
|
|
130
|
+
modelFields.value = data.fields
|
|
132
131
|
|
|
133
132
|
/**
|
|
134
133
|
* Sinalizar que houve já uma busca, para evitar que onLoad entre em looping,
|
|
@@ -136,7 +135,7 @@ async function fetchList () {
|
|
|
136
135
|
*/
|
|
137
136
|
hasMadeFirstFetch.value = true
|
|
138
137
|
|
|
139
|
-
emit('fetch-success', { list: newList, offset: offset.value, count: count.value })
|
|
138
|
+
emit('fetch-success', { list: newList, fields: modelFields.value, offset: offset.value, count: count.value })
|
|
140
139
|
} catch (error) {
|
|
141
140
|
NotifyError('Ops… Não conseguimos acessar as informações. Por favor, tente novamente em alguns minutos.')
|
|
142
141
|
|
|
@@ -151,7 +150,7 @@ async function fetchList () {
|
|
|
151
150
|
function refresh () {
|
|
152
151
|
count.value = 0
|
|
153
152
|
offset.value = 0
|
|
154
|
-
|
|
153
|
+
modelList.value = []
|
|
155
154
|
|
|
156
155
|
hasMadeFirstFetch.value = false
|
|
157
156
|
|
|
@@ -162,7 +161,7 @@ function refresh () {
|
|
|
162
161
|
}
|
|
163
162
|
|
|
164
163
|
function remove (index) {
|
|
165
|
-
|
|
164
|
+
modelList.value.splice(index, 1)
|
|
166
165
|
count.value -= 1
|
|
167
166
|
offset.value -= 1
|
|
168
167
|
}
|
|
@@ -4,6 +4,13 @@ meta:
|
|
|
4
4
|
desc: Componente de infinite scroll que implementa o "QInfiniteScroll".
|
|
5
5
|
|
|
6
6
|
props:
|
|
7
|
+
fields:
|
|
8
|
+
desc: Model dos fields.
|
|
9
|
+
default: {}
|
|
10
|
+
type: Object
|
|
11
|
+
examples: [v-model:fields="fields"]
|
|
12
|
+
model: true
|
|
13
|
+
|
|
7
14
|
list:
|
|
8
15
|
desc: Model da lista de itens.
|
|
9
16
|
default: []
|
|
@@ -47,6 +47,7 @@ import debug from 'debug'
|
|
|
47
47
|
import { extend } from 'quasar'
|
|
48
48
|
import { getState, getAction } from '@bildvitta/store-adapter'
|
|
49
49
|
import { viewMixin, contextMixin } from '../../mixins'
|
|
50
|
+
import { computed } from 'vue'
|
|
50
51
|
|
|
51
52
|
const log = debug('asteroid-ui:qas-list-view')
|
|
52
53
|
|
|
@@ -58,6 +59,13 @@ export default {
|
|
|
58
59
|
|
|
59
60
|
mixins: [contextMixin, viewMixin],
|
|
60
61
|
|
|
62
|
+
provide () {
|
|
63
|
+
return {
|
|
64
|
+
isFetchListSucceeded: computed(() => this.isFetchListSucceeded),
|
|
65
|
+
isListView: true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
|
|
61
69
|
props: {
|
|
62
70
|
filtersProps: {
|
|
63
71
|
default: () => ({}),
|
|
@@ -107,7 +115,8 @@ export default {
|
|
|
107
115
|
data () {
|
|
108
116
|
return {
|
|
109
117
|
page: 1,
|
|
110
|
-
resultsQuantity: 0
|
|
118
|
+
resultsQuantity: 0,
|
|
119
|
+
isFetchListSucceeded: false
|
|
111
120
|
}
|
|
112
121
|
},
|
|
113
122
|
|
|
@@ -188,6 +197,7 @@ export default {
|
|
|
188
197
|
|
|
189
198
|
async fetchList (externalPayload = {}) {
|
|
190
199
|
this.mx_isFetching = true
|
|
200
|
+
this.isFetchListSucceeded = false
|
|
191
201
|
|
|
192
202
|
try {
|
|
193
203
|
const payload = {
|
|
@@ -215,6 +225,8 @@ export default {
|
|
|
215
225
|
metadata: this.mx_metadata
|
|
216
226
|
})
|
|
217
227
|
|
|
228
|
+
this.isFetchListSucceeded = true
|
|
229
|
+
|
|
218
230
|
this.$emit('fetch-success', response)
|
|
219
231
|
|
|
220
232
|
log(`[${this.entity}]:fetchList:success`, response)
|
|
@@ -158,3 +158,12 @@ events:
|
|
|
158
158
|
value:
|
|
159
159
|
desc: Retorna se está ou não fazendo fetching de dados.
|
|
160
160
|
type: Boolean
|
|
161
|
+
|
|
162
|
+
provide:
|
|
163
|
+
is-fetch-list-succeeded:
|
|
164
|
+
desc: Valor que diz se o `fetchList` foi realizado com sucesso ou não.
|
|
165
|
+
type: Boolean
|
|
166
|
+
|
|
167
|
+
is-list-view:
|
|
168
|
+
desc: Provide que diz quando se está utilizando o listView
|
|
169
|
+
type: Boolean
|
|
@@ -17,7 +17,7 @@ props:
|
|
|
17
17
|
desc: Propriedades que serão repassadas para o QasStepper.
|
|
18
18
|
type: Object
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
provide:
|
|
21
21
|
stepper-model:
|
|
22
22
|
desc: Model do stepper caso precise recuperar o step atual para alguma lógica. Possui reatividade, portanto para acessar é necessário do ".value"
|
|
23
23
|
type: Number
|
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
* onMoveFn: function({ element: HTMLElement, event: MouseEvent | TouchEvent }),
|
|
8
8
|
* onScrollFn: function({ element: HTMLElement, event: Event })
|
|
9
9
|
* }} options
|
|
10
|
+
* @param {String} cancelMouseDownTarget
|
|
10
11
|
*
|
|
11
12
|
* @returns {{ element: HTMLElement, destroyEvents: function }}
|
|
12
13
|
*/
|
|
13
|
-
export default function (element, options = {}) {
|
|
14
|
+
export default function (element, options = {}, cancelMouseDownTarget) {
|
|
14
15
|
let isDown = false
|
|
15
16
|
let startX
|
|
16
17
|
let scrollLeft
|
|
@@ -46,6 +47,13 @@ export default function (element, options = {}) {
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
function onMouseEnter (event) {
|
|
50
|
+
/**
|
|
51
|
+
* closest busca ancestral mais próximo de um elemento, ou seja, verifica se no event que recebo, tenho a classe no qual nao se deve aplicar o grab.
|
|
52
|
+
*/
|
|
53
|
+
const targetElement = event.target.closest(`.${cancelMouseDownTarget}`)
|
|
54
|
+
|
|
55
|
+
if (!!cancelMouseDownTarget && !!targetElement) return null
|
|
56
|
+
|
|
49
57
|
onEnter()
|
|
50
58
|
|
|
51
59
|
startX = event.pageX - element.offsetLeft
|