evui 3.1.53 → 3.1.57
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/dist/evui.common.js +792 -583
- package/dist/evui.common.js.map +1 -1
- package/dist/evui.umd.js +792 -583
- package/dist/evui.umd.js.map +1 -1
- package/dist/evui.umd.min.js +1 -1
- package/dist/evui.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/chart/Chart.vue +4 -9
- package/src/components/chart/chart.core.js +4 -4
- package/src/components/chart/element/element.bar.js +2 -4
- package/src/components/chart/model/model.store.js +7 -18
- package/src/components/chart/plugins/plugins.interaction.js +15 -6
- package/src/components/chart/plugins/plugins.tooltip.js +2 -2
- package/src/components/grid/Grid.vue +2 -68
- package/src/components/toggle/Toggle.vue +12 -5
- package/src/components/treeGrid/TreeGrid.vue +8 -5
- package/src/components/treeGrid/uses.js +37 -18
- package/src/components/window/Window.vue +21 -1
- package/src/components/window/uses.js +358 -146
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import {
|
|
2
|
-
getCurrentInstance,
|
|
2
|
+
getCurrentInstance,
|
|
3
|
+
ref,
|
|
4
|
+
computed,
|
|
5
|
+
reactive,
|
|
6
|
+
watch,
|
|
7
|
+
nextTick,
|
|
8
|
+
onMounted,
|
|
9
|
+
onBeforeUnmount,
|
|
3
10
|
} from 'vue';
|
|
4
11
|
|
|
5
12
|
// 세로 스크롤 너비
|
|
6
13
|
const getVScrollWidth = () => window.innerWidth - document.documentElement.clientWidth;
|
|
7
14
|
// 가로 스크롤 너비
|
|
8
|
-
const getHScrollWidth = () => window.innerHeight - document.documentElement.clientHeight;
|
|
9
|
-
// 전체 문서 너비
|
|
10
|
-
const getDocumentWidth = () => Math.max(
|
|
11
|
-
document.body.scrollWidth, document.documentElement.scrollWidth,
|
|
12
|
-
document.body.offsetWidth, document.documentElement.offsetWidth,
|
|
13
|
-
document.body.clientWidth, document.documentElement.clientWidth,
|
|
14
|
-
);
|
|
15
|
-
// 전체 문서 높이
|
|
16
|
-
const getDocumentHeight = () => Math.max(
|
|
17
|
-
document.body.scrollHeight, document.documentElement.scrollHeight,
|
|
18
|
-
document.body.offsetHeight, document.documentElement.offsetHeight,
|
|
19
|
-
document.body.clientHeight, document.documentElement.clientHeight,
|
|
20
|
-
);
|
|
15
|
+
// const getHScrollWidth = () => window.innerHeight - document.documentElement.clientHeight;
|
|
21
16
|
|
|
22
17
|
const useModel = () => {
|
|
23
18
|
const { props, emit } = getCurrentInstance();
|
|
@@ -89,6 +84,8 @@ const useModel = () => {
|
|
|
89
84
|
}));
|
|
90
85
|
|
|
91
86
|
const setBasePosition = () => {
|
|
87
|
+
basePosition.position = 'fixed';
|
|
88
|
+
|
|
92
89
|
if (props.fullscreen) {
|
|
93
90
|
basePosition.width = '100%';
|
|
94
91
|
basePosition.height = '100%';
|
|
@@ -97,22 +94,32 @@ const useModel = () => {
|
|
|
97
94
|
return;
|
|
98
95
|
}
|
|
99
96
|
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
const convertedWidth = removeUnit(props.width, 'horizontal');
|
|
98
|
+
const convertedMinWidth = removeUnit(props.minWidth, 'horizontal');
|
|
99
|
+
if (convertedWidth < convertedMinWidth) {
|
|
100
|
+
console.warn('Since width is less than min-width, it is replaced by min-width.');
|
|
101
|
+
basePosition.width = numberToUnit(props.minWidth);
|
|
102
|
+
} else {
|
|
103
|
+
basePosition.width = numberToUnit(props.width);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const convertedHeight = removeUnit(props.height, 'vertical');
|
|
107
|
+
const convertedMinHeight = removeUnit(props.minHeight, 'vertical');
|
|
108
|
+
if (convertedHeight < convertedMinHeight) {
|
|
109
|
+
console.warn('Since height is less than min-height, it is replaced by min-height.');
|
|
110
|
+
basePosition.height = numberToUnit(props.minHeight);
|
|
111
|
+
} else {
|
|
112
|
+
basePosition.height = numberToUnit(props.height);
|
|
113
|
+
}
|
|
104
114
|
|
|
105
|
-
basePosition.
|
|
106
|
-
basePosition.
|
|
107
|
-
basePosition.position = 'absolute';
|
|
108
|
-
basePosition.top = `calc(((100vh - ${basePosition.height}) / 2) + ${scrollTop}px)`;
|
|
109
|
-
basePosition.left = `calc(((100vw - ${basePosition.width}) / 2) + ${scrollLeft}px)`;
|
|
115
|
+
basePosition.top = `calc((100% - ${basePosition.height}) / 2)`;
|
|
116
|
+
basePosition.left = `calc((100% - ${basePosition.width}) / 2)`;
|
|
110
117
|
|
|
111
118
|
if (removeUnit(props.width, 'horizontal') > window.innerWidth) {
|
|
112
119
|
basePosition.left = 0;
|
|
113
120
|
}
|
|
114
121
|
if (removeUnit(props.height, 'vertical') > window.innerHeight) {
|
|
115
|
-
basePosition.top =
|
|
122
|
+
basePosition.top = 0;
|
|
116
123
|
}
|
|
117
124
|
};
|
|
118
125
|
|
|
@@ -125,61 +132,32 @@ const useModel = () => {
|
|
|
125
132
|
};
|
|
126
133
|
|
|
127
134
|
const changeBodyCls = (isVisible) => {
|
|
128
|
-
const windowCnt = root?.getElementsByClassName('ev-window-wrapper')?.length;
|
|
129
135
|
const hideScrollWindowCnt = root?.getElementsByClassName('scroll-lock')?.length;
|
|
130
|
-
const allowScrollWindowCnt = root?.getElementsByClassName('scroll-allow')?.length;
|
|
131
136
|
const bodyElem = document.body;
|
|
132
137
|
|
|
133
|
-
if (isVisible) {
|
|
138
|
+
if (isVisible) { // window open
|
|
134
139
|
if (props.hideScroll) {
|
|
135
|
-
//
|
|
136
|
-
// body 우측 padding 추가 & overflow hidden class 추가
|
|
140
|
+
// hideScroll 시, body 우측 padding 추가 & overflow hidden class 추가
|
|
137
141
|
if (!hideScrollWindowCnt) {
|
|
138
142
|
const scrollWidth = getVScrollWidth();
|
|
139
143
|
bodyElem.style.paddingRight = `${scrollWidth}px`;
|
|
140
144
|
}
|
|
141
145
|
bodyElem.classList.add('ev-window-scroll-lock');
|
|
142
|
-
} else if (!props.hideScroll && !props.isModal) {
|
|
143
|
-
// !props.hideScroll && !props.isModal 시,
|
|
144
|
-
// body에 position: relative 추가, 스크롤 여부에 따라 overflow-x or y hidden 처리
|
|
145
|
-
const vScrollWidth = getVScrollWidth();
|
|
146
|
-
const hScrollWidth = getHScrollWidth();
|
|
147
|
-
const bodyClassName = ['ev-window-scroll-allow'];
|
|
148
|
-
if (vScrollWidth > 0 && hScrollWidth === 0) {
|
|
149
|
-
// 세로 스크롤만 있을 경우 - 가로 스크롤 막음
|
|
150
|
-
bodyClassName.push('horizontal-hide');
|
|
151
|
-
} else if (vScrollWidth === 0 && hScrollWidth > 0) {
|
|
152
|
-
// 가로 스크롤만 있을 경우 - 세로 스크롤 막음
|
|
153
|
-
bodyClassName.push('vertical-hide');
|
|
154
|
-
} else if (vScrollWidth === 0 && hScrollWidth === 0) {
|
|
155
|
-
// 둘다 없을 경우 - 가로&세로 스크롤 막음
|
|
156
|
-
bodyClassName.push('hide');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
bodyElem.classList.add(...bodyClassName);
|
|
160
|
-
}
|
|
161
|
-
bodyElem.classList.add('ev-window-open');
|
|
162
|
-
} else {
|
|
163
|
-
if (hideScrollWindowCnt === 1) {
|
|
164
|
-
bodyElem.style.removeProperty('padding-right');
|
|
165
|
-
bodyElem.classList.remove('ev-window-scroll-lock');
|
|
166
|
-
}
|
|
167
|
-
if (allowScrollWindowCnt === 1) {
|
|
168
|
-
bodyElem.classList.remove('ev-window-scroll-allow', 'horizontal-hide', 'vertical-hide', 'hide');
|
|
169
|
-
}
|
|
170
|
-
if (windowCnt === 1) {
|
|
171
|
-
bodyElem.classList.remove('ev-window-open');
|
|
172
146
|
}
|
|
147
|
+
} else if (props.hideScroll && hideScrollWindowCnt === 1) { // window close
|
|
148
|
+
bodyElem.style.removeProperty('padding-right');
|
|
149
|
+
bodyElem.classList.remove('ev-window-scroll-lock');
|
|
173
150
|
}
|
|
174
151
|
};
|
|
152
|
+
|
|
175
153
|
setBasePosition();
|
|
176
154
|
|
|
177
155
|
watch(
|
|
178
156
|
() => props.visible,
|
|
179
|
-
(newVal) => {
|
|
157
|
+
async (newVal) => {
|
|
180
158
|
changeBodyCls(newVal);
|
|
181
159
|
if (newVal) {
|
|
182
|
-
nextTick(() => {
|
|
160
|
+
await nextTick(() => {
|
|
183
161
|
setBasePosition();
|
|
184
162
|
});
|
|
185
163
|
}
|
|
@@ -211,8 +189,6 @@ const useMouseEvent = (param) => {
|
|
|
211
189
|
const draggingMinSize = 50;
|
|
212
190
|
const grabbingBorderSize = 5;
|
|
213
191
|
const dragStyle = reactive({});
|
|
214
|
-
const documentWidth = ref(0);
|
|
215
|
-
const documentHeight = ref(0);
|
|
216
192
|
const clickedInfo = reactive({
|
|
217
193
|
state: '',
|
|
218
194
|
pressedSpot: '',
|
|
@@ -417,6 +393,7 @@ const useMouseEvent = (param) => {
|
|
|
417
393
|
// 브라우저 상하 위치 제약
|
|
418
394
|
const getValidTop = (windowHeight, top) => {
|
|
419
395
|
let tempTop = top;
|
|
396
|
+
|
|
420
397
|
if (tempTop < 0) { // 상
|
|
421
398
|
tempTop = 0;
|
|
422
399
|
} else if (tempTop > windowHeight - draggingMinSize) { // 하
|
|
@@ -435,28 +412,6 @@ const useMouseEvent = (param) => {
|
|
|
435
412
|
return tempLeft;
|
|
436
413
|
};
|
|
437
414
|
|
|
438
|
-
// mousedown > wheel: 마우스 휠
|
|
439
|
-
const wheeling = (e) => {
|
|
440
|
-
const scrollTop = document.documentElement.scrollTop;
|
|
441
|
-
if (e.deltaY < 0 && scrollTop <= 0) {
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
let tempTop = removeUnit(dragStyle.top) || clickedInfo.top;
|
|
446
|
-
tempTop += e.deltaY;
|
|
447
|
-
|
|
448
|
-
const windowHeight = props.hideScroll || props.isModal
|
|
449
|
-
? document.documentElement.clientHeight : documentHeight.value;
|
|
450
|
-
tempTop = getValidTop(windowHeight, tempTop);
|
|
451
|
-
|
|
452
|
-
clickedInfo.top = tempTop;
|
|
453
|
-
|
|
454
|
-
setDragStyle({
|
|
455
|
-
top: `${tempTop}px`,
|
|
456
|
-
left: dragStyle.left,
|
|
457
|
-
});
|
|
458
|
-
};
|
|
459
|
-
|
|
460
415
|
// mousedown > mousemove: 마우스 드래그
|
|
461
416
|
const dragging = (e) => {
|
|
462
417
|
e.preventDefault();
|
|
@@ -464,63 +419,14 @@ const useMouseEvent = (param) => {
|
|
|
464
419
|
|
|
465
420
|
// window header를 통해 mouseMove 됐을 경우
|
|
466
421
|
if (props.draggable && clickedInfo.pressedSpot === 'header') {
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
documentWidth.value = getDocumentWidth();
|
|
470
|
-
}
|
|
471
|
-
if (!documentHeight.value) {
|
|
472
|
-
documentHeight.value = getDocumentHeight();
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// 스크롤 있을 경우 전체 문서 기준, 없을 경우 clientWidth, Height 기준
|
|
476
|
-
const windowWidth = props.hideScroll || props.isModal
|
|
477
|
-
? document.documentElement.clientWidth : documentWidth.value;
|
|
478
|
-
const windowHeight = props.hideScroll || props.isModal
|
|
479
|
-
? document.documentElement.clientHeight : documentHeight.value;
|
|
480
|
-
|
|
422
|
+
const windowWidth = document.documentElement.clientWidth;
|
|
423
|
+
const windowHeight = document.documentElement.clientHeight;
|
|
481
424
|
const diffTop = e.clientY - clickedInfo.clientY;
|
|
482
425
|
const diffLeft = e.clientX - clickedInfo.clientX;
|
|
483
426
|
|
|
484
427
|
let tempTop = clickedInfo.top + diffTop;
|
|
485
428
|
let tempLeft = clickedInfo.left + diffLeft;
|
|
486
429
|
|
|
487
|
-
// 스크롤 허용 & 드래그 시 브라우저 상하단 위치에서 스크롤 이동
|
|
488
|
-
if (!props.hideScroll && !props.isModal) {
|
|
489
|
-
let [x, y] = [0, 0];
|
|
490
|
-
const moveScrollSize = 10;
|
|
491
|
-
const scrollTop = document.documentElement.scrollTop;
|
|
492
|
-
|
|
493
|
-
if (e.clientY < draggingMinSize && scrollTop > 0) { // 상
|
|
494
|
-
tempTop = draggedInfo.top || tempTop;
|
|
495
|
-
clickedInfo.clientY = e.clientY;
|
|
496
|
-
clickedInfo.top = tempTop;
|
|
497
|
-
y = -moveScrollSize;
|
|
498
|
-
tempTop -= moveScrollSize;
|
|
499
|
-
} else if (e.clientY > document.documentElement.clientHeight - draggingMinSize) { // 하
|
|
500
|
-
tempTop = draggedInfo.top || tempTop;
|
|
501
|
-
clickedInfo.clientY = e.clientY;
|
|
502
|
-
clickedInfo.top = tempTop;
|
|
503
|
-
y = moveScrollSize;
|
|
504
|
-
tempTop += moveScrollSize;
|
|
505
|
-
} else if (e.clientX < draggingMinSize) { // 좌
|
|
506
|
-
tempLeft = draggedInfo.left || tempLeft;
|
|
507
|
-
clickedInfo.clientX = e.clientX;
|
|
508
|
-
clickedInfo.left = tempLeft;
|
|
509
|
-
x = -moveScrollSize;
|
|
510
|
-
tempLeft -= moveScrollSize;
|
|
511
|
-
} else if (e.clientX > document.documentElement.clientWidth - draggingMinSize) { // 우
|
|
512
|
-
tempLeft = draggedInfo.left || tempLeft;
|
|
513
|
-
clickedInfo.clientX = e.clientX;
|
|
514
|
-
clickedInfo.left = tempLeft;
|
|
515
|
-
x = moveScrollSize;
|
|
516
|
-
tempLeft += moveScrollSize;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
document.documentElement.scrollBy(x, y);
|
|
520
|
-
draggedInfo.top = tempTop;
|
|
521
|
-
draggedInfo.left = tempLeft;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
430
|
tempTop = getValidTop(windowHeight, tempTop);
|
|
525
431
|
tempLeft = getValidLeft(windowWidth, tempLeft);
|
|
526
432
|
|
|
@@ -542,7 +448,6 @@ const useMouseEvent = (param) => {
|
|
|
542
448
|
|
|
543
449
|
emit('mousedown-mouseup', e);
|
|
544
450
|
|
|
545
|
-
window.removeEventListener('wheel', wheeling);
|
|
546
451
|
window.removeEventListener('mousemove', dragging);
|
|
547
452
|
window.removeEventListener('mouseup', endDrag);
|
|
548
453
|
};
|
|
@@ -594,7 +499,6 @@ const useMouseEvent = (param) => {
|
|
|
594
499
|
|
|
595
500
|
emit('mousedown', { ...clickedInfo });
|
|
596
501
|
|
|
597
|
-
window.addEventListener('wheel', wheeling);
|
|
598
502
|
window.addEventListener('mousemove', dragging);
|
|
599
503
|
window.addEventListener('mouseup', endDrag);
|
|
600
504
|
};
|
|
@@ -609,14 +513,7 @@ const useMouseEvent = (param) => {
|
|
|
609
513
|
const clickExpandBtn = () => {
|
|
610
514
|
isFullExpandWindow.value = !isFullExpandWindow.value;
|
|
611
515
|
nextTick(() => {
|
|
612
|
-
if (
|
|
613
|
-
setDragStyle({
|
|
614
|
-
top: beforeExpandPosInfo.top,
|
|
615
|
-
left: beforeExpandPosInfo.left,
|
|
616
|
-
width: beforeExpandPosInfo.width,
|
|
617
|
-
height: beforeExpandPosInfo.height,
|
|
618
|
-
});
|
|
619
|
-
} else {
|
|
516
|
+
if (isFullExpandWindow.value) {
|
|
620
517
|
beforeExpandPosInfo.top = windowRef.value.offsetTop;
|
|
621
518
|
beforeExpandPosInfo.left = windowRef.value.offsetLeft;
|
|
622
519
|
beforeExpandPosInfo.width = windowRef.value.offsetWidth;
|
|
@@ -628,7 +525,21 @@ const useMouseEvent = (param) => {
|
|
|
628
525
|
width: document.body.clientWidth,
|
|
629
526
|
height: document.body.clientHeight,
|
|
630
527
|
});
|
|
528
|
+
} else {
|
|
529
|
+
setDragStyle({
|
|
530
|
+
top: beforeExpandPosInfo.top,
|
|
531
|
+
left: beforeExpandPosInfo.left,
|
|
532
|
+
width: beforeExpandPosInfo.width,
|
|
533
|
+
height: beforeExpandPosInfo.height,
|
|
534
|
+
});
|
|
631
535
|
}
|
|
536
|
+
|
|
537
|
+
emit('expand', {
|
|
538
|
+
top: beforeExpandPosInfo.top,
|
|
539
|
+
left: beforeExpandPosInfo.left,
|
|
540
|
+
width: beforeExpandPosInfo.width,
|
|
541
|
+
height: beforeExpandPosInfo.height,
|
|
542
|
+
});
|
|
632
543
|
});
|
|
633
544
|
};
|
|
634
545
|
|
|
@@ -679,7 +590,308 @@ const useMouseEvent = (param) => {
|
|
|
679
590
|
};
|
|
680
591
|
};
|
|
681
592
|
|
|
593
|
+
const activeWindows = (() => {
|
|
594
|
+
let windows = [];
|
|
595
|
+
let sequence = 0;
|
|
596
|
+
|
|
597
|
+
return {
|
|
598
|
+
add(activeWindow) {
|
|
599
|
+
if (activeWindow === null || activeWindow === undefined) return;
|
|
600
|
+
|
|
601
|
+
activeWindow.sequence = sequence++;
|
|
602
|
+
windows.push(activeWindow);
|
|
603
|
+
|
|
604
|
+
// eslint-disable-next-line consistent-return
|
|
605
|
+
return activeWindow.sequence;
|
|
606
|
+
},
|
|
607
|
+
remove(inactiveWindow) {
|
|
608
|
+
if (inactiveWindow === null || inactiveWindow === undefined) return;
|
|
609
|
+
windows = windows.filter(activeWindow => activeWindow.sequence !== inactiveWindow.sequence);
|
|
610
|
+
},
|
|
611
|
+
|
|
612
|
+
get windows() {
|
|
613
|
+
return windows.slice();
|
|
614
|
+
},
|
|
615
|
+
getWindowBySequence(targetSequence) {
|
|
616
|
+
return windows.find(activeWindow => activeWindow.sequence === targetSequence);
|
|
617
|
+
},
|
|
618
|
+
|
|
619
|
+
isEmpty() {
|
|
620
|
+
return windows.length <= 0;
|
|
621
|
+
},
|
|
622
|
+
isFirstWindowOpen() {
|
|
623
|
+
return sequence === 1;
|
|
624
|
+
},
|
|
625
|
+
};
|
|
626
|
+
})();
|
|
627
|
+
|
|
628
|
+
const zIndexService = (() => {
|
|
629
|
+
const LOWER = 700;
|
|
630
|
+
const UPPER = 750;
|
|
631
|
+
|
|
632
|
+
const INCREMENT = 1;
|
|
633
|
+
const PADDING = INCREMENT * 2;
|
|
634
|
+
|
|
635
|
+
const UPPER_LIMIT = UPPER - PADDING;
|
|
636
|
+
|
|
637
|
+
let current = LOWER;
|
|
638
|
+
|
|
639
|
+
return {
|
|
640
|
+
getNext() {
|
|
641
|
+
if (current >= UPPER_LIMIT) {
|
|
642
|
+
return UPPER_LIMIT;
|
|
643
|
+
}
|
|
644
|
+
current += INCREMENT;
|
|
645
|
+
return current;
|
|
646
|
+
},
|
|
647
|
+
getNextOverLimit() {
|
|
648
|
+
return UPPER_LIMIT + INCREMENT;
|
|
649
|
+
},
|
|
650
|
+
getPrevFrom(index) {
|
|
651
|
+
const prev = current - (index * INCREMENT);
|
|
652
|
+
|
|
653
|
+
if (prev <= LOWER) return LOWER;
|
|
654
|
+
return prev;
|
|
655
|
+
},
|
|
656
|
+
isUpperLimitClose() {
|
|
657
|
+
return current >= UPPER_LIMIT;
|
|
658
|
+
},
|
|
659
|
+
resetToLower() {
|
|
660
|
+
current = LOWER;
|
|
661
|
+
},
|
|
662
|
+
getAllocableCount() {
|
|
663
|
+
return Math.floor((UPPER_LIMIT - LOWER) / INCREMENT);
|
|
664
|
+
},
|
|
665
|
+
};
|
|
666
|
+
})();
|
|
667
|
+
|
|
668
|
+
const getZIndexFromElement = (element) => {
|
|
669
|
+
const zIndex = window.getComputedStyle(element).getPropertyValue('z-index').trim();
|
|
670
|
+
|
|
671
|
+
if (!zIndex || isNaN(zIndex)) return 700; // window 초기 z-index 값
|
|
672
|
+
|
|
673
|
+
return parseInt(zIndex);
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
const getActiveWindowsOrderByZIndexAsc = () => {
|
|
677
|
+
// zIndex 클수록, 최근에 열린 것일수록(sequence 클수록) 뒤에 위치
|
|
678
|
+
const compareByZIndex = (window1, window2) => {
|
|
679
|
+
if (window1.zIndex > window2.zIndex) return 1;
|
|
680
|
+
if (window1.zIndex < window2.zIndex) return -1;
|
|
681
|
+
|
|
682
|
+
if (window1.sequence > window2.sequence) return 1;
|
|
683
|
+
return -1;
|
|
684
|
+
};
|
|
685
|
+
|
|
686
|
+
const activeWindowsSorted = Array.prototype.map.call(activeWindows.windows, activeWindow => ({
|
|
687
|
+
...activeWindow,
|
|
688
|
+
zIndex: getZIndexFromElement(activeWindow.elem),
|
|
689
|
+
})).sort(compareByZIndex);
|
|
690
|
+
|
|
691
|
+
return activeWindowsSorted;
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
const useEscCloseAndFocusable = ({ closeWin, windowRef }) => {
|
|
695
|
+
const { props } = getCurrentInstance();
|
|
696
|
+
|
|
697
|
+
let sequence = null;
|
|
698
|
+
let timer = null;
|
|
699
|
+
|
|
700
|
+
// escClose 관련 로직 시작
|
|
701
|
+
const addActiveWindow = () => {
|
|
702
|
+
const windowSequence = activeWindows.add({
|
|
703
|
+
sequence,
|
|
704
|
+
closeWin,
|
|
705
|
+
elem: windowRef.value,
|
|
706
|
+
escClose: props.escClose,
|
|
707
|
+
});
|
|
708
|
+
return windowSequence;
|
|
709
|
+
};
|
|
710
|
+
|
|
711
|
+
const removeInactiveWindow = (inactiveWindow) => {
|
|
712
|
+
activeWindows.remove(inactiveWindow);
|
|
713
|
+
};
|
|
714
|
+
|
|
715
|
+
const keydownEsc = (event) => {
|
|
716
|
+
if (activeWindows.isEmpty()) return;
|
|
717
|
+
|
|
718
|
+
const { code } = event;
|
|
719
|
+
if (code !== 'Escape') return;
|
|
720
|
+
|
|
721
|
+
const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
|
|
722
|
+
const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
|
|
723
|
+
|
|
724
|
+
// 예시 상황) Nested에서 외부 Window의 escClose는 true이고, 내부 Window의 escClose는 false인 경우,
|
|
725
|
+
// esc 눌러도 외부 Window는 닫히지 않고, 가장 상단에 있는 내부 Window가 수동으로 닫힌 후에 닫히도록 하기 위해
|
|
726
|
+
if (!topActiveWindow.escClose) return;
|
|
727
|
+
|
|
728
|
+
topActiveWindow.closeWin();
|
|
729
|
+
};
|
|
730
|
+
|
|
731
|
+
const setWindowActive = () => {
|
|
732
|
+
sequence = addActiveWindow();
|
|
733
|
+
// DOM의 dataset에 sequence 값 추가해 식별 가능하도록
|
|
734
|
+
windowRef.value.dataset.sequence = sequence;
|
|
735
|
+
|
|
736
|
+
if (activeWindows.isFirstWindowOpen()) {
|
|
737
|
+
document.addEventListener('keydown', keydownEsc);
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
const setWindowInactive = () => {
|
|
742
|
+
const inactiveWindow = activeWindows.getWindowBySequence(sequence);
|
|
743
|
+
removeInactiveWindow(inactiveWindow);
|
|
744
|
+
};
|
|
745
|
+
// escClose 관련 로직 끝
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
// focusable 관련 로직 시작
|
|
749
|
+
const setZIndexToWindow = ({ elem, zIndex }) => {
|
|
750
|
+
// 모달인 경우에는 dim layer도 같이 z-index 높여준다.
|
|
751
|
+
if (props.isModal) {
|
|
752
|
+
const dimLayerElem = elem.parentElement.getElementsByClassName('ev-window-dim-layer')[0];
|
|
753
|
+
dimLayerElem.style.zIndex = zIndex;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
elem.style.zIndex = zIndex;
|
|
757
|
+
};
|
|
758
|
+
|
|
759
|
+
const assignZIndex = () => {
|
|
760
|
+
// Window가 1번째로 열릴 때, z-index 값을 시작값으로 설정
|
|
761
|
+
if (activeWindows.windows.length === 1) {
|
|
762
|
+
zIndexService.resetToLower();
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const nextZIndex = zIndexService.getNext();
|
|
766
|
+
setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
const sameAsCurrent = windowData => String(windowData.sequence)
|
|
770
|
+
=== windowRef.value.dataset.sequence;
|
|
771
|
+
|
|
772
|
+
// 할당하려는 z-index 값이 상한일 때
|
|
773
|
+
const reassignZIndex = () => {
|
|
774
|
+
const activeWindowsZIndexAsc = getActiveWindowsOrderByZIndexAsc();
|
|
775
|
+
|
|
776
|
+
const overCountLimit = activeWindows.windows.length > zIndexService.getAllocableCount();
|
|
777
|
+
// 할당 가능한 z-index 수보다 많은 Window를 띄웠을 때
|
|
778
|
+
if (overCountLimit) {
|
|
779
|
+
const activeWindowsZIndexDesc = activeWindowsZIndexAsc.reverse();
|
|
780
|
+
|
|
781
|
+
// z-index 기준 내림차순으로 정렬한 Window의 z-index 값을 UPPER에서 LOWER로 1씩 감소한 값 할당
|
|
782
|
+
let interval = 0;
|
|
783
|
+
activeWindowsZIndexDesc.forEach((activeWindow) => {
|
|
784
|
+
if (sameAsCurrent(activeWindow)) return;
|
|
785
|
+
|
|
786
|
+
const prevZIndex = zIndexService.getPrevFrom(interval++);
|
|
787
|
+
setZIndexToWindow({ elem: activeWindow.elem, zIndex: prevZIndex });
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
// 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
|
|
791
|
+
const nextZIndex = zIndexService.getNextOverLimit();
|
|
792
|
+
setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
|
|
793
|
+
} else {
|
|
794
|
+
zIndexService.resetToLower();
|
|
795
|
+
|
|
796
|
+
activeWindowsZIndexAsc.forEach((activeWindow) => {
|
|
797
|
+
if (sameAsCurrent(activeWindow)) return;
|
|
798
|
+
|
|
799
|
+
const nextZIndex = zIndexService.getNext();
|
|
800
|
+
setZIndexToWindow({ elem: activeWindow.elem, zIndex: nextZIndex });
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
// 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
|
|
804
|
+
const nextZIndex = zIndexService.getNext();
|
|
805
|
+
setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
|
|
806
|
+
}
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
const checkLimitAndSetZIndex = () => {
|
|
810
|
+
if (zIndexService.isUpperLimitClose()) {
|
|
811
|
+
reassignZIndex();
|
|
812
|
+
} else {
|
|
813
|
+
assignZIndex();
|
|
814
|
+
}
|
|
815
|
+
};
|
|
816
|
+
|
|
817
|
+
const setFocus = () => {
|
|
818
|
+
// X 버튼을 클릭했을 때
|
|
819
|
+
if (!windowRef.value) return;
|
|
820
|
+
|
|
821
|
+
// focusable prop이 false인 경우에는 z-index를 높이지 않는다.
|
|
822
|
+
if (!props.focusable) return;
|
|
823
|
+
|
|
824
|
+
const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
|
|
825
|
+
const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
|
|
826
|
+
|
|
827
|
+
const isAlreadyTop = sameAsCurrent(topActiveWindow);
|
|
828
|
+
if (isAlreadyTop) return;
|
|
829
|
+
|
|
830
|
+
checkLimitAndSetZIndex();
|
|
831
|
+
};
|
|
832
|
+
// focusable 관련 로직 끝
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
/*
|
|
836
|
+
실행 시점(=Window 열림):
|
|
837
|
+
visible 초기값이 true일 때 watch를 실행시키지 않아 onMounted hook 사용
|
|
838
|
+
*/
|
|
839
|
+
onMounted(() => {
|
|
840
|
+
if (props.visible) {
|
|
841
|
+
setWindowActive();
|
|
842
|
+
timer = setTimeout(checkLimitAndSetZIndex, 0);
|
|
843
|
+
}
|
|
844
|
+
});
|
|
845
|
+
|
|
846
|
+
/*
|
|
847
|
+
실행 시점(=Window 닫힘):
|
|
848
|
+
예시. 배열을 통해 Window 여러 개 띄울 때, 배열 원소 삭제로 인해 해당 Window가 닫히는 경우
|
|
849
|
+
unmount가 발생해서 watch를 실행히시키지 않아 onBeforeUnmount hook 사용
|
|
850
|
+
*/
|
|
851
|
+
onBeforeUnmount(() => {
|
|
852
|
+
if (props.visible) {
|
|
853
|
+
setWindowInactive();
|
|
854
|
+
clearTimeout(timer);
|
|
855
|
+
}
|
|
856
|
+
});
|
|
857
|
+
|
|
858
|
+
/*
|
|
859
|
+
실행 시점:
|
|
860
|
+
1. visible 값이 false -> true로 변했을 때(=Window 열림)
|
|
861
|
+
2. visible 값이 true -> false로 변했을 때(=Window 닫힙)
|
|
862
|
+
*/
|
|
863
|
+
watch(
|
|
864
|
+
() => props.visible,
|
|
865
|
+
(visible) => {
|
|
866
|
+
nextTick(() => {
|
|
867
|
+
if (visible) {
|
|
868
|
+
// visible 값이 false -> true로 변경되었을 때
|
|
869
|
+
setWindowActive();
|
|
870
|
+
timer = setTimeout(checkLimitAndSetZIndex, 0);
|
|
871
|
+
} else {
|
|
872
|
+
// visible 값이 true -> false로 변경되었을 때
|
|
873
|
+
setWindowInactive();
|
|
874
|
+
clearTimeout(timer);
|
|
875
|
+
}
|
|
876
|
+
});
|
|
877
|
+
});
|
|
878
|
+
|
|
879
|
+
watch(
|
|
880
|
+
() => props.escClose,
|
|
881
|
+
(escClose) => {
|
|
882
|
+
if (!props.visible) return;
|
|
883
|
+
const currentWindow = activeWindows.getWindowBySequence(sequence);
|
|
884
|
+
if (currentWindow) currentWindow.escClose = escClose;
|
|
885
|
+
},
|
|
886
|
+
);
|
|
887
|
+
|
|
888
|
+
return {
|
|
889
|
+
setFocus,
|
|
890
|
+
};
|
|
891
|
+
};
|
|
892
|
+
|
|
682
893
|
export {
|
|
683
894
|
useModel,
|
|
684
895
|
useMouseEvent,
|
|
896
|
+
useEscCloseAndFocusable,
|
|
685
897
|
};
|