evui 3.4.207 → 3.4.209

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.
Files changed (162) hide show
  1. package/README.md +18 -33
  2. package/dist/404.html +44 -0
  3. package/dist/favicon.ico +0 -0
  4. package/dist/index.js +22738 -0
  5. package/dist/index.umd.cjs +28 -0
  6. package/dist/style.css +1 -0
  7. package/package.json +46 -43
  8. package/dist/evui.common.js +0 -63681
  9. package/dist/evui.common.js.map +0 -1
  10. package/dist/evui.umd.js +0 -63691
  11. package/dist/evui.umd.js.map +0 -1
  12. package/dist/evui.umd.min.js +0 -2
  13. package/dist/evui.umd.min.js.map +0 -1
  14. package/dist/img/EVUI.b82ee81a.svg +0 -293
  15. package/src/assets/logo.png +0 -0
  16. package/src/common/emitter.js +0 -20
  17. package/src/common/utils.bignumber.js +0 -67
  18. package/src/common/utils.debounce.js +0 -223
  19. package/src/common/utils.js +0 -151
  20. package/src/common/utils.table.js +0 -78
  21. package/src/common/utils.throttle.js +0 -83
  22. package/src/common/utils.tree.js +0 -18
  23. package/src/components/button/Button.vue +0 -195
  24. package/src/components/button/index.js +0 -7
  25. package/src/components/buttonGroup/ButtonGroup.vue +0 -11
  26. package/src/components/buttonGroup/index.js +0 -7
  27. package/src/components/calendar/Calendar.vue +0 -725
  28. package/src/components/calendar/index.js +0 -7
  29. package/src/components/calendar/uses.js +0 -1410
  30. package/src/components/chart/Chart.vue +0 -363
  31. package/src/components/chart/ChartToolbar.vue +0 -52
  32. package/src/components/chart/chart.core.js +0 -1170
  33. package/src/components/chart/chartZoom.core.js +0 -540
  34. package/src/components/chart/element/element.bar.js +0 -672
  35. package/src/components/chart/element/element.bar.time.js +0 -166
  36. package/src/components/chart/element/element.heatmap.js +0 -743
  37. package/src/components/chart/element/element.line.js +0 -611
  38. package/src/components/chart/element/element.pie.js +0 -197
  39. package/src/components/chart/element/element.scatter.js +0 -320
  40. package/src/components/chart/element/element.tip.js +0 -717
  41. package/src/components/chart/helpers/helpers.canvas.js +0 -265
  42. package/src/components/chart/helpers/helpers.constant.js +0 -235
  43. package/src/components/chart/helpers/helpers.util.js +0 -400
  44. package/src/components/chart/index.js +0 -9
  45. package/src/components/chart/model/index.js +0 -50
  46. package/src/components/chart/model/model.series.js +0 -125
  47. package/src/components/chart/model/model.store.js +0 -1427
  48. package/src/components/chart/plugins/plugins.interaction.js +0 -1659
  49. package/src/components/chart/plugins/plugins.legend.gradient.js +0 -606
  50. package/src/components/chart/plugins/plugins.legend.js +0 -1543
  51. package/src/components/chart/plugins/plugins.pie.js +0 -254
  52. package/src/components/chart/plugins/plugins.scrollbar.js +0 -732
  53. package/src/components/chart/plugins/plugins.title.js +0 -61
  54. package/src/components/chart/plugins/plugins.tooltip.js +0 -1041
  55. package/src/components/chart/scale/scale.js +0 -951
  56. package/src/components/chart/scale/scale.linear.js +0 -268
  57. package/src/components/chart/scale/scale.logarithmic.js +0 -135
  58. package/src/components/chart/scale/scale.step.js +0 -430
  59. package/src/components/chart/scale/scale.time.category.js +0 -338
  60. package/src/components/chart/scale/scale.time.js +0 -49
  61. package/src/components/chart/style/chart.scss +0 -405
  62. package/src/components/chart/uses.js +0 -721
  63. package/src/components/chartBrush/ChartBrush.vue +0 -323
  64. package/src/components/chartBrush/chartBrush.core.js +0 -691
  65. package/src/components/chartBrush/index.js +0 -9
  66. package/src/components/chartBrush/uses.js +0 -23
  67. package/src/components/chartGroup/ChartGroup.vue +0 -144
  68. package/src/components/chartGroup/index.js +0 -9
  69. package/src/components/chartGroup/style/chartGroup.scss +0 -5
  70. package/src/components/chartGroup/uses.js +0 -53
  71. package/src/components/checkbox/Checkbox.vue +0 -229
  72. package/src/components/checkbox/index.js +0 -7
  73. package/src/components/checkboxGroup/CheckboxGroup.vue +0 -44
  74. package/src/components/checkboxGroup/index.js +0 -7
  75. package/src/components/contextMenu/ContextMenu.vue +0 -95
  76. package/src/components/contextMenu/MenuList.vue +0 -182
  77. package/src/components/contextMenu/index.js +0 -7
  78. package/src/components/contextMenu/uses.js +0 -223
  79. package/src/components/datePicker/DatePicker.vue +0 -504
  80. package/src/components/datePicker/index.js +0 -7
  81. package/src/components/datePicker/uses.js +0 -460
  82. package/src/components/grid/Grid.vue +0 -1535
  83. package/src/components/grid/GridColumnSetting.vue +0 -358
  84. package/src/components/grid/GridFilterSetting.vue +0 -323
  85. package/src/components/grid/GridPagination.vue +0 -75
  86. package/src/components/grid/GridSummary.vue +0 -314
  87. package/src/components/grid/GridToolbar.vue +0 -35
  88. package/src/components/grid/icon/icon-option-button.vue +0 -17
  89. package/src/components/grid/icon/icon-sort-button.vue +0 -67
  90. package/src/components/grid/index.js +0 -11
  91. package/src/components/grid/style/grid.scss +0 -417
  92. package/src/components/grid/uses.js +0 -1629
  93. package/src/components/icon/Icon.vue +0 -53
  94. package/src/components/icon/index.js +0 -8
  95. package/src/components/inputNumber/InputNumber.vue +0 -212
  96. package/src/components/inputNumber/index.js +0 -7
  97. package/src/components/inputNumber/uses.js +0 -217
  98. package/src/components/loading/Loading.vue +0 -125
  99. package/src/components/loading/index.js +0 -7
  100. package/src/components/menu/Menu.vue +0 -79
  101. package/src/components/menu/MenuItem.vue +0 -201
  102. package/src/components/menu/index.js +0 -7
  103. package/src/components/message/Message.vue +0 -229
  104. package/src/components/message/index.js +0 -34
  105. package/src/components/messageBox/MessageBox.vue +0 -358
  106. package/src/components/messageBox/index.js +0 -22
  107. package/src/components/notification/Notification.vue +0 -316
  108. package/src/components/notification/index.js +0 -49
  109. package/src/components/pagination/Pagination.vue +0 -317
  110. package/src/components/pagination/index.js +0 -7
  111. package/src/components/pagination/pageButton.vue +0 -31
  112. package/src/components/progress/Progress.vue +0 -139
  113. package/src/components/progress/index.js +0 -7
  114. package/src/components/radio/Radio.vue +0 -159
  115. package/src/components/radio/index.js +0 -7
  116. package/src/components/radioGroup/RadioGroup.vue +0 -41
  117. package/src/components/radioGroup/index.js +0 -7
  118. package/src/components/scheduler/Scheduler.vue +0 -149
  119. package/src/components/scheduler/index.js +0 -7
  120. package/src/components/scheduler/uses.js +0 -183
  121. package/src/components/select/Select.vue +0 -556
  122. package/src/components/select/index.js +0 -7
  123. package/src/components/select/uses.js +0 -379
  124. package/src/components/slider/Slider.vue +0 -505
  125. package/src/components/slider/index.js +0 -7
  126. package/src/components/slider/uses.js +0 -391
  127. package/src/components/tabPanel/TabPanel.vue +0 -74
  128. package/src/components/tabPanel/index.js +0 -7
  129. package/src/components/tabs/Tabs.vue +0 -517
  130. package/src/components/tabs/index.js +0 -7
  131. package/src/components/textField/TextField.vue +0 -399
  132. package/src/components/textField/index.js +0 -7
  133. package/src/components/timePicker/TimePicker.vue +0 -364
  134. package/src/components/timePicker/index.js +0 -7
  135. package/src/components/toggle/Toggle.vue +0 -115
  136. package/src/components/toggle/index.js +0 -7
  137. package/src/components/tree/Tree.vue +0 -338
  138. package/src/components/tree/TreeNode.vue +0 -293
  139. package/src/components/tree/index.js +0 -7
  140. package/src/components/treeGrid/TreeGrid.vue +0 -1074
  141. package/src/components/treeGrid/TreeGridNode.vue +0 -349
  142. package/src/components/treeGrid/TreeGridToolbar.vue +0 -35
  143. package/src/components/treeGrid/icon/icon-tree.png +0 -0
  144. package/src/components/treeGrid/index.js +0 -9
  145. package/src/components/treeGrid/style/treeGrid.scss +0 -277
  146. package/src/components/treeGrid/uses.js +0 -1178
  147. package/src/components/window/Window.vue +0 -329
  148. package/src/components/window/index.js +0 -7
  149. package/src/components/window/uses.js +0 -908
  150. package/src/directives/clickoutside.js +0 -90
  151. package/src/main.js +0 -120
  152. package/src/style/components/input.scss +0 -108
  153. package/src/style/functions.scss +0 -3
  154. package/src/style/index.scss +0 -6
  155. package/src/style/lib/fonts/EVUI.eot +0 -0
  156. package/src/style/lib/fonts/EVUI.svg +0 -293
  157. package/src/style/lib/fonts/EVUI.ttf +0 -0
  158. package/src/style/lib/fonts/EVUI.woff +0 -0
  159. package/src/style/lib/icon.css +0 -888
  160. package/src/style/mixins.scss +0 -94
  161. package/src/style/themes.scss +0 -69
  162. package/src/style/variables.scss +0 -22
@@ -1,1629 +0,0 @@
1
- import { getCurrentInstance, nextTick } from 'vue';
2
- import { uniqBy } from 'lodash-es';
3
- import { numberWithComma } from '@/common/utils';
4
-
5
- const ROW_INDEX = 0;
6
- const ROW_CHECK_INDEX = 1;
7
- const ROW_DATA_INDEX = 2;
8
- const ROW_SELECT_INDEX = 3;
9
- const ROW_EXPAND_INDEX = 4;
10
-
11
- export const commonFunctions = () => {
12
- const { props } = getCurrentInstance();
13
- /**
14
- * 해당 컬럼이 사용자 지정 컬럼인지 확인한다.
15
- *
16
- * @param {object} column - 컬럼 정보
17
- * @returns {boolean} 사용자 지정 컬럼 유무
18
- */
19
- const isRenderer = (column = {}) => !!column?.render?.use;
20
- const getComponentName = (type = '') => {
21
- const setUpperCaseFirstStr = str => str.charAt(0).toUpperCase() + str.slice(1);
22
- const rendererStr = 'Renderer';
23
- let typeStr = '';
24
- if (type.indexOf('_') !== -1) {
25
- const typeStrArray = type.split('_');
26
- for (let ix = 0; ix < typeStrArray.length; ix++) {
27
- typeStr += setUpperCaseFirstStr(typeStrArray[ix]);
28
- }
29
- } else {
30
- typeStr = setUpperCaseFirstStr(type);
31
- }
32
- return typeStr + rendererStr;
33
- };
34
- /**
35
- * 데이터 타입에 따라 변환된 데이터을 반환한다.
36
- *
37
- * @param {object} column - 컬럼 정보
38
- * @param {number|string} value - 데이터
39
- * @returns {number|string} 변환된 데이터
40
- */
41
- const getConvertValue = (column, value) => {
42
- let convertValue = column.type === 'number' || column.type === 'float' ? Number(value) : value;
43
-
44
- if (column.type === 'number') {
45
- convertValue = numberWithComma(value);
46
- convertValue = convertValue === false ? value : convertValue;
47
- } else if (column.type === 'float') {
48
- const floatValue = convertValue.toFixed(column.decimal ?? 3);
49
- convertValue = floatValue.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
50
- }
51
-
52
- return convertValue;
53
- };
54
- /**
55
- * 전달받은 필드명과 일치하는 컬럼 인덱스를 반환한다.
56
- *
57
- * @param {string} field - 컬럼 필드명
58
- * @returns {number} 일치한다면 컬럼 인덱스, 일치하지 않는다면 -1
59
- */
60
- const getColumnIndex = field => props.columns.findIndex(column => column.field === field);
61
- const setPixelUnit = (value) => {
62
- let size = value;
63
- const hasPx = size.toString().indexOf('px') >= 0;
64
- const hasPct = size.toString().indexOf('%') >= 0;
65
- if (!hasPx && !hasPct) {
66
- size = `${size}px`;
67
- }
68
- return size;
69
- };
70
-
71
- return {
72
- isRenderer,
73
- getComponentName,
74
- getConvertValue,
75
- getColumnIndex,
76
- setPixelUnit,
77
- };
78
- };
79
-
80
- export const getUpdatedColumns = (stores) => {
81
- const baseColumns = (
82
- stores.movedColumns?.length ? stores.movedColumns : stores.originColumns
83
- ) ?? [];
84
- const filteredColumnsMap = new Map(
85
- (stores.filteredColumns ?? []).map(filtered => [filtered.index, filtered]),
86
- );
87
- return baseColumns.map((column) => {
88
- const filteredColumn = filteredColumnsMap.get(column.index) ?? {};
89
- return {
90
- ...column,
91
- ...filteredColumn,
92
- };
93
- });
94
- };
95
-
96
- export const scrollEvent = (params) => {
97
- const {
98
- scrollInfo,
99
- stores,
100
- elementInfo,
101
- resizeInfo,
102
- pageInfo,
103
- summaryScroll,
104
- getPagingData,
105
- updatePagingInfo,
106
- expandedInfo,
107
- } = params;
108
- /**
109
- * 수직 스크롤의 위치 계산 후 적용한다.
110
- */
111
- const updateVScrollBase = (isScroll) => {
112
- const bodyEl = elementInfo.body;
113
- const rowHeight = resizeInfo.rowHeight;
114
- const expandedRowHeight = expandedInfo.detailRowHeight ?? 0;
115
-
116
- if (bodyEl) {
117
- let store = stores.store;
118
- if (pageInfo.isClientPaging) {
119
- store = getPagingData();
120
- }
121
-
122
- const expandedRowCount = expandedInfo.expandedRows?.length ?? 0;
123
- const expandedRowIndexes = expandedInfo.expandedRows?.map(
124
- row => store.findIndex(data => data[ROW_DATA_INDEX] === row),
125
- ) ?? [];
126
- const totalScrollHeight = store.length * rowHeight + expandedRowCount * expandedRowHeight;
127
-
128
- let firstVisibleIndex = 0;
129
- let scrollTop = 0;
130
-
131
- if (expandedRowCount) {
132
- for (firstVisibleIndex = 0; scrollTop + rowHeight < bodyEl.scrollTop; firstVisibleIndex++) {
133
- if (expandedRowIndexes.includes(firstVisibleIndex)) {
134
- scrollTop += expandedRowHeight;
135
- }
136
- scrollTop += rowHeight;
137
- }
138
- } else {
139
- firstVisibleIndex = Math.floor(bodyEl.scrollTop / rowHeight);
140
- scrollTop = Math.max(firstVisibleIndex, 0) * rowHeight;
141
- }
142
-
143
- if (firstVisibleIndex > store.length - 1) {
144
- firstVisibleIndex = 0;
145
- }
146
-
147
- let rowCount = 0;
148
- let renderRowHeight = 0;
149
-
150
- if (expandedRowCount) {
151
- for (let i = firstVisibleIndex; renderRowHeight <= bodyEl.clientHeight; i++) {
152
- if (expandedRowIndexes.includes(i)) {
153
- renderRowHeight += expandedRowHeight;
154
- }
155
- renderRowHeight += rowHeight;
156
- rowCount += 1;
157
- }
158
- } else {
159
- rowCount = bodyEl.clientHeight > rowHeight
160
- ? Math.ceil(bodyEl.clientHeight / rowHeight) : store.length;
161
- renderRowHeight = rowCount * rowHeight;
162
- }
163
-
164
- const lastVisibleIndex = firstVisibleIndex + rowCount + 1;
165
- const firstIndex = Math.max(firstVisibleIndex, 0);
166
- const lastIndex = lastVisibleIndex;
167
- const tableEl = elementInfo.table;
168
-
169
- stores.viewStore = store.slice(firstIndex, lastIndex);
170
- scrollInfo.hasVerticalScrollBar = rowCount < store.length
171
- || bodyEl.clientHeight < tableEl.clientHeight;
172
- scrollInfo.vScrollTopHeight = scrollTop;
173
- scrollInfo.vScrollBottomHeight = totalScrollHeight - renderRowHeight
174
- - scrollInfo.vScrollTopHeight;
175
- if (isScroll && pageInfo.isInfinite && scrollInfo.vScrollBottomHeight === 0) {
176
- pageInfo.prevPage = pageInfo.currentPage;
177
- pageInfo.currentPage = Math.ceil(lastIndex / pageInfo.perPage) + 1;
178
- pageInfo.startIndex = lastIndex;
179
- updatePagingInfo({ onScrollEnd: true });
180
- }
181
- }
182
- };
183
-
184
- /**
185
- * 고정 높이를 지정하지 않은 rowDetail slot 시에는 가상 스크롤을 적용하지 않는다.
186
- */
187
- const updateVScroll = (isScroll) => {
188
- if (expandedInfo.useRowDetail && !expandedInfo.detailRowHeight) {
189
- let store = stores.store;
190
- if (pageInfo.isClientPaging) {
191
- store = getPagingData();
192
- }
193
- stores.viewStore = [...store];
194
- scrollInfo.vScrollTopHeight = 0;
195
- scrollInfo.vScrollBottomHeight = 0;
196
- } else {
197
- updateVScrollBase(isScroll);
198
- }
199
- };
200
- /**
201
- * 수평 스크롤의 위치 계산 후 적용한다.
202
- */
203
- const updateHScroll = () => {
204
- const headerEl = elementInfo.header;
205
- const bodyEl = elementInfo.body;
206
- const tableEl = elementInfo.table;
207
-
208
- headerEl.scrollLeft = bodyEl.scrollLeft;
209
- summaryScroll.value = bodyEl.scrollLeft;
210
- scrollInfo.hasHorizontalScrollBar = bodyEl.clientWidth < tableEl.clientWidth;
211
- };
212
- /**
213
- * scroll 이벤트를 처리한다.
214
- */
215
- const onScroll = () => {
216
- const bodyEl = elementInfo.body;
217
- const scrollTop = bodyEl.scrollTop;
218
- const scrollLeft = bodyEl.scrollLeft;
219
- const lastTop = scrollInfo.lastScroll.top;
220
- const lastLeft = scrollInfo.lastScroll.left;
221
- const isHorizontal = !(scrollLeft === lastLeft);
222
- const isVertical = !(scrollTop === lastTop);
223
-
224
- if (isVertical && bodyEl?.clientHeight) {
225
- updateVScroll(true);
226
- }
227
-
228
- if (isHorizontal) {
229
- updateHScroll();
230
- }
231
-
232
- scrollInfo.lastScroll.top = scrollTop;
233
- scrollInfo.lastScroll.left = scrollLeft;
234
- };
235
- return { updateVScroll, updateHScroll, onScroll };
236
- };
237
-
238
- export const resizeEvent = (params) => {
239
- const { props, emit } = getCurrentInstance();
240
- const {
241
- resizeInfo,
242
- elementInfo,
243
- checkInfo,
244
- expandedInfo,
245
- stores,
246
- isRenderer,
247
- updateVScroll,
248
- updateHScroll,
249
- contextInfo,
250
- } = params;
251
- /**
252
- * 고정 너비, 스크롤 유무 등에 따른 컬럼 너비를 계산한다.
253
- */
254
- const calculatedColumn = () => {
255
- let columnWidth = resizeInfo.columnWidth;
256
- let remainWidth = 0;
257
- if (resizeInfo.adjust) {
258
- const bodyEl = elementInfo.body;
259
- let elWidth = bodyEl.offsetWidth;
260
- const elHeight = bodyEl.offsetHeight;
261
- const rowHeight = bodyEl.querySelector('tr')?.offsetHeight || resizeInfo.rowHeight;
262
- const scrollWidth = elWidth - bodyEl.clientWidth;
263
-
264
- const result = stores.orderedColumns.reduce((acc, cur) => {
265
- if (cur.hide || cur.hiddenDisplay) {
266
- return acc;
267
- }
268
- if (cur.width) {
269
- acc.totalWidth += cur.width;
270
- } else {
271
- acc.emptyCount++;
272
- }
273
-
274
- return acc;
275
- }, { totalWidth: contextInfo.customContextMenu.length ? 30 : 0, emptyCount: 0 });
276
-
277
- if (rowHeight * props.rows.length > elHeight) {
278
- elWidth -= scrollWidth;
279
- }
280
-
281
- if (checkInfo.useCheckbox.use) {
282
- elWidth -= resizeInfo.minWidth;
283
- }
284
-
285
- if (expandedInfo.useRowDetail) {
286
- elWidth -= resizeInfo.minWidth;
287
- }
288
-
289
- columnWidth = elWidth - result.totalWidth;
290
- if (columnWidth > 0) {
291
- const sharePerEmptyCount = result.emptyCount === 0
292
- ? 0
293
- : Math.floor(columnWidth / result.emptyCount);
294
-
295
- remainWidth = columnWidth - (sharePerEmptyCount * result.emptyCount);
296
- columnWidth = result.emptyCount !== 0
297
- ? sharePerEmptyCount
298
- : columnWidth;
299
- } else {
300
- columnWidth = resizeInfo.columnWidth;
301
- }
302
-
303
- columnWidth = columnWidth < resizeInfo.minWidth ? resizeInfo.minWidth : columnWidth;
304
- resizeInfo.columnWidth = columnWidth;
305
- }
306
-
307
- stores.orderedColumns.forEach((col) => {
308
- const minWidth = isRenderer(col) ? resizeInfo.rendererMinWidth : resizeInfo.minWidth;
309
- if (col.width && col.width < minWidth) {
310
- col.width = minWidth;
311
- }
312
- if (!col.width && !col.hide) {
313
- col.width = columnWidth;
314
- }
315
- });
316
-
317
- if (remainWidth && stores.orderedColumns.length) {
318
- let index = stores.orderedColumns.length - 1;
319
- let lastColumn = stores.orderedColumns[index];
320
-
321
- // orderedColumns에 hiddenDisplay === true 컬럼은 포함되어 있지 않다.
322
- // 하지만 hide === true 컬럼은 포함되어 있다. 그래서 hiddenDisplay 조건은 필요없지만 조건을 추가해서 코드 가독성과 안정성을 높였다.
323
- while (index > 0 && lastColumn && (lastColumn.hide || lastColumn.hiddenDisplay)) {
324
- index -= 1;
325
- lastColumn = stores.orderedColumns[index];
326
- }
327
- if (lastColumn) {
328
- lastColumn.width += remainWidth;
329
- }
330
- }
331
- };
332
- /**
333
- * grid resize 이벤트를 처리한다.
334
- */
335
- const onResize = () => {
336
- const propColumnsMap = new Map(props.columns.map(col => [col.field, col.width]));
337
- nextTick(() => {
338
- if (resizeInfo.adjust) {
339
- stores.orderedColumns.forEach((column) => {
340
- const item = column;
341
-
342
- if (!item.resized) {
343
- item.width = propColumnsMap.get(item.field) ?? 0;
344
- }
345
-
346
- return item;
347
- }, this);
348
- }
349
-
350
- calculatedColumn();
351
- if (elementInfo.body?.clientHeight) {
352
- updateVScroll();
353
- }
354
- if (elementInfo.body?.clientWidth) {
355
- updateHScroll();
356
- }
357
- });
358
- };
359
-
360
- const onShow = (isVisible) => {
361
- if (isVisible) {
362
- onResize();
363
- }
364
- };
365
-
366
- /**
367
- * column resize 이벤트를 처리한다.
368
- *
369
- * @param {number} columnIndex - 컬럼 인덱스
370
- * @param {object} event - 이벤트 객체
371
- */
372
- const onColumnResize = (columnIndex, event) => {
373
- event.preventDefault();
374
- const headerEl = elementInfo.header;
375
- const bodyEl = elementInfo.body;
376
- const headerLeft = headerEl.getBoundingClientRect().left;
377
- const columnEl = headerEl.querySelector(`li[data-index="${columnIndex}"]`);
378
- const minWidth = isRenderer(stores.orderedColumns[columnIndex])
379
- ? resizeInfo.rendererMinWidth : resizeInfo.minWidth;
380
- const columnRect = columnEl.getBoundingClientRect();
381
- const resizeLineEl = elementInfo.resizeLine;
382
- const minLeft = columnRect.left - headerLeft + minWidth;
383
- const startLeft = columnRect.right - headerLeft;
384
- const startMouseLeft = event.clientX;
385
- const startColumnLeft = columnRect.left - headerLeft;
386
-
387
- bodyEl.style.overflow = 'auto';
388
- resizeLineEl.style.left = `${startLeft}px`;
389
-
390
- resizeInfo.showResizeLine = true;
391
-
392
- const handleMouseMove = (evt) => {
393
- const deltaLeft = evt.clientX - startMouseLeft;
394
- const proxyLeft = startLeft + deltaLeft;
395
- const resizeWidth = Math.max(minLeft, proxyLeft);
396
-
397
- resizeLineEl.style.left = `${resizeWidth}px`;
398
- };
399
-
400
- const handleMouseUp = () => {
401
- const destLeft = parseInt(resizeLineEl.style.left, 10);
402
- const changedWidth = destLeft - startColumnLeft;
403
-
404
- if (stores.orderedColumns[columnIndex]) {
405
- stores.orderedColumns[columnIndex].width = changedWidth;
406
- stores.orderedColumns[columnIndex].resized = true;
407
- }
408
-
409
- resizeInfo.showResizeLine = false;
410
- document.removeEventListener('mousemove', handleMouseMove);
411
- onResize();
412
-
413
- const updatedColumns = getUpdatedColumns(stores);
414
- emit('resize-column', {
415
- column: stores.orderedColumns[columnIndex],
416
- columns: updatedColumns,
417
- });
418
- emit('change-column-info', {
419
- type: 'resize',
420
- columns: updatedColumns,
421
- });
422
- };
423
-
424
- document.addEventListener('mousemove', handleMouseMove);
425
- document.addEventListener('mouseup', handleMouseUp, { once: true });
426
- };
427
- return { calculatedColumn, onResize, onShow, onColumnResize };
428
- };
429
-
430
- export const clickEvent = (params) => {
431
- const { emit } = getCurrentInstance();
432
- const { selectInfo, stores } = params;
433
- const getClickedRowData = (event, row) => {
434
- const tagName = event.target.tagName?.toLowerCase();
435
- let cellInfo = {};
436
- if (tagName === 'td') {
437
- cellInfo = event.target.dataset;
438
- } else {
439
- cellInfo = event.target.parentNode.dataset;
440
- }
441
- return {
442
- event,
443
- rowData: row[ROW_DATA_INDEX],
444
- rowIndex: row[ROW_INDEX],
445
- cellName: cellInfo.name,
446
- cellIndex: cellInfo.index,
447
- };
448
- };
449
- /**
450
- * row click 이벤트를 처리한다.
451
- *
452
- * @param {object} event - 이벤트 객체
453
- * @param {array} row - row 데이터
454
- */
455
- let clickTimer = null;
456
- let lastIndex = -1;
457
- const onRowClick = (event, row, isRight) => {
458
- if (event.target.parentElement.classList?.contains('row-checkbox-input')) {
459
- return false;
460
- }
461
- const isContextmenu = !!event.target.closest('td')?.classList?.contains('row-contextmenu');
462
- const onMultiSelectByKey = (keyType, selected, selectedRow) => {
463
- if (keyType === 'shift') {
464
- const rowIndex = row[ROW_INDEX];
465
- if (lastIndex > -1) {
466
- for (
467
- let i = Math.min(rowIndex, lastIndex);
468
- i <= Math.max(rowIndex, lastIndex);
469
- i++
470
- ) {
471
- if (!selected) {
472
- stores.originStore[i][ROW_SELECT_INDEX] = true;
473
- if (lastIndex !== i) {
474
- selectInfo.selectedRow.push(stores.originStore[i][ROW_DATA_INDEX]);
475
- }
476
- } else {
477
- stores.originStore[i][ROW_SELECT_INDEX] = false;
478
- const deselectedIndex = selectInfo.selectedRow
479
- .indexOf(stores.originStore[i][ROW_DATA_INDEX]);
480
- if (deselectedIndex > -1) {
481
- selectInfo.selectedRow.splice(deselectedIndex, 1);
482
- }
483
- }
484
- }
485
- }
486
- } else if (keyType === 'ctrl') {
487
- if (!selected) {
488
- selectInfo.selectedRow.push(selectedRow);
489
- } else {
490
- selectInfo.selectedRow.splice(selectInfo.selectedRow.indexOf(row[ROW_DATA_INDEX]), 1);
491
- }
492
- }
493
- };
494
-
495
- if (clickTimer) {
496
- clearTimeout(clickTimer);
497
- }
498
- clickTimer = setTimeout(() => {
499
- if (selectInfo.useSelect) {
500
- const rowData = row[ROW_DATA_INDEX];
501
- const selected = row[ROW_SELECT_INDEX];
502
- row[ROW_SELECT_INDEX] = !row[ROW_SELECT_INDEX];
503
- let keyType = '';
504
- if (event.shiftKey) {
505
- keyType = 'shift';
506
- } else if (event.ctrlKey) {
507
- keyType = 'ctrl';
508
- }
509
-
510
- if (selectInfo.multiple && keyType) { // multi select
511
- onMultiSelectByKey(keyType, selected, rowData);
512
- } else if (isRight || isContextmenu) {
513
- selectInfo.selectedRow = [...selectInfo.selectedRow];
514
- if (!selectInfo.selectedRow.includes(rowData)) {
515
- selectInfo.selectedRow = [rowData];
516
- }
517
- } else if (selected) { // single select
518
- selectInfo.selectedRow = [];
519
- } else {
520
- selectInfo.selectedRow = [rowData];
521
- }
522
- lastIndex = row[ROW_INDEX];
523
- emit('update:selected', selectInfo.selectedRow);
524
- emit('click-row', getClickedRowData(event, row));
525
- }
526
- }, 100);
527
- return true;
528
- };
529
- /**
530
- * row dblclick 이벤트를 처리한다.
531
- *
532
- * @param {object} event - 이벤트 객체
533
- * @param {array} row - row 데이터
534
- */
535
- const onRowDblClick = (event, row) => {
536
- if (clickTimer) {
537
- clearTimeout(clickTimer);
538
- }
539
- emit('dblclick-row', getClickedRowData(event, row));
540
- };
541
- return { onRowClick, onRowDblClick };
542
- };
543
-
544
- export const checkEvent = (params) => {
545
- const { checkInfo, stores, pageInfo, getPagingData } = params;
546
- const { props, emit } = getCurrentInstance();
547
- /**
548
- * row에 대한 체크 상태를 해제한다.
549
- *
550
- * @param {array} row - row 데이터
551
- */
552
- const unCheckedRow = (row) => {
553
- const index = stores.originStore.findIndex(
554
- item => item[ROW_DATA_INDEX] === row[ROW_DATA_INDEX]);
555
-
556
- if (index !== -1) {
557
- stores.originStore[index][ROW_CHECK_INDEX] = row[ROW_CHECK_INDEX];
558
- }
559
- };
560
- /**
561
- * checkbox click 이벤트를 처리한다.
562
- *
563
- * @param {object} event - 이벤트 객체
564
- * @param {array} row - row 데이터
565
- */
566
- const onCheck = (event, row) => {
567
- if (checkInfo.useCheckbox.mode === 'single' && checkInfo.prevCheckedRow.length) {
568
- checkInfo.prevCheckedRow = [];
569
- unCheckedRow(checkInfo.prevCheckedRow);
570
- }
571
-
572
- if (row[ROW_CHECK_INDEX]) {
573
- if (checkInfo.useCheckbox.mode === 'single') {
574
- checkInfo.checkedRows = [row[ROW_DATA_INDEX]];
575
- } else {
576
- checkInfo.checkedRows.push(row[ROW_DATA_INDEX]);
577
- }
578
- let store = stores.store;
579
- if (pageInfo.isClientPaging) {
580
- store = getPagingData();
581
- }
582
-
583
- const isAllChecked = store
584
- .filter(rowData => !props.uncheckable.includes(rowData[ROW_DATA_INDEX]))
585
- .filter(rowData => !props.disabledRows.includes(rowData[ROW_DATA_INDEX]))
586
- .every(d => d[ROW_CHECK_INDEX]);
587
- if (store.length && isAllChecked) {
588
- checkInfo.isHeaderChecked = true;
589
- }
590
- checkInfo.isHeaderIndeterminate = store.length && !isAllChecked;
591
- } else {
592
- if (checkInfo.useCheckbox.mode === 'single') {
593
- checkInfo.checkedRows = [];
594
- } else {
595
- checkInfo.checkedRows.splice(checkInfo.checkedRows.indexOf(row[ROW_DATA_INDEX]), 1);
596
- }
597
- checkInfo.isHeaderChecked = false;
598
- checkInfo.isHeaderIndeterminate = !!(stores.store.length && checkInfo.checkedRows.length);
599
- }
600
- checkInfo.prevCheckedRow = row.slice();
601
- emit('update:checked', checkInfo.checkedRows);
602
- emit('check-row', event, row[ROW_INDEX], row[ROW_DATA_INDEX]);
603
- };
604
- /**
605
- * all checkbox click 이벤트를 처리한다.
606
- *
607
- * @param {object} event - 이벤트 객체
608
- */
609
- const onCheckAll = (event) => {
610
- const isHeaderChecked = checkInfo.isHeaderChecked;
611
- let store = stores.store;
612
- if (pageInfo.isClientPaging) {
613
- store = getPagingData();
614
- }
615
- store.forEach((row) => {
616
- const uncheckable = props.uncheckable.includes(row[ROW_DATA_INDEX])
617
- || props.disabledRows.includes(row[ROW_DATA_INDEX]);
618
- if (isHeaderChecked) {
619
- if (!checkInfo.checkedRows.includes(row[ROW_DATA_INDEX]) && !uncheckable) {
620
- checkInfo.checkedRows.push(row[ROW_DATA_INDEX]);
621
- }
622
- } else {
623
- checkInfo.checkedRows.splice(checkInfo.checkedRows.indexOf(row[ROW_DATA_INDEX]), 1);
624
- }
625
-
626
- if (!uncheckable) {
627
- row[ROW_CHECK_INDEX] = isHeaderChecked;
628
- }
629
- });
630
- checkInfo.isHeaderIndeterminate = false;
631
- emit('update:checked', checkInfo.checkedRows);
632
- emit('check-all', event, checkInfo.checkedRows);
633
- };
634
- return { onCheck, onCheckAll };
635
- };
636
-
637
- export const expandEvent = (params) => {
638
- const { expandedInfo } = params;
639
- const { emit } = getCurrentInstance();
640
-
641
- /**
642
- * expand click 이벤트를 처리한다.
643
- *
644
- * @param {object} event - 이벤트 객체
645
- * @param {array} row - row 데이터
646
- */
647
- const onExpanded = (event, row) => {
648
- const data = row[ROW_DATA_INDEX];
649
- const index = expandedInfo.expandedRows.indexOf(data);
650
- if (index === -1) {
651
- expandedInfo.expandedRows.push(data);
652
- } else {
653
- expandedInfo.expandedRows.splice(index, 1);
654
- }
655
- row[ROW_EXPAND_INDEX] = !row[ROW_EXPAND_INDEX];
656
- emit('update:expanded', expandedInfo.expandedRows);
657
- emit('expand-row', event, row[ROW_DATA_INDEX], row[ROW_EXPAND_INDEX], row[ROW_INDEX]);
658
- };
659
-
660
- return {
661
- onExpanded,
662
- };
663
- };
664
-
665
- export const sortEvent = (params) => {
666
- const { sortInfo, stores, updatePagingInfo } = params;
667
- const { emit } = getCurrentInstance();
668
-
669
- const getDefaultSortType = (includeInit = true) => (includeInit ? ['asc', 'desc', 'init'] : ['asc', 'desc']);
670
- function OrderQueue() {
671
- this.orders = getDefaultSortType();
672
- this.dequeue = () => this.orders.shift();
673
- this.enqueue = o => this.orders.push(o);
674
- }
675
-
676
- const setSortOptionToOrderedColumns = (column, sortType = 'init') => {
677
- stores.orderedColumns.forEach((orderedColumn) => {
678
- if (orderedColumn.index === column?.index && sortType) {
679
- orderedColumn.sortOption = { sortType };
680
- } else {
681
- orderedColumn.sortOption = { sortType: 'init' };
682
- }
683
- });
684
- };
685
-
686
- const initializeHiddenColumnsSortType = () => {
687
- const hiddenColumns = stores.originColumns.filter(col => col.hiddenDisplay || col.hide);
688
- if (hiddenColumns.length) {
689
- hiddenColumns.forEach((col) => {
690
- col.sortOption = { sortType: 'init' };
691
- });
692
- }
693
- };
694
-
695
- const order = new OrderQueue();
696
- const setSortInfo = (column, emitTriggered = true) => {
697
- const { sortType } = column?.sortOption || {};
698
- sortInfo.sortColumn = column;
699
- sortInfo.sortField = column?.field;
700
- sortInfo.sortOrder = sortType;
701
- sortInfo.isSorting = !!(sortType);
702
-
703
- if (emitTriggered) {
704
- setSortOptionToOrderedColumns(column, sortType);
705
-
706
- emit('change-column-info', {
707
- type: 'sort',
708
- columns: getUpdatedColumns(stores),
709
- });
710
- }
711
- };
712
-
713
- /**
714
- * sort 이벤트를 처리한다.
715
- *
716
- * @param {object} column - 컬럼 정보
717
- * @param {string} sortOrder - 정렬 순서
718
- */
719
- const onSort = (column, sortOrder) => {
720
- const sortable = column.sortable === undefined ? true : column.sortable;
721
- if (sortable) {
722
- sortInfo.sortColumn = column;
723
- if (sortInfo.sortField !== column?.field) {
724
- order.orders = getDefaultSortType();
725
- sortInfo.sortField = column?.field;
726
- }
727
- if (sortOrder) {
728
- order.orders = getDefaultSortType();
729
- if (sortOrder === 'desc') {
730
- sortInfo.sortOrder = order.dequeue();
731
- order.enqueue(sortInfo.sortOrder);
732
- }
733
- }
734
- sortInfo.sortOrder = order.dequeue();
735
- order.enqueue(sortInfo.sortOrder);
736
-
737
- sortInfo.isSorting = true;
738
- updatePagingInfo({ onSort: true });
739
-
740
- initializeHiddenColumnsSortType();
741
- setSortOptionToOrderedColumns(column, sortInfo.sortOrder);
742
-
743
- const updatedColumInfo = getUpdatedColumns(stores);
744
- emit('sort-column', {
745
- field: sortInfo.sortField,
746
- order: sortInfo.sortOrder,
747
- column: sortInfo.sortColumn,
748
- columns: updatedColumInfo,
749
- });
750
-
751
- emit('change-column-info', {
752
- type: 'sort',
753
- columns: updatedColumInfo,
754
- });
755
- }
756
- };
757
- /**
758
- * 설정값에 따라 해당 컬럼 데이터에 대해 정렬한다.
759
- */
760
- const setSort = () => {
761
- const { field, index } = sortInfo.sortColumn || {};
762
- const customSetAsc = sortInfo.sortFunction?.[field] ?? null;
763
- const setDesc = (a, b) => (a > b ? -1 : 1);
764
- const setAsc = (a, b) => (a < b ? -1 : 1);
765
- const numberSetDesc = (a, b) => ((a === null) - (b === null) || Number(b) - Number(a));
766
- const numberSetAsc = (a, b) => ((a === null) - (b === null) || Number(a) - Number(b));
767
- if (sortInfo.sortOrder === 'init' || (!sortInfo.sortField && !sortInfo.isSorting)) {
768
- stores.store.sort((a, b) => {
769
- if (typeof a[ROW_INDEX] === 'number') {
770
- return setAsc(a[ROW_INDEX], b[ROW_INDEX]);
771
- }
772
- return 0;
773
- });
774
- return;
775
- }
776
- const type = sortInfo.sortColumn.type || 'string';
777
- const sortFn = sortInfo.sortOrder === 'desc' ? setDesc : setAsc;
778
- const numberSortFn = sortInfo.sortOrder === 'desc' ? numberSetDesc : numberSetAsc;
779
- const getColumnValue = (a, b) => {
780
- let aCol = a[ROW_DATA_INDEX][index];
781
- let bCol = b[ROW_DATA_INDEX][index];
782
- if (a[ROW_DATA_INDEX][index] && typeof a[ROW_DATA_INDEX][index] === 'object') {
783
- aCol = a[ROW_DATA_INDEX][index][stores.originColumns[index]?.field];
784
- bCol = b[ROW_DATA_INDEX][index][stores.originColumns[index]?.field];
785
- }
786
- return { aCol, bCol };
787
- };
788
-
789
- if (customSetAsc) {
790
- stores.store.sort((a, b) => {
791
- /*
792
- 배열 및 객체일 경우 customAscFunc 사용자에게 데이터 전처리를 맡길 수 있게끔
793
- getColumnValue 사용 안함
794
- */
795
- const aCol = a[ROW_DATA_INDEX][index];
796
- const bCol = b[ROW_DATA_INDEX][index];
797
- const compareAscReturn = customSetAsc(aCol, bCol);
798
- return sortInfo.sortOrder === 'desc' ? -compareAscReturn : compareAscReturn;
799
- });
800
- return;
801
- }
802
- switch (type) {
803
- case 'string':
804
- stores.store.sort((a, b) => {
805
- let { aCol, bCol } = getColumnValue(a, b);
806
- if ((!aCol || typeof aCol === 'string') && (!bCol || typeof bCol === 'string')) {
807
- aCol = aCol || '';
808
- bCol = bCol || '';
809
- const lowerA = aCol.toLowerCase();
810
- const lowerB = bCol.toLowerCase();
811
- if (aCol !== bCol && lowerA === lowerB) {
812
- const diffIndex = Array.from(aCol).findIndex((char, idx) => char !== bCol[idx]);
813
- return sortFn(aCol[diffIndex], bCol[diffIndex]);
814
- }
815
- return sortFn(lowerA, lowerB);
816
- }
817
- return 0;
818
- });
819
- break;
820
- case 'stringNumber':
821
- stores.store.sort((a, b) => {
822
- let { aCol, bCol } = getColumnValue(a, b);
823
- if (!aCol || typeof aCol === 'string' || typeof aCol === 'number') {
824
- aCol = aCol === '' ? null : aCol;
825
- bCol = bCol === '' ? null : bCol;
826
- return numberSortFn(aCol ?? null, bCol ?? null);
827
- }
828
- return 0;
829
- });
830
- break;
831
- default:
832
- stores.store.sort((a, b) => {
833
- const { aCol, bCol } = getColumnValue(a, b);
834
- if (!aCol || typeof aCol === 'number' || typeof aCol === 'boolean') {
835
- return numberSortFn(aCol ?? null, bCol ?? null);
836
- }
837
- return 0;
838
- });
839
- break;
840
- }
841
- };
842
-
843
- const getSortTarget = () => stores.orderedColumns?.find(
844
- column => column?.sortOption && getDefaultSortType(false).includes(column.sortOption.sortType),
845
- );
846
- const hasSortTarget = () => !!getSortTarget();
847
-
848
- return { onSort, getSortTarget, setSort, setSortInfo, hasSortTarget };
849
- };
850
-
851
- export const filterEvent = (params) => {
852
- const { props } = getCurrentInstance();
853
- const {
854
- columnSettingInfo,
855
- filterInfo,
856
- stores,
857
- checkInfo,
858
- pageInfo,
859
- getConvertValue,
860
- updateVScroll,
861
- getPagingData,
862
- updatePagingInfo,
863
- getColumnIndex,
864
- } = params;
865
- /**
866
- * 헤더 체크박스 상태를 체크한다.
867
- *
868
- * @param {array} rowData - row 데이터
869
- */
870
- const setHeaderCheckboxByFilter = (rowData) => {
871
- let checkedCount = 0;
872
- rowData.forEach((row) => {
873
- const isChecked = checkInfo.checkedRows.includes(row[ROW_DATA_INDEX]);
874
- row[ROW_CHECK_INDEX] = isChecked;
875
- checkedCount += isChecked ? 1 : 0;
876
- });
877
- if (rowData.length) {
878
- checkInfo.isHeaderChecked = rowData.length === checkedCount;
879
- checkInfo.isHeaderIndeterminate = (rowData.length !== checkedCount) && checkedCount > 0;
880
- checkInfo.isHeaderUncheckable = rowData
881
- .every(row => props.uncheckable.includes(row[ROW_DATA_INDEX])
882
- || props.disabledRows.includes(row[ROW_DATA_INDEX]));
883
- }
884
- };
885
- /**
886
- * 전달받은 문자열 내 해당 키워드가 존재하는지 확인한다.
887
- *
888
- * @param {string} conditionValue - 검색 키워드
889
- * @param {string} value - 기준 문자열
890
- * @param {string} pos - 시작, 끝나는 문자열
891
- * @returns {boolean} 문자열 내 키워드 존재 유무
892
- */
893
- const findLike = (conditionValue, value, pos) => {
894
- if (typeof conditionValue !== 'string' || value === null) {
895
- return false;
896
- }
897
- const baseValueLower = value?.toLowerCase();
898
- const conditionValueLower = conditionValue?.toLowerCase();
899
- let result = baseValueLower.includes(conditionValueLower);
900
- if (pos) {
901
- if (pos === 'start') {
902
- result = baseValueLower.startsWith(conditionValueLower);
903
- } else if (pos === 'end') {
904
- result = baseValueLower.endsWith(conditionValueLower);
905
- }
906
- }
907
- return result;
908
- };
909
- /**
910
- * 필터 조건에 따라 문자열을 확인한다.
911
- *
912
- * @param {array} item - row 데이터
913
- * @param {object} condition - 필터 정보
914
- * @returns {boolean} 확인 결과
915
- */
916
- const stringFilter = (item, condition) => {
917
- const comparison = condition.comparison;
918
- const conditionValue = condition.value;
919
- let value = item[ROW_DATA_INDEX][condition.index];
920
- if (value || value === 0) {
921
- value = `${item[ROW_DATA_INDEX][condition.index]}`;
922
- }
923
- let result;
924
- if (comparison === '=') {
925
- result = conditionValue?.toLowerCase() === value?.toLowerCase();
926
- } else if (comparison === '!=') {
927
- result = conditionValue?.toLowerCase() !== value?.toLowerCase();
928
- } else if (comparison === '%s%') {
929
- result = findLike(conditionValue, value);
930
- } else if (comparison === 'notLike') {
931
- result = !findLike(conditionValue, value);
932
- } else if (comparison === 's%') {
933
- result = findLike(conditionValue, value, 'start');
934
- } else if (comparison === '%s') {
935
- result = findLike(conditionValue, value, 'end');
936
- } else if (comparison === 'isEmpty') {
937
- result = value === undefined || value === null || value === '';
938
- } else if (comparison === 'isNotEmpty') {
939
- result = !!value;
940
- }
941
-
942
- return result;
943
- };
944
- /**
945
- * 필터 조건에 따라 숫자를 확인한다.
946
- *
947
- * @param {array} item - row 데이터
948
- * @param {object} condition - 필터 정보
949
- * @param {string} columnType - 데이터 유형
950
- * @returns {boolean} 확인 결과
951
- */
952
- const numberFilter = (item, condition, columnType) => {
953
- const comparison = condition.comparison;
954
- const conditionValue = Number(condition.value.replace(/,/g, '')); // 콤마 제거
955
- let value = Number(item[ROW_DATA_INDEX][condition.index]);
956
- let result;
957
- if (columnType === 'float') {
958
- value = Number(value.toFixed(3));
959
- }
960
-
961
- if (comparison === '=') {
962
- result = value === conditionValue;
963
- } else if (comparison === '>') {
964
- result = value > conditionValue;
965
- } else if (comparison === '<') {
966
- result = value < conditionValue;
967
- } else if (comparison === '<=') {
968
- result = value <= conditionValue;
969
- } else if (comparison === '>=') {
970
- result = value >= conditionValue;
971
- } else if (comparison === '!=') {
972
- result = value !== conditionValue;
973
- } else if (comparison === 'isEmpty') {
974
- result = value === undefined || value === null || isNaN(value);
975
- } else if (comparison === 'isNotEmpty') {
976
- result = !!value || value === 0;
977
- }
978
-
979
- return result;
980
- };
981
- const booleanFilter = (item, condition) => {
982
- const comparison = condition.comparison;
983
- const conditionValue = condition.value;
984
- const value = `${item[ROW_DATA_INDEX][condition.index]}`;
985
- let result;
986
-
987
- if (comparison === '=') {
988
- result = value === conditionValue;
989
- }
990
-
991
- return result;
992
- };
993
- /**
994
- * 필터 조건이 적용된 데이터를 반환한다.
995
- *
996
- * @param {array} data - row 데이터
997
- * @param {string} columnType - 데이터 유형
998
- * @param {object} condition - 필터 정보
999
- * @returns {boolean} 확인 결과
1000
- */
1001
- const getFilteringData = (data, columnType, condition) => {
1002
- let filterFn = columnType === 'string' || columnType === 'stringNumber'
1003
- ? stringFilter : numberFilter;
1004
- if (columnType === 'boolean') {
1005
- filterFn = booleanFilter;
1006
- }
1007
- return data.filter(row => filterFn(row, condition, columnType)) || [];
1008
- };
1009
- /**
1010
- * 전체 데이터에서 설정된 필터 적용 후 결과를 filterStore 에 저장한다.
1011
- */
1012
- const setFilter = () => {
1013
- const filteringItemsByColumn = filterInfo.filteringItemsByColumn;
1014
- const fields = Object.keys(filteringItemsByColumn);
1015
- const originStore = stores.originStore;
1016
- let filterStore = [];
1017
- let filteredOnce = false;
1018
- let prevStore = [];
1019
-
1020
- fields.forEach((field, idx) => {
1021
- const filters = filteringItemsByColumn[field];
1022
- const index = getColumnIndex(field);
1023
- const columnType = props.columns[index].type;
1024
- const OR = filterInfo.columnOperator === 'or';
1025
- const AND = idx > 0 && filterInfo.columnOperator === 'and';
1026
-
1027
- filters.forEach((item, ix) => {
1028
- if (!filterStore.length && !filteredOnce) {
1029
- filterStore = getFilteringData(originStore, columnType, {
1030
- ...item,
1031
- index,
1032
- });
1033
- } else if (AND && item.operator === 'or') {
1034
- if (ix > 0) {
1035
- filterStore.push(...getFilteringData(prevStore, columnType, {
1036
- ...item,
1037
- index,
1038
- }));
1039
- } else { // ix === 0
1040
- filterStore = getFilteringData(prevStore, columnType, {
1041
- ...item,
1042
- index,
1043
- });
1044
- }
1045
- } else if ((ix === 0 && OR) || (ix !== 0 && item.operator === 'or')) {
1046
- filterStore.push(...getFilteringData(originStore, columnType, {
1047
- ...item,
1048
- index,
1049
- }));
1050
- } else {
1051
- filterStore = getFilteringData(filterStore, columnType, {
1052
- ...item,
1053
- index,
1054
- });
1055
- }
1056
- filteredOnce = true;
1057
- });
1058
- prevStore = JSON.parse(JSON.stringify(filterStore));
1059
- });
1060
-
1061
- if (!filteredOnce) {
1062
- stores.filterStore = originStore;
1063
- } else {
1064
- stores.filterStore = uniqBy(filterStore, JSON.stringify);
1065
- }
1066
- };
1067
-
1068
- let searchTimer = null;
1069
- const onSearch = (searchWord) => {
1070
- if (searchTimer) {
1071
- clearTimeout(searchTimer);
1072
- }
1073
- searchTimer = setTimeout(() => {
1074
- filterInfo.isSearch = false;
1075
- filterInfo.searchWord = searchWord;
1076
- if (searchWord) {
1077
- stores.searchStore = stores.store.filter((row) => {
1078
- let isShow = false;
1079
- const rowData = columnSettingInfo.isFilteringColumn ? row[ROW_DATA_INDEX]
1080
- .filter((data, idx) => columnSettingInfo.visibleColumnIdx
1081
- .includes(idx)) : row[ROW_DATA_INDEX];
1082
-
1083
- for (let ix = 0; ix < stores.orderedColumns.length; ix++) {
1084
- const column = stores.orderedColumns[ix] || {};
1085
- let columnValue = rowData[column.index] ?? null;
1086
- column.type = column.type || 'string';
1087
- if (columnValue !== null) {
1088
- if (columnValue instanceof Array) {
1089
- columnValue = JSON.stringify(columnValue);
1090
- } else if (typeof columnValue === 'object') {
1091
- columnValue = columnValue[column.field];
1092
- }
1093
- if (!column.hide && (column?.searchable === undefined || column?.searchable)) {
1094
- columnValue = getConvertValue(column, columnValue).toString();
1095
- isShow = columnValue.toLowerCase().includes(searchWord.toString().toLowerCase());
1096
- if (isShow) {
1097
- break;
1098
- }
1099
- }
1100
- }
1101
- }
1102
- return isShow;
1103
- });
1104
- filterInfo.isSearch = true;
1105
- }
1106
- setHeaderCheckboxByFilter(stores.store);
1107
- if (!searchWord && pageInfo.isClientPaging && pageInfo.prevPage) {
1108
- pageInfo.currentPage = 1;
1109
- stores.pagingStore = getPagingData();
1110
- }
1111
-
1112
- updatePagingInfo({ onSearch: true });
1113
- updateVScroll();
1114
- }, 500);
1115
- };
1116
- return { onSearch, setFilter, setHeaderCheckboxByFilter };
1117
- };
1118
-
1119
- export const contextMenuEvent = (params) => {
1120
- const {
1121
- contextInfo,
1122
- stores,
1123
- selectInfo,
1124
- onSort,
1125
- filterInfo,
1126
- useGridSetting,
1127
- columnSettingInfo,
1128
- setColumnHidden,
1129
- } = params;
1130
- /**
1131
- * 컨텍스트 메뉴를 설정한다.
1132
- *
1133
- * @param {object} event - 이벤트 객체
1134
- */
1135
- let contextmenuTimer = null;
1136
- const { emit } = getCurrentInstance();
1137
- const setContextMenu = (e) => {
1138
- if (contextmenuTimer) {
1139
- clearTimeout(contextmenuTimer);
1140
- }
1141
- const menuItems = [];
1142
- contextmenuTimer = setTimeout(() => {
1143
- if (contextInfo.customContextMenu.length) {
1144
- const customItems = contextInfo.customContextMenu.map(
1145
- (item) => {
1146
- const menuItem = item;
1147
- if (menuItem.validate) {
1148
- menuItem.disabled = !menuItem.validate(menuItem.itemId, selectInfo.selectedRow);
1149
- }
1150
-
1151
- menuItem.selectedRow = selectInfo.selectedRow ?? [];
1152
- menuItem.contextmenuInfo = selectInfo.contextmenuInfo ?? [];
1153
-
1154
- return menuItem;
1155
- });
1156
-
1157
- menuItems.push(...customItems);
1158
- }
1159
-
1160
- contextInfo.contextMenuItems = menuItems;
1161
- contextInfo.menu.show(e);
1162
- }, 200);
1163
- };
1164
- /**
1165
- * 마우스 우클릭 이벤트를 처리한다.
1166
- *
1167
- * @param {object} e - 이벤트 객체
1168
- */
1169
- const onContextMenu = (e) => {
1170
- e.preventDefault();
1171
- const target = e.target;
1172
- const rowIndex = target.closest('.row')?.dataset?.index;
1173
- let clickedRow = null;
1174
- if (rowIndex) {
1175
- clickedRow = stores.viewStore.find(row => row[ROW_INDEX] === +rowIndex)?.[ROW_DATA_INDEX];
1176
- }
1177
- if (clickedRow) {
1178
- selectInfo.contextmenuInfo = [clickedRow];
1179
- setContextMenu(e);
1180
- }
1181
- };
1182
- /**
1183
- * 컬럼 기능을 수행하는 Contextmenu 를 생성한다.
1184
- *
1185
- * @param {object} event - 이벤트 객체
1186
- * @param {object} column - 컬럼 정보
1187
- */
1188
- const onColumnContextMenu = (event, column) => {
1189
- if (event.target.className === 'column-name') {
1190
- const sortable = column.sortable === undefined ? true : column.sortable;
1191
- const filterable = filterInfo.isFiltering
1192
- && column.filterable === undefined ? true : column.filterable;
1193
- const columnMenuItems = [
1194
- {
1195
- text: contextInfo.columnMenuTextInfo?.ascending ?? 'Ascending',
1196
- iconClass: 'ev-icon-allow2-up',
1197
- disabled: !sortable,
1198
- hidden: contextInfo.hiddenColumnMenuItem?.ascending,
1199
- click: () => onSort(column, 'asc'),
1200
- },
1201
- {
1202
- text: contextInfo.columnMenuTextInfo?.descending ?? 'Descending',
1203
- iconClass: 'ev-icon-allow2-down',
1204
- disabled: !sortable,
1205
- hidden: contextInfo.hiddenColumnMenuItem?.descending,
1206
- click: () => onSort(column, 'desc'),
1207
- },
1208
- {
1209
- text: contextInfo.columnMenuTextInfo?.filter ?? 'Filter',
1210
- iconClass: 'ev-icon-filter-list',
1211
- click: () => {
1212
- const docWidth = document.documentElement.clientWidth;
1213
- const clientX = contextInfo.columnMenu.menuStyle.clientX;
1214
- const pageX = contextInfo.columnMenu.menuStyle.pageX;
1215
- const MODAL_WIDTH = 350;
1216
- const isOver = docWidth < clientX + MODAL_WIDTH;
1217
- if (isOver) {
1218
- contextInfo.columnMenu.menuStyle.left = `${pageX - MODAL_WIDTH}px`;
1219
- }
1220
- filterInfo.filterSettingPosition = {
1221
- top: contextInfo.columnMenu.menuStyle.top,
1222
- left: contextInfo.columnMenu.menuStyle.left,
1223
- };
1224
- filterInfo.isShowFilterSetting = true;
1225
- filterInfo.filteringColumn = column;
1226
-
1227
- emit('change-column-info', {
1228
- type: 'filter',
1229
- columns: stores.updatedColumns,
1230
- });
1231
- },
1232
- disabled: !filterable,
1233
- hidden: contextInfo.hiddenColumnMenuItem?.filter || !filterInfo.isFiltering,
1234
- },
1235
- {
1236
- text: contextInfo.columnMenuTextInfo?.hide ?? 'Hide',
1237
- iconClass: 'ev-icon-visibility-off',
1238
- disabled: !useGridSetting.value || stores.orderedColumns.length === 1 || column.fixed,
1239
- hidden: contextInfo.hiddenColumnMenuItem?.hide || !useGridSetting.value,
1240
- click: () => {
1241
- setColumnHidden(column.field);
1242
- emit('change-column-status', {
1243
- columns: stores.updatedColumns,
1244
- });
1245
-
1246
- emit('change-column-info', {
1247
- type: 'display',
1248
- columns: stores.updatedColumns,
1249
- });
1250
- },
1251
- },
1252
- ];
1253
- contextInfo.columnMenuItems = [];
1254
- if (!sortable && !filterable && !useGridSetting.value) {
1255
- return;
1256
- }
1257
- contextInfo.columnMenuItems = columnMenuItems.filter(item => !item.hidden);
1258
- }
1259
- };
1260
- /**
1261
- * 상단 우측의 Grid 옵션에 대한 Contextmenu 를 생성한다.
1262
- *
1263
- * @param {object} e - 이벤트 객체
1264
- */
1265
- const onGridSettingContextMenu = (e) => {
1266
- const { useDefaultColumnSetting, columnSettingTextInfo } = columnSettingInfo;
1267
- const columnListMenu = {
1268
- text: columnSettingTextInfo?.title ?? 'Column List',
1269
- isShowMenu: true,
1270
- click: () => {
1271
- columnSettingInfo.isShowColumnSetting = true;
1272
- contextInfo.isShowMenuOnClick = true;
1273
- },
1274
- };
1275
-
1276
- if (contextInfo.customGridSettingContextMenu.length) {
1277
- contextInfo.gridSettingContextMenuItems = [
1278
- ...contextInfo.customGridSettingContextMenu,
1279
- ];
1280
- }
1281
-
1282
- if (useDefaultColumnSetting) {
1283
- contextInfo.gridSettingContextMenuItems.push(columnListMenu);
1284
- }
1285
- contextInfo.gridSettingMenu.show(e);
1286
- };
1287
-
1288
- return {
1289
- setContextMenu,
1290
- onContextMenu,
1291
- onColumnContextMenu,
1292
- onGridSettingContextMenu,
1293
- };
1294
- };
1295
-
1296
- export const storeEvent = (params) => {
1297
- const { props } = getCurrentInstance();
1298
- const {
1299
- selectInfo,
1300
- checkInfo,
1301
- stores,
1302
- sortInfo,
1303
- elementInfo,
1304
- filterInfo,
1305
- expandedInfo,
1306
- setSort,
1307
- setSortInfo,
1308
- updateVScroll,
1309
- setFilter,
1310
- } = params;
1311
- /**
1312
- * 전달된 데이터를 내부 store 및 속성에 저장한다.
1313
- *
1314
- * @param {array} rows - row 데이터
1315
- * @param {boolean} isMakeIndex - 인덱스 생성 유무
1316
- * @param {boolean} isInit - 초기 setStore 여부
1317
- */
1318
- const setStore = ({ rows, isMakeIndex = true, isInit = false }) => {
1319
- const sortingColumns = stores.orderedColumns.find(
1320
- column => column?.sortOption && ['asc', 'desc'].includes(column.sortOption.sortType),
1321
- );
1322
-
1323
- if (isMakeIndex) {
1324
- const store = [];
1325
- let hasUnChecked = false;
1326
- rows.forEach((row, idx) => {
1327
- const checked = props.checked.includes(row);
1328
- const uncheckable = props.uncheckable.includes(row) || props.disabledRows.includes(row);
1329
- let selected = false;
1330
- if (selectInfo.useSelect) {
1331
- selected = props.selected.includes(row);
1332
- }
1333
- if (!checked && !uncheckable) {
1334
- hasUnChecked = true;
1335
- }
1336
- let expanded = false;
1337
- if (expandedInfo.useRowDetail) {
1338
- expanded = props.expanded.includes(row);
1339
- }
1340
- const disabled = props.disabledRows.includes(row);
1341
- store.push([idx, checked, row, selected, expanded, uncheckable, disabled]);
1342
- });
1343
-
1344
- if (rows.length !== props.checked.length
1345
- && (rows.length === props.uncheckable?.length || rows.length === props.disabledRows?.length)
1346
- ) {
1347
- hasUnChecked = true;
1348
- }
1349
- checkInfo.isHeaderChecked = rows.length > 0 ? !hasUnChecked : false;
1350
- checkInfo.isHeaderIndeterminate = hasUnChecked && !!checkInfo.checkedRows.length;
1351
- checkInfo.isHeaderUncheckable = rows.every(row => props.uncheckable.includes(row)
1352
- || props.disabledRows.includes(row));
1353
- stores.originStore = store;
1354
- }
1355
- if (filterInfo.isFiltering) {
1356
- setFilter();
1357
- }
1358
-
1359
- if (sortingColumns && isInit) {
1360
- setSortInfo(sortingColumns, false);
1361
- }
1362
-
1363
- if (sortInfo.sortField) {
1364
- setSort();
1365
- }
1366
- if (elementInfo.body?.clientHeight) {
1367
- updateVScroll();
1368
- }
1369
- };
1370
- return { setStore };
1371
- };
1372
-
1373
- export const pagingEvent = (params) => {
1374
- const { emit } = getCurrentInstance();
1375
- const {
1376
- stores,
1377
- pageInfo,
1378
- sortInfo,
1379
- filterInfo,
1380
- elementInfo,
1381
- clearCheckInfo,
1382
- } = params;
1383
- const getPagingData = () => {
1384
- const start = (pageInfo.currentPage - 1) * pageInfo.perPage;
1385
- const end = parseInt(start, 10) + parseInt(pageInfo.perPage, 10);
1386
- return stores.store.slice(start, end);
1387
- };
1388
- const updatePagingInfo = (eventName) => {
1389
- emit('page-change', {
1390
- eventName,
1391
- pageInfo: {
1392
- currentPage: pageInfo.currentPage,
1393
- prevPage: pageInfo.prevPage,
1394
- startIndex: pageInfo.startIndex,
1395
- total: pageInfo.pageTotal,
1396
- perPage: pageInfo.perPage,
1397
- },
1398
- sortInfo: {
1399
- field: sortInfo.sortField,
1400
- order: sortInfo.sortOrder,
1401
- },
1402
- searchInfo: {
1403
- searchWord: filterInfo.searchWord,
1404
- searchColumns: stores.orderedColumns
1405
- .filter(c => !c.hide && (c?.searchable === undefined || c?.searchable))
1406
- .map(d => d.field),
1407
- },
1408
- });
1409
- if (pageInfo.isInfinite && (eventName?.onSearch || eventName?.onSort)) {
1410
- pageInfo.currentPage = 1;
1411
- elementInfo.body.scrollTop = 0;
1412
- clearCheckInfo();
1413
- }
1414
- };
1415
- const changePage = (beforeVal) => {
1416
- if (pageInfo.isClientPaging) {
1417
- pageInfo.prevPage = beforeVal;
1418
- if (stores.store.length <= pageInfo.perPage) {
1419
- stores.pagingStore = stores.store;
1420
- } else {
1421
- const start = (pageInfo.currentPage - 1) * pageInfo.perPage;
1422
- const end = parseInt(start, 10) + parseInt(pageInfo.perPage, 10);
1423
- stores.pagingStore = stores.store.slice(start, end);
1424
- elementInfo.body.scrollTop = 0;
1425
- pageInfo.startIndex = start;
1426
- }
1427
- }
1428
- updatePagingInfo({ onChangePage: true });
1429
- };
1430
- return { getPagingData, updatePagingInfo, changePage };
1431
- };
1432
-
1433
- export const columnSettingEvent = (params) => {
1434
- const { props, emit } = getCurrentInstance();
1435
- const {
1436
- stores,
1437
- columnSettingInfo,
1438
- contextInfo,
1439
- onSearch,
1440
- onResize,
1441
- } = params;
1442
-
1443
- const setPositionColumnSetting = (toolbarRef) => {
1444
- if (!columnSettingInfo.isShowColumnSetting) {
1445
- return;
1446
- }
1447
- columnSettingInfo.columnSettingPosition.columnListMenuWidth = 0;
1448
-
1449
- if (contextInfo.gridSettingContextMenuItems.length) {
1450
- // 컨텍스트 메뉴 형태인 경우
1451
- const columnListMenu = contextInfo.gridSettingContextMenuItems.length - 1;
1452
- const columnListMenuRect = contextInfo.gridSettingMenu?.rootMenuList?.$el?.children[0]
1453
- .children[columnListMenu].getBoundingClientRect();
1454
-
1455
- columnSettingInfo.columnSettingPosition.columnListMenuWidth = columnListMenuRect.width;
1456
- columnSettingInfo.columnSettingPosition.top = columnListMenuRect.top;
1457
- columnSettingInfo.columnSettingPosition.left = columnListMenuRect.right;
1458
- } else {
1459
- // 컬럼 리스트만 있는 경우
1460
- const toolbarRefDivRect = toolbarRef?.getBoundingClientRect();
1461
- const toolbarHeight = toolbarRefDivRect?.height;
1462
-
1463
- columnSettingInfo.columnSettingPosition.top = toolbarRefDivRect?.top + toolbarHeight;
1464
- columnSettingInfo.columnSettingPosition.left = toolbarRefDivRect?.right;
1465
- }
1466
- };
1467
-
1468
- const initColumnSettingInfo = () => {
1469
- stores.filteredColumns.length = 0;
1470
- // columnSettingInfo.isShowColumnSetting = false;
1471
- columnSettingInfo.isFilteringColumn = false;
1472
- columnSettingInfo.visibleColumnIdx = [];
1473
- columnSettingInfo.hiddenColumn = '';
1474
- };
1475
- const getBaseColumns = () => {
1476
- if (Array.isArray(stores.movedColumns) && stores.movedColumns.length) {
1477
- return stores.movedColumns;
1478
- }
1479
- return stores.originColumns || [];
1480
- };
1481
- const syncHiddenState = (column, hidden) => {
1482
- if (!column) {
1483
- return;
1484
- }
1485
- column.hiddenDisplay = hidden;
1486
- const originColumn = stores.originColumns?.find(col => col.index === column.index);
1487
- if (originColumn && originColumn !== column) {
1488
- originColumn.hiddenDisplay = hidden;
1489
- }
1490
- if (Array.isArray(stores.movedColumns)) {
1491
- const movedColumn = stores.movedColumns.find(col => col.index === column.index);
1492
- if (movedColumn && movedColumn !== column) {
1493
- movedColumn.hiddenDisplay = hidden;
1494
- }
1495
- }
1496
- };
1497
- const setFilteringColumn = () => {
1498
- columnSettingInfo.visibleColumnIdx = stores.filteredColumns.map(col => col.index);
1499
-
1500
- const originColumnIdx = stores.originColumns.filter(col => (!col.hide || col.hiddenDisplay))
1501
- .map(col => col.index);
1502
- const visibleColumnIdx = columnSettingInfo.visibleColumnIdx;
1503
-
1504
- columnSettingInfo.isFilteringColumn = (visibleColumnIdx.length !== originColumnIdx.length);
1505
-
1506
- // 컬럼을 필터링했을 때, 검색어가 있는 경우 재검색
1507
- if (props.option.searchValue) {
1508
- onSearch(props.option.searchValue);
1509
- }
1510
- onResize();
1511
- };
1512
- const onApplyColumn = (columnNames) => {
1513
- const columns = stores.orderedColumns.filter(col => !col.hide && !col.hiddenDisplay);
1514
- const isSameColumn = columnNames.length === columns.length
1515
- && columns.every(col => columnNames.includes(col.field));
1516
-
1517
- if (isSameColumn) {
1518
- return;
1519
- }
1520
-
1521
- const baseColumns = getBaseColumns();
1522
- const columnNameSet = new Set(columnNames);
1523
- stores.filteredColumns = baseColumns.filter((col) => {
1524
- const shouldShow = columnNameSet.has(col.field) || !col.caption;
1525
- syncHiddenState(col, !shouldShow);
1526
- return shouldShow;
1527
- });
1528
- columnSettingInfo.hiddenColumn = '';
1529
- setFilteringColumn();
1530
- emit('change-column-status', {
1531
- columns: stores.updatedColumns,
1532
- });
1533
-
1534
- emit('change-column-info', {
1535
- type: 'display',
1536
- columns: stores.updatedColumns,
1537
- });
1538
- };
1539
- const setColumnHidden = (val) => {
1540
- const columns = stores.orderedColumns.filter(col => !col.hide && !col.hiddenDisplay);
1541
-
1542
- if (columns.length === 1) {
1543
- return;
1544
- }
1545
- stores.filteredColumns = columns
1546
- .filter((col) => {
1547
- const shouldHide = col.field === val;
1548
- syncHiddenState(col, shouldHide);
1549
- return !shouldHide;
1550
- });
1551
- const baseColumns = getBaseColumns();
1552
- baseColumns.forEach((col) => {
1553
- if (col.field === val) {
1554
- syncHiddenState(col, true);
1555
- }
1556
- });
1557
- columnSettingInfo.hiddenColumn = val;
1558
- setFilteringColumn();
1559
- };
1560
-
1561
- return {
1562
- setPositionColumnSetting,
1563
- initColumnSettingInfo,
1564
- onApplyColumn,
1565
- setColumnHidden,
1566
- };
1567
- };
1568
-
1569
- export const dragEvent = ({ stores }) => {
1570
- const { emit } = getCurrentInstance();
1571
- const buildMovedColumns = (visibleColumns) => {
1572
- const baseColumns = (stores.movedColumns?.length
1573
- ? [...stores.movedColumns]
1574
- : [...stores.originColumns]);
1575
- const queue = [...visibleColumns];
1576
- const visibleIndexSet = new Set(queue.map(column => column.index));
1577
- stores.movedColumns = baseColumns.map((column) => {
1578
- if (visibleIndexSet.has(column.index)) {
1579
- return queue.shift();
1580
- }
1581
- return column;
1582
- });
1583
- };
1584
- const setColumnMoving = (currentIndex, droppedIndex) => {
1585
- const oldIndex = parseInt(currentIndex, 10);
1586
- const newPositionIndex = parseInt(droppedIndex, 10);
1587
-
1588
- if (!Number.isInteger(oldIndex) || !Number.isInteger(newPositionIndex)) {
1589
- return;
1590
- }
1591
-
1592
- const columns = [...stores.orderedColumns];
1593
- const movedColumn = columns[oldIndex];
1594
-
1595
- columns.splice(oldIndex, 1);
1596
- columns.splice(newPositionIndex, 0, movedColumn);
1597
-
1598
- if (stores.filteredColumns.length) {
1599
- stores.filteredColumns = columns;
1600
- }
1601
- buildMovedColumns(columns);
1602
- };
1603
- const onDragStart = (e) => {
1604
- e.dataTransfer.setData('text/plain', e.currentTarget.dataset.index);
1605
- };
1606
- const onDragOver = (e) => {
1607
- e.preventDefault();
1608
- };
1609
- const onDrop = (e) => {
1610
- e.preventDefault();
1611
- const currentIndex = e.dataTransfer.getData('text/plain');
1612
- const droppedIndex = e.target.parentNode.dataset.index;
1613
- setColumnMoving(currentIndex, droppedIndex);
1614
- emit('change-column-order', {
1615
- column: stores.orderedColumns[droppedIndex],
1616
- columns: stores.updatedColumns,
1617
- });
1618
-
1619
- emit('change-column-info', {
1620
- type: 'order',
1621
- columns: stores.updatedColumns,
1622
- });
1623
- };
1624
- return {
1625
- onDragStart,
1626
- onDragOver,
1627
- onDrop,
1628
- };
1629
- };