evui 3.3.36 → 3.3.39
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/LICENSE +21 -21
- package/README.md +40 -40
- package/dist/evui.common.js +1907 -1832
- package/dist/evui.common.js.map +1 -1
- package/dist/evui.umd.js +1907 -1832
- 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/dist/img/{EVUI.7f3588fb.svg → EVUI.b82ee81a.svg} +292 -292
- package/dist/img/{icon_mysql.7ea26d5d.svg → icon_mysql.1085fdc9.svg} +78 -78
- package/dist/img/{icon_oracle.9009b108.svg → icon_oracle.0572d3ee.svg} +13 -13
- package/dist/img/{icon_postgresql.f8fffba9.svg → icon_postgresql.ee12bde8.svg} +58 -58
- package/package.json +61 -61
- package/src/common/emitter.js +20 -20
- package/src/common/utils.debounce.js +223 -223
- package/src/common/utils.js +134 -134
- package/src/common/utils.table.js +78 -78
- package/src/common/utils.throttle.js +83 -83
- package/src/common/utils.tree.js +18 -18
- package/src/components/button/Button.vue +198 -198
- package/src/components/button/index.js +7 -7
- package/src/components/buttonGroup/ButtonGroup.vue +11 -11
- package/src/components/buttonGroup/index.js +7 -7
- package/src/components/calendar/Calendar.vue +661 -661
- package/src/components/calendar/index.js +7 -7
- package/src/components/calendar/uses.js +1272 -1272
- package/src/components/chart/Chart.vue +189 -192
- package/src/components/chart/chart.core.js +870 -870
- package/src/components/chart/element/element.bar.js +524 -524
- package/src/components/chart/element/element.bar.time.js +156 -156
- package/src/components/chart/element/element.heatmap.js +533 -533
- package/src/components/chart/element/element.line.js +339 -339
- package/src/components/chart/element/element.pie.js +197 -197
- package/src/components/chart/element/element.scatter.js +184 -184
- package/src/components/chart/element/element.tip.js +550 -542
- package/src/components/chart/helpers/helpers.canvas.js +265 -265
- package/src/components/chart/helpers/helpers.constant.js +206 -206
- package/src/components/chart/helpers/helpers.util.js +346 -338
- package/src/components/chart/index.js +9 -9
- package/src/components/chart/model/index.js +4 -4
- package/src/components/chart/model/model.series.js +93 -93
- package/src/components/chart/model/model.store.js +977 -967
- package/src/components/chart/plugins/plugins.interaction.js +769 -769
- package/src/components/chart/plugins/plugins.legend.gradient.js +602 -602
- package/src/components/chart/plugins/plugins.legend.js +1155 -1151
- package/src/components/chart/plugins/plugins.pie.js +254 -254
- package/src/components/chart/plugins/plugins.title.js +56 -56
- package/src/components/chart/plugins/plugins.tooltip.js +692 -692
- package/src/components/chart/scale/scale.js +848 -848
- package/src/components/chart/scale/scale.linear.js +38 -38
- package/src/components/chart/scale/scale.logarithmic.js +128 -128
- package/src/components/chart/scale/scale.step.js +336 -336
- package/src/components/chart/scale/scale.time.category.js +277 -277
- package/src/components/chart/scale/scale.time.js +48 -48
- package/src/components/chart/style/chart.scss +312 -312
- package/src/components/chart/uses.js +264 -252
- package/src/components/checkbox/Checkbox.vue +200 -200
- package/src/components/checkbox/index.js +7 -7
- package/src/components/checkboxGroup/CheckboxGroup.vue +44 -44
- package/src/components/checkboxGroup/index.js +7 -7
- package/src/components/contextMenu/ContextMenu.vue +80 -80
- package/src/components/contextMenu/MenuList.vue +149 -149
- package/src/components/contextMenu/index.js +7 -7
- package/src/components/contextMenu/uses.js +203 -203
- package/src/components/datePicker/DatePicker.vue +437 -437
- package/src/components/datePicker/index.js +7 -7
- package/src/components/datePicker/uses.js +419 -419
- package/src/components/grid/Grid.vue +827 -827
- package/src/components/grid/grid.filter.window.vue +493 -493
- package/src/components/grid/grid.pagination.vue +75 -75
- package/src/components/grid/grid.summary.vue +265 -265
- package/src/components/grid/grid.toolbar.vue +26 -26
- package/src/components/grid/index.js +11 -11
- package/src/components/grid/style/grid.scss +263 -263
- package/src/components/grid/uses.js +1002 -1007
- package/src/components/icon/Icon.vue +49 -49
- package/src/components/icon/index.js +8 -8
- package/src/components/inputNumber/InputNumber.vue +212 -212
- package/src/components/inputNumber/index.js +7 -7
- package/src/components/inputNumber/uses.js +217 -217
- package/src/components/loading/Loading.vue +125 -125
- package/src/components/loading/index.js +7 -7
- package/src/components/menu/Menu.vue +68 -68
- package/src/components/menu/MenuItem.vue +187 -187
- package/src/components/menu/index.js +7 -7
- package/src/components/message/Message.vue +223 -223
- package/src/components/message/index.js +31 -31
- package/src/components/messageBox/MessageBox.vue +358 -358
- package/src/components/messageBox/index.js +22 -22
- package/src/components/notification/Notification.vue +316 -316
- package/src/components/notification/index.js +49 -49
- package/src/components/pagination/Pagination.vue +271 -271
- package/src/components/pagination/index.js +7 -7
- package/src/components/pagination/pageButton.vue +30 -30
- package/src/components/progress/Progress.vue +139 -139
- package/src/components/progress/index.js +7 -7
- package/src/components/radio/Radio.vue +159 -159
- package/src/components/radio/index.js +7 -7
- package/src/components/radioGroup/RadioGroup.vue +41 -41
- package/src/components/radioGroup/index.js +7 -7
- package/src/components/scheduler/Scheduler.vue +149 -149
- package/src/components/scheduler/index.js +7 -7
- package/src/components/scheduler/uses.js +183 -183
- package/src/components/select/Select.vue +440 -440
- package/src/components/select/index.js +7 -7
- package/src/components/select/uses.js +270 -270
- package/src/components/slider/Slider.vue +505 -505
- package/src/components/slider/index.js +7 -7
- package/src/components/slider/uses.js +390 -390
- package/src/components/tabPanel/TabPanel.vue +74 -74
- package/src/components/tabPanel/index.js +7 -7
- package/src/components/tabs/Tabs.vue +517 -517
- package/src/components/tabs/index.js +7 -7
- package/src/components/textField/TextField.vue +375 -375
- package/src/components/textField/index.js +7 -7
- package/src/components/timePicker/TimePicker.vue +352 -352
- package/src/components/timePicker/index.js +7 -7
- package/src/components/toggle/Toggle.vue +115 -115
- package/src/components/toggle/index.js +7 -7
- package/src/components/tree/Tree.vue +313 -313
- package/src/components/tree/TreeNode.vue +293 -293
- package/src/components/tree/index.js +7 -7
- package/src/components/treeGrid/TreeGrid.vue +758 -758
- package/src/components/treeGrid/TreeGridNode.vue +275 -275
- package/src/components/treeGrid/index.js +9 -9
- package/src/components/treeGrid/style/treeGrid.scss +261 -261
- package/src/components/treeGrid/treeGrid.toolbar.vue +26 -26
- package/src/components/treeGrid/uses.js +867 -867
- package/src/components/window/Window.vue +329 -329
- package/src/components/window/index.js +7 -7
- package/src/components/window/uses.js +899 -899
- package/src/directives/clickoutside.js +90 -90
- package/src/main.js +116 -116
- package/src/style/components/input.scss +108 -108
- package/src/style/functions.scss +3 -3
- package/src/style/index.scss +6 -6
- package/src/style/lib/fonts/EVUI.svg +292 -292
- package/src/style/lib/icon.css +888 -888
- package/src/style/mixins.scss +94 -94
- package/src/style/themes.scss +67 -67
- package/src/style/variables.scss +22 -22
|
@@ -1,899 +1,899 @@
|
|
|
1
|
-
import {
|
|
2
|
-
getCurrentInstance,
|
|
3
|
-
ref,
|
|
4
|
-
computed,
|
|
5
|
-
reactive,
|
|
6
|
-
watch,
|
|
7
|
-
nextTick,
|
|
8
|
-
onMounted,
|
|
9
|
-
onBeforeUnmount,
|
|
10
|
-
} from 'vue';
|
|
11
|
-
|
|
12
|
-
// 세로 스크롤 너비
|
|
13
|
-
const getVScrollWidth = () => window.innerWidth - document.documentElement.clientWidth;
|
|
14
|
-
// 가로 스크롤 너비
|
|
15
|
-
// const getHScrollWidth = () => window.innerHeight - document.documentElement.clientHeight;
|
|
16
|
-
|
|
17
|
-
const useModel = () => {
|
|
18
|
-
const { props, emit } = getCurrentInstance();
|
|
19
|
-
|
|
20
|
-
const windowRef = ref();
|
|
21
|
-
const headerRef = ref();
|
|
22
|
-
const isFullExpandWindow = ref(false);
|
|
23
|
-
const maximizableIcon = computed(() => (isFullExpandWindow.value ? 'ev-icon-compress' : 'ev-icon-expand'));
|
|
24
|
-
|
|
25
|
-
// body에 #ev-window-modal div append
|
|
26
|
-
let root = document.getElementById('ev-window-modal');
|
|
27
|
-
const initWrapperDiv = () => {
|
|
28
|
-
if (!root) {
|
|
29
|
-
const rootDiv = document.createElement('div');
|
|
30
|
-
rootDiv.id = 'ev-window-modal';
|
|
31
|
-
document.body.appendChild(rootDiv);
|
|
32
|
-
root = document.getElementById('ev-window-modal');
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
initWrapperDiv();
|
|
36
|
-
|
|
37
|
-
const numberToUnit = (input) => {
|
|
38
|
-
let output;
|
|
39
|
-
let result;
|
|
40
|
-
|
|
41
|
-
if (typeof input === 'string' || typeof input === 'number') {
|
|
42
|
-
const match = (/^(normal|(-*\d+(?:\.\d+)?)(px|%|vw|vh)?)$/).exec(input);
|
|
43
|
-
output = match ? { value: +match[2], unit: match[3] || undefined } : undefined;
|
|
44
|
-
} else {
|
|
45
|
-
output = undefined;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
if (output === null || output === undefined) {
|
|
49
|
-
result = undefined;
|
|
50
|
-
} else if (output.unit) {
|
|
51
|
-
result = `${output.value}${output.unit}`;
|
|
52
|
-
} else {
|
|
53
|
-
result = `${output.value}px`;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return result;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
const removeUnit = (input, direction = 'horizontal') => {
|
|
60
|
-
if (typeof input === 'number') {
|
|
61
|
-
return input;
|
|
62
|
-
} else if (!input) {
|
|
63
|
-
return 0;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
let result = 0;
|
|
67
|
-
const match = (/^(normal|(\d+(?:\.\d+)?)(px|%|vw|vh)?)$/).exec(input);
|
|
68
|
-
|
|
69
|
-
if (direction && ['%', 'vw', 'vh'].includes(match[3]) && match[2]) {
|
|
70
|
-
const standard = direction === 'horizontal' ? window.innerWidth : window.innerHeight;
|
|
71
|
-
result = Math.floor((standard * +match[2]) / 100);
|
|
72
|
-
} else if (match[2]) {
|
|
73
|
-
result = +match[2];
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
return result;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
// set base style
|
|
80
|
-
const basePosition = reactive({});
|
|
81
|
-
const baseStyle = computed(() => ({
|
|
82
|
-
...props.style,
|
|
83
|
-
...basePosition,
|
|
84
|
-
}));
|
|
85
|
-
|
|
86
|
-
const setBasePosition = () => {
|
|
87
|
-
basePosition.position = 'fixed';
|
|
88
|
-
|
|
89
|
-
if (props.fullscreen) {
|
|
90
|
-
basePosition.width = '100%';
|
|
91
|
-
basePosition.height = '100%';
|
|
92
|
-
basePosition.top = 0;
|
|
93
|
-
basePosition.left = 0;
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
|
|
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
|
-
}
|
|
114
|
-
|
|
115
|
-
basePosition.top = `calc((100% - ${basePosition.height}) / 2)`;
|
|
116
|
-
basePosition.left = `calc((100% - ${basePosition.width}) / 2)`;
|
|
117
|
-
|
|
118
|
-
if (removeUnit(props.width, 'horizontal') > window.innerWidth) {
|
|
119
|
-
basePosition.left = 0;
|
|
120
|
-
}
|
|
121
|
-
if (removeUnit(props.height, 'vertical') > window.innerHeight) {
|
|
122
|
-
basePosition.top = 0;
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
// close window
|
|
127
|
-
const closeWin = (from) => {
|
|
128
|
-
if (from === 'layer' && !props.closeOnClickModal) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
emit('update:visible', false);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const changeBodyCls = (isVisible) => {
|
|
135
|
-
const hideScrollWindowCnt = root?.getElementsByClassName('scroll-lock')?.length;
|
|
136
|
-
const bodyElem = document.body;
|
|
137
|
-
|
|
138
|
-
if (isVisible) { // window open
|
|
139
|
-
if (props.hideScroll) {
|
|
140
|
-
// hideScroll 시, body 우측 padding 추가 & overflow hidden class 추가
|
|
141
|
-
if (!hideScrollWindowCnt) {
|
|
142
|
-
const scrollWidth = getVScrollWidth();
|
|
143
|
-
bodyElem.style.paddingRight = `${scrollWidth}px`;
|
|
144
|
-
}
|
|
145
|
-
bodyElem.classList.add('ev-window-scroll-lock');
|
|
146
|
-
}
|
|
147
|
-
} else if (props.hideScroll && hideScrollWindowCnt === 1) { // window close
|
|
148
|
-
bodyElem.style.removeProperty('padding-right');
|
|
149
|
-
bodyElem.classList.remove('ev-window-scroll-lock');
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
setBasePosition();
|
|
154
|
-
|
|
155
|
-
watch(
|
|
156
|
-
() => props.visible,
|
|
157
|
-
async (newVal) => {
|
|
158
|
-
changeBodyCls(newVal);
|
|
159
|
-
if (newVal) {
|
|
160
|
-
await nextTick(() => {
|
|
161
|
-
setBasePosition();
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
},
|
|
165
|
-
);
|
|
166
|
-
|
|
167
|
-
return {
|
|
168
|
-
windowRef,
|
|
169
|
-
headerRef,
|
|
170
|
-
isFullExpandWindow,
|
|
171
|
-
maximizableIcon,
|
|
172
|
-
baseStyle,
|
|
173
|
-
closeWin,
|
|
174
|
-
numberToUnit,
|
|
175
|
-
removeUnit,
|
|
176
|
-
};
|
|
177
|
-
};
|
|
178
|
-
|
|
179
|
-
const useMouseEvent = (param) => {
|
|
180
|
-
const { props, emit } = getCurrentInstance();
|
|
181
|
-
const {
|
|
182
|
-
windowRef,
|
|
183
|
-
headerRef,
|
|
184
|
-
isFullExpandWindow,
|
|
185
|
-
numberToUnit,
|
|
186
|
-
removeUnit,
|
|
187
|
-
} = param;
|
|
188
|
-
|
|
189
|
-
const draggingMinSize = 50;
|
|
190
|
-
const grabbingBorderSize = 5;
|
|
191
|
-
const dragStyle = reactive({});
|
|
192
|
-
const clickedInfo = reactive({
|
|
193
|
-
state: '',
|
|
194
|
-
pressedSpot: '',
|
|
195
|
-
top: 0,
|
|
196
|
-
left: 0,
|
|
197
|
-
width: 0,
|
|
198
|
-
height: 0,
|
|
199
|
-
clientX: 0,
|
|
200
|
-
clientY: 0,
|
|
201
|
-
});
|
|
202
|
-
const draggedInfo = reactive({
|
|
203
|
-
top: 0,
|
|
204
|
-
left: 0,
|
|
205
|
-
});
|
|
206
|
-
const grabbingBorderPosInfo = reactive({
|
|
207
|
-
top: false,
|
|
208
|
-
right: false,
|
|
209
|
-
left: false,
|
|
210
|
-
bottom: false,
|
|
211
|
-
});
|
|
212
|
-
const beforeExpandPosInfo = reactive({
|
|
213
|
-
width: null,
|
|
214
|
-
height: null,
|
|
215
|
-
top: null,
|
|
216
|
-
left: null,
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
const isInHeader = (x, y) => {
|
|
220
|
-
if (x == null || y == null) {
|
|
221
|
-
return false;
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const rect = windowRef.value.getBoundingClientRect();
|
|
225
|
-
const posX = +x - rect.left;
|
|
226
|
-
const posY = +y - rect.top;
|
|
227
|
-
const headerAreaStyleInfo = headerRef.value.style;
|
|
228
|
-
const headerPaddingInfo = {
|
|
229
|
-
top: removeUnit(headerAreaStyleInfo.paddingTop, 'vertical'),
|
|
230
|
-
left: removeUnit(headerAreaStyleInfo.paddingLeft, 'horizontal'),
|
|
231
|
-
right: removeUnit(headerAreaStyleInfo.paddingRight, 'horizontal'),
|
|
232
|
-
};
|
|
233
|
-
const startPosX = headerPaddingInfo.left;
|
|
234
|
-
const endPosX = rect.width - headerPaddingInfo.right;
|
|
235
|
-
const startPosY = headerPaddingInfo.top;
|
|
236
|
-
const endPosY = startPosY + headerRef.value.offsetHeight;
|
|
237
|
-
|
|
238
|
-
return posX > startPosX && posX < endPosX && posY > startPosY && posY < endPosY;
|
|
239
|
-
};
|
|
240
|
-
|
|
241
|
-
const setDragStyle = (paramObj) => {
|
|
242
|
-
if (paramObj === null || typeof paramObj !== 'object') {
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
let top;
|
|
247
|
-
let left;
|
|
248
|
-
let width;
|
|
249
|
-
let height;
|
|
250
|
-
let tMinWidth;
|
|
251
|
-
let tMinHeight;
|
|
252
|
-
const windowEl = windowRef.value;
|
|
253
|
-
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
254
|
-
|
|
255
|
-
if (hasOwnProperty.call(paramObj, 'top')) {
|
|
256
|
-
top = paramObj.top;
|
|
257
|
-
} else {
|
|
258
|
-
top = clickedInfo.top;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (hasOwnProperty.call(paramObj, 'left')) {
|
|
262
|
-
left = paramObj.left;
|
|
263
|
-
} else {
|
|
264
|
-
left = clickedInfo.left;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
if (hasOwnProperty.call(paramObj, 'width')) {
|
|
268
|
-
width = paramObj.width;
|
|
269
|
-
} else {
|
|
270
|
-
width = windowEl.offsetWidth;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
if (hasOwnProperty.call(paramObj, 'height')) {
|
|
274
|
-
height = paramObj.height;
|
|
275
|
-
} else {
|
|
276
|
-
height = windowEl.offsetHeight;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
if (hasOwnProperty.call(paramObj, 'minWidth')) {
|
|
280
|
-
tMinWidth = paramObj.minWidth;
|
|
281
|
-
} else {
|
|
282
|
-
tMinWidth = props.minWidth;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (hasOwnProperty.call(paramObj, 'minHeight')) {
|
|
286
|
-
tMinHeight = paramObj.minHeight;
|
|
287
|
-
} else {
|
|
288
|
-
tMinHeight = props.minHeight;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
width = removeUnit(width, 'horizontal') > removeUnit(tMinWidth, 'horizontal') ? width : tMinWidth;
|
|
292
|
-
height = removeUnit(height, 'vertical') > removeUnit(tMinHeight, 'vertical') ? height : tMinHeight;
|
|
293
|
-
|
|
294
|
-
dragStyle.top = numberToUnit(top);
|
|
295
|
-
dragStyle.left = numberToUnit(left);
|
|
296
|
-
dragStyle.width = numberToUnit(width);
|
|
297
|
-
dragStyle.height = numberToUnit(height);
|
|
298
|
-
dragStyle.minWidth = numberToUnit(tMinWidth);
|
|
299
|
-
dragStyle.minHeight = numberToUnit(tMinHeight);
|
|
300
|
-
};
|
|
301
|
-
|
|
302
|
-
const changeMouseCursor = (e) => {
|
|
303
|
-
if (!windowRef.value || clickedInfo.pressedSpot) {
|
|
304
|
-
return;
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
if (props.resizable) {
|
|
308
|
-
const rect = windowRef.value.getBoundingClientRect();
|
|
309
|
-
const x = e.clientX - rect.left;
|
|
310
|
-
const y = e.clientY - rect.top;
|
|
311
|
-
const top = y < grabbingBorderSize;
|
|
312
|
-
const left = x < grabbingBorderSize;
|
|
313
|
-
const right = x >= (rect.width - grabbingBorderSize);
|
|
314
|
-
const bottom = y >= (rect.height - grabbingBorderSize);
|
|
315
|
-
|
|
316
|
-
if ((top && left) || (bottom && right)) {
|
|
317
|
-
windowRef.value.style.cursor = 'nwse-resize';
|
|
318
|
-
} else if ((top && right) || (bottom && left)) {
|
|
319
|
-
windowRef.value.style.cursor = 'nesw-resize';
|
|
320
|
-
} else if (right || left) {
|
|
321
|
-
windowRef.value.style.cursor = 'ew-resize';
|
|
322
|
-
} else if (bottom || top) {
|
|
323
|
-
windowRef.value.style.cursor = 'ns-resize';
|
|
324
|
-
} else if (props.draggable && isInHeader(e.clientX, e.clientY)) {
|
|
325
|
-
windowRef.value.style.cursor = 'move';
|
|
326
|
-
} else {
|
|
327
|
-
windowRef.value.style.cursor = 'default';
|
|
328
|
-
}
|
|
329
|
-
} else if (props.draggable && isInHeader(e.clientX, e.clientY)) {
|
|
330
|
-
windowRef.value.style.cursor = 'move';
|
|
331
|
-
} else {
|
|
332
|
-
windowRef.value.style.cursor = 'default';
|
|
333
|
-
}
|
|
334
|
-
};
|
|
335
|
-
|
|
336
|
-
// window resize
|
|
337
|
-
const resizeWindow = (e) => {
|
|
338
|
-
const windowWidth = window.innerWidth;
|
|
339
|
-
const windowHeight = window.innerHeight;
|
|
340
|
-
const isTop = grabbingBorderPosInfo.top;
|
|
341
|
-
const isLeft = grabbingBorderPosInfo.left;
|
|
342
|
-
const isRight = grabbingBorderPosInfo.right;
|
|
343
|
-
const isBottom = grabbingBorderPosInfo.bottom;
|
|
344
|
-
const minWidth = removeUnit(props.minWidth, 'horizontal');
|
|
345
|
-
const minHeight = removeUnit(props.minHeight, 'vertical');
|
|
346
|
-
const clientX = e.clientX >= windowWidth ? windowWidth : e.clientX;
|
|
347
|
-
let clientY = e.clientY >= windowHeight ? windowHeight : e.clientY;
|
|
348
|
-
clientY = e.clientY > 0 ? clientY : 0;
|
|
349
|
-
const diffX = clientX - clickedInfo.clientX;
|
|
350
|
-
const diffY = clientY - clickedInfo.clientY;
|
|
351
|
-
|
|
352
|
-
let top = clickedInfo.top;
|
|
353
|
-
let left = clickedInfo.left;
|
|
354
|
-
let width = clickedInfo.width;
|
|
355
|
-
let height = clickedInfo.height;
|
|
356
|
-
const maxTop = (top + clickedInfo.height) - minHeight;
|
|
357
|
-
const maxLeft = (left + clickedInfo.width) - minWidth;
|
|
358
|
-
|
|
359
|
-
if (isTop) {
|
|
360
|
-
top = clickedInfo.top + diffY;
|
|
361
|
-
height = clickedInfo.height - diffY;
|
|
362
|
-
|
|
363
|
-
if (top > maxTop) {
|
|
364
|
-
top = maxTop;
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
if (isLeft) {
|
|
369
|
-
left = clickedInfo.left + diffX;
|
|
370
|
-
width = clickedInfo.width - diffX;
|
|
371
|
-
|
|
372
|
-
if (left > maxLeft) {
|
|
373
|
-
left = maxLeft;
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
if (isRight) {
|
|
378
|
-
width = clickedInfo.width + diffX;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
if (isBottom) {
|
|
382
|
-
height = clickedInfo.height + diffY;
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
width = Math.min(Math.max(width, minWidth), windowWidth);
|
|
386
|
-
height = Math.min(Math.max(height, minHeight), windowHeight);
|
|
387
|
-
|
|
388
|
-
const positionInfo = { top, left, width, height };
|
|
389
|
-
setDragStyle(positionInfo);
|
|
390
|
-
emit('resize', e, { ...positionInfo });
|
|
391
|
-
};
|
|
392
|
-
|
|
393
|
-
// 브라우저 상하 위치 제약
|
|
394
|
-
const getValidTop = (windowHeight, top) => {
|
|
395
|
-
let tempTop = top;
|
|
396
|
-
|
|
397
|
-
if (tempTop < 0) { // 상
|
|
398
|
-
tempTop = 0;
|
|
399
|
-
} else if (tempTop > windowHeight - draggingMinSize) { // 하
|
|
400
|
-
tempTop = Math.floor(windowHeight - draggingMinSize);
|
|
401
|
-
}
|
|
402
|
-
return tempTop;
|
|
403
|
-
};
|
|
404
|
-
// 브라우저 좌우 위치 제약
|
|
405
|
-
const getValidLeft = (windowWidth, left) => {
|
|
406
|
-
let tempLeft = left;
|
|
407
|
-
if (tempLeft < -(clickedInfo.width - draggingMinSize)) { // 좌
|
|
408
|
-
tempLeft = -Math.floor(clickedInfo.width - draggingMinSize);
|
|
409
|
-
} else if (tempLeft > windowWidth - draggingMinSize) { // 우
|
|
410
|
-
tempLeft = Math.floor(windowWidth - draggingMinSize);
|
|
411
|
-
}
|
|
412
|
-
return tempLeft;
|
|
413
|
-
};
|
|
414
|
-
|
|
415
|
-
// mousedown > mousemove: 마우스 드래그
|
|
416
|
-
const dragging = (e) => {
|
|
417
|
-
e.preventDefault();
|
|
418
|
-
clickedInfo.state = 'mousedown-mousemove';
|
|
419
|
-
|
|
420
|
-
// window header를 통해 mouseMove 됐을 경우
|
|
421
|
-
if (props.draggable && clickedInfo.pressedSpot === 'header') {
|
|
422
|
-
const windowWidth = document.documentElement.clientWidth;
|
|
423
|
-
const windowHeight = document.documentElement.clientHeight;
|
|
424
|
-
const diffTop = e.clientY - clickedInfo.clientY;
|
|
425
|
-
const diffLeft = e.clientX - clickedInfo.clientX;
|
|
426
|
-
|
|
427
|
-
let tempTop = clickedInfo.top + diffTop;
|
|
428
|
-
let tempLeft = clickedInfo.left + diffLeft;
|
|
429
|
-
|
|
430
|
-
tempTop = getValidTop(windowHeight, tempTop);
|
|
431
|
-
tempLeft = getValidLeft(windowWidth, tempLeft);
|
|
432
|
-
|
|
433
|
-
setDragStyle({
|
|
434
|
-
top: `${tempTop}px`,
|
|
435
|
-
left: `${tempLeft}px`,
|
|
436
|
-
width: dragStyle.width ?? props.width,
|
|
437
|
-
height: dragStyle.height ?? props.height,
|
|
438
|
-
});
|
|
439
|
-
} else if (props.resizable && clickedInfo.pressedSpot === 'border') {
|
|
440
|
-
resizeWindow(e);
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
emit('mousedown-mousemove', e);
|
|
444
|
-
};
|
|
445
|
-
|
|
446
|
-
// mousedown > mouseup: 마우스 드래그 종료
|
|
447
|
-
const endDrag = (e) => {
|
|
448
|
-
clickedInfo.state = '';
|
|
449
|
-
clickedInfo.pressedSpot = '';
|
|
450
|
-
|
|
451
|
-
emit('mousedown-mouseup', e);
|
|
452
|
-
|
|
453
|
-
window.removeEventListener('mousemove', dragging);
|
|
454
|
-
window.removeEventListener('mouseup', endDrag);
|
|
455
|
-
};
|
|
456
|
-
|
|
457
|
-
// mousedown: 드래그 시작
|
|
458
|
-
const startDrag = (e) => {
|
|
459
|
-
if (!windowRef.value || (!props.resizable && !props.draggable)) {
|
|
460
|
-
return;
|
|
461
|
-
}
|
|
462
|
-
let pressedSpot = '';
|
|
463
|
-
if (props.resizable) {
|
|
464
|
-
const clientRect = windowRef.value.getBoundingClientRect();
|
|
465
|
-
const x = e.clientX - clientRect.left;
|
|
466
|
-
const y = e.clientY - clientRect.top;
|
|
467
|
-
const isGrabTop = y < grabbingBorderSize;
|
|
468
|
-
const isGrabLeft = x < grabbingBorderSize;
|
|
469
|
-
const isGrabRight = x >= (clientRect.width - grabbingBorderSize);
|
|
470
|
-
const isGrabBottom = y >= (clientRect.height - grabbingBorderSize);
|
|
471
|
-
|
|
472
|
-
grabbingBorderPosInfo.top = isGrabTop;
|
|
473
|
-
grabbingBorderPosInfo.left = isGrabLeft;
|
|
474
|
-
grabbingBorderPosInfo.right = isGrabRight;
|
|
475
|
-
grabbingBorderPosInfo.bottom = isGrabBottom;
|
|
476
|
-
|
|
477
|
-
if (isGrabTop || isGrabLeft || isGrabRight || isGrabBottom) {
|
|
478
|
-
pressedSpot = 'border';
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
|
|
482
|
-
if (pressedSpot !== 'border' && isInHeader(e.clientX, e.clientY)) {
|
|
483
|
-
pressedSpot = 'header';
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
if (!pressedSpot
|
|
487
|
-
|| (!props.draggable && pressedSpot === 'header')
|
|
488
|
-
|| (!props.resizable && pressedSpot === 'border')
|
|
489
|
-
) {
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
clickedInfo.state = 'mousedown';
|
|
494
|
-
clickedInfo.pressedSpot = pressedSpot;
|
|
495
|
-
clickedInfo.top = windowRef.value.offsetTop;
|
|
496
|
-
clickedInfo.left = windowRef.value.offsetLeft;
|
|
497
|
-
clickedInfo.width = windowRef.value.offsetWidth;
|
|
498
|
-
clickedInfo.height = windowRef.value.offsetHeight;
|
|
499
|
-
clickedInfo.clientX = e.clientX;
|
|
500
|
-
clickedInfo.clientY = e.clientY;
|
|
501
|
-
|
|
502
|
-
emit('mousedown', { ...clickedInfo });
|
|
503
|
-
|
|
504
|
-
window.addEventListener('mousemove', dragging);
|
|
505
|
-
window.addEventListener('mouseup', endDrag);
|
|
506
|
-
};
|
|
507
|
-
|
|
508
|
-
const moveMouse = (e) => {
|
|
509
|
-
if (!props.draggable && !props.resizable) {
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
changeMouseCursor(e);
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
const clickExpandBtn = () => {
|
|
516
|
-
isFullExpandWindow.value = !isFullExpandWindow.value;
|
|
517
|
-
nextTick(() => {
|
|
518
|
-
if (isFullExpandWindow.value) {
|
|
519
|
-
beforeExpandPosInfo.top = windowRef.value.offsetTop;
|
|
520
|
-
beforeExpandPosInfo.left = windowRef.value.offsetLeft;
|
|
521
|
-
beforeExpandPosInfo.width = windowRef.value.offsetWidth;
|
|
522
|
-
beforeExpandPosInfo.height = windowRef.value.offsetHeight;
|
|
523
|
-
|
|
524
|
-
setDragStyle({
|
|
525
|
-
top: 0,
|
|
526
|
-
left: 0,
|
|
527
|
-
width: document.body.clientWidth,
|
|
528
|
-
height: document.body.clientHeight,
|
|
529
|
-
});
|
|
530
|
-
} else {
|
|
531
|
-
setDragStyle({
|
|
532
|
-
top: beforeExpandPosInfo.top,
|
|
533
|
-
left: beforeExpandPosInfo.left,
|
|
534
|
-
width: beforeExpandPosInfo.width,
|
|
535
|
-
height: beforeExpandPosInfo.height,
|
|
536
|
-
});
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
emit('expand', {
|
|
540
|
-
top: beforeExpandPosInfo.top,
|
|
541
|
-
left: beforeExpandPosInfo.left,
|
|
542
|
-
width: beforeExpandPosInfo.width,
|
|
543
|
-
height: beforeExpandPosInfo.height,
|
|
544
|
-
});
|
|
545
|
-
});
|
|
546
|
-
};
|
|
547
|
-
|
|
548
|
-
const initWindowInfo = () => {
|
|
549
|
-
isFullExpandWindow.value = false;
|
|
550
|
-
|
|
551
|
-
clickedInfo.state = '';
|
|
552
|
-
clickedInfo.pressedSpot = '';
|
|
553
|
-
clickedInfo.top = 0;
|
|
554
|
-
clickedInfo.left = 0;
|
|
555
|
-
clickedInfo.width = 0;
|
|
556
|
-
clickedInfo.height = 0;
|
|
557
|
-
clickedInfo.clientX = 0;
|
|
558
|
-
clickedInfo.clientY = 0;
|
|
559
|
-
|
|
560
|
-
draggedInfo.top = 0;
|
|
561
|
-
draggedInfo.left = 0;
|
|
562
|
-
|
|
563
|
-
grabbingBorderPosInfo.top = false;
|
|
564
|
-
grabbingBorderPosInfo.left = false;
|
|
565
|
-
grabbingBorderPosInfo.right = false;
|
|
566
|
-
grabbingBorderPosInfo.bottom = false;
|
|
567
|
-
|
|
568
|
-
beforeExpandPosInfo.top = null;
|
|
569
|
-
beforeExpandPosInfo.left = null;
|
|
570
|
-
beforeExpandPosInfo.width = null;
|
|
571
|
-
beforeExpandPosInfo.height = null;
|
|
572
|
-
|
|
573
|
-
Object.keys(dragStyle).forEach((key) => {
|
|
574
|
-
delete dragStyle[key];
|
|
575
|
-
});
|
|
576
|
-
};
|
|
577
|
-
|
|
578
|
-
watch(
|
|
579
|
-
() => props.visible,
|
|
580
|
-
(newVal) => {
|
|
581
|
-
if (!newVal) {
|
|
582
|
-
initWindowInfo();
|
|
583
|
-
}
|
|
584
|
-
},
|
|
585
|
-
);
|
|
586
|
-
|
|
587
|
-
return {
|
|
588
|
-
dragStyle,
|
|
589
|
-
startDrag,
|
|
590
|
-
moveMouse,
|
|
591
|
-
clickExpandBtn,
|
|
592
|
-
};
|
|
593
|
-
};
|
|
594
|
-
|
|
595
|
-
const activeWindows = (() => {
|
|
596
|
-
let windows = [];
|
|
597
|
-
let sequence = 0;
|
|
598
|
-
|
|
599
|
-
return {
|
|
600
|
-
add(activeWindow) {
|
|
601
|
-
if (activeWindow === null || activeWindow === undefined) return;
|
|
602
|
-
|
|
603
|
-
activeWindow.sequence = sequence++;
|
|
604
|
-
windows.push(activeWindow);
|
|
605
|
-
|
|
606
|
-
// eslint-disable-next-line consistent-return
|
|
607
|
-
return activeWindow.sequence;
|
|
608
|
-
},
|
|
609
|
-
remove(inactiveWindow) {
|
|
610
|
-
if (inactiveWindow === null || inactiveWindow === undefined) return;
|
|
611
|
-
windows = windows.filter(activeWindow => activeWindow.sequence !== inactiveWindow.sequence);
|
|
612
|
-
},
|
|
613
|
-
|
|
614
|
-
get windows() {
|
|
615
|
-
return windows.slice();
|
|
616
|
-
},
|
|
617
|
-
getWindowBySequence(targetSequence) {
|
|
618
|
-
return windows.find(activeWindow => activeWindow.sequence === targetSequence);
|
|
619
|
-
},
|
|
620
|
-
|
|
621
|
-
isEmpty() {
|
|
622
|
-
return windows.length <= 0;
|
|
623
|
-
},
|
|
624
|
-
isFirstWindowOpen() {
|
|
625
|
-
return sequence === 1;
|
|
626
|
-
},
|
|
627
|
-
};
|
|
628
|
-
})();
|
|
629
|
-
|
|
630
|
-
const zIndexService = (() => {
|
|
631
|
-
const LOWER = 700;
|
|
632
|
-
const UPPER = 750;
|
|
633
|
-
|
|
634
|
-
const INCREMENT = 1;
|
|
635
|
-
const PADDING = INCREMENT * 2;
|
|
636
|
-
|
|
637
|
-
const UPPER_LIMIT = UPPER - PADDING;
|
|
638
|
-
|
|
639
|
-
let current = LOWER;
|
|
640
|
-
|
|
641
|
-
return {
|
|
642
|
-
getNext() {
|
|
643
|
-
if (current >= UPPER_LIMIT) {
|
|
644
|
-
return UPPER_LIMIT;
|
|
645
|
-
}
|
|
646
|
-
current += INCREMENT;
|
|
647
|
-
return current;
|
|
648
|
-
},
|
|
649
|
-
getNextOverLimit() {
|
|
650
|
-
return UPPER_LIMIT + INCREMENT;
|
|
651
|
-
},
|
|
652
|
-
getPrevFrom(index) {
|
|
653
|
-
const prev = current - (index * INCREMENT);
|
|
654
|
-
|
|
655
|
-
if (prev <= LOWER) return LOWER;
|
|
656
|
-
return prev;
|
|
657
|
-
},
|
|
658
|
-
isUpperLimitClose() {
|
|
659
|
-
return current >= UPPER_LIMIT;
|
|
660
|
-
},
|
|
661
|
-
resetToLower() {
|
|
662
|
-
current = LOWER;
|
|
663
|
-
},
|
|
664
|
-
getAllocableCount() {
|
|
665
|
-
return Math.floor((UPPER_LIMIT - LOWER) / INCREMENT);
|
|
666
|
-
},
|
|
667
|
-
};
|
|
668
|
-
})();
|
|
669
|
-
|
|
670
|
-
const getZIndexFromElement = (element) => {
|
|
671
|
-
const zIndex = window.getComputedStyle(element).getPropertyValue('z-index').trim();
|
|
672
|
-
|
|
673
|
-
if (!zIndex || isNaN(zIndex)) return 700; // window 초기 z-index 값
|
|
674
|
-
|
|
675
|
-
return parseInt(zIndex);
|
|
676
|
-
};
|
|
677
|
-
|
|
678
|
-
const getActiveWindowsOrderByZIndexAsc = () => {
|
|
679
|
-
// zIndex 클수록, 최근에 열린 것일수록(sequence 클수록) 뒤에 위치
|
|
680
|
-
const compareByZIndex = (window1, window2) => {
|
|
681
|
-
if (window1.zIndex > window2.zIndex) return 1;
|
|
682
|
-
if (window1.zIndex < window2.zIndex) return -1;
|
|
683
|
-
|
|
684
|
-
if (window1.sequence > window2.sequence) return 1;
|
|
685
|
-
return -1;
|
|
686
|
-
};
|
|
687
|
-
|
|
688
|
-
const activeWindowsSorted = Array.prototype.map.call(activeWindows.windows, activeWindow => ({
|
|
689
|
-
...activeWindow,
|
|
690
|
-
zIndex: getZIndexFromElement(activeWindow.elem),
|
|
691
|
-
})).sort(compareByZIndex);
|
|
692
|
-
|
|
693
|
-
return activeWindowsSorted;
|
|
694
|
-
};
|
|
695
|
-
|
|
696
|
-
const useEscCloseAndFocusable = ({ closeWin, windowRef }) => {
|
|
697
|
-
const { props } = getCurrentInstance();
|
|
698
|
-
|
|
699
|
-
let sequence = null;
|
|
700
|
-
let timer = null;
|
|
701
|
-
|
|
702
|
-
// escClose 관련 로직 시작
|
|
703
|
-
const addActiveWindow = () => {
|
|
704
|
-
const windowSequence = activeWindows.add({
|
|
705
|
-
sequence,
|
|
706
|
-
closeWin,
|
|
707
|
-
elem: windowRef.value,
|
|
708
|
-
escClose: props.escClose,
|
|
709
|
-
});
|
|
710
|
-
return windowSequence;
|
|
711
|
-
};
|
|
712
|
-
|
|
713
|
-
const removeInactiveWindow = (inactiveWindow) => {
|
|
714
|
-
activeWindows.remove(inactiveWindow);
|
|
715
|
-
};
|
|
716
|
-
|
|
717
|
-
const keydownEsc = (event) => {
|
|
718
|
-
if (activeWindows.isEmpty()) return;
|
|
719
|
-
|
|
720
|
-
const { code } = event;
|
|
721
|
-
if (code !== 'Escape') return;
|
|
722
|
-
|
|
723
|
-
const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
|
|
724
|
-
const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
|
|
725
|
-
|
|
726
|
-
// 예시 상황) Nested에서 외부 Window의 escClose는 true이고, 내부 Window의 escClose는 false인 경우,
|
|
727
|
-
// esc 눌러도 외부 Window는 닫히지 않고, 가장 상단에 있는 내부 Window가 수동으로 닫힌 후에 닫히도록 하기 위해
|
|
728
|
-
if (!topActiveWindow.escClose) return;
|
|
729
|
-
|
|
730
|
-
topActiveWindow.closeWin();
|
|
731
|
-
};
|
|
732
|
-
|
|
733
|
-
const setWindowActive = () => {
|
|
734
|
-
sequence = addActiveWindow();
|
|
735
|
-
// DOM의 dataset에 sequence 값 추가해 식별 가능하도록
|
|
736
|
-
windowRef.value.dataset.sequence = sequence;
|
|
737
|
-
|
|
738
|
-
if (activeWindows.isFirstWindowOpen()) {
|
|
739
|
-
document.addEventListener('keydown', keydownEsc);
|
|
740
|
-
}
|
|
741
|
-
};
|
|
742
|
-
|
|
743
|
-
const setWindowInactive = () => {
|
|
744
|
-
const inactiveWindow = activeWindows.getWindowBySequence(sequence);
|
|
745
|
-
removeInactiveWindow(inactiveWindow);
|
|
746
|
-
};
|
|
747
|
-
// escClose 관련 로직 끝
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
// focusable 관련 로직 시작
|
|
751
|
-
const setZIndexToWindow = ({ elem, zIndex }) => {
|
|
752
|
-
// 모달인 경우에는 dim layer도 같이 z-index 높여준다.
|
|
753
|
-
if (props.isModal) {
|
|
754
|
-
const dimLayerElem = elem.parentElement.getElementsByClassName('ev-window-dim-layer')[0];
|
|
755
|
-
dimLayerElem.style.zIndex = zIndex;
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
elem.style.zIndex = zIndex;
|
|
759
|
-
};
|
|
760
|
-
|
|
761
|
-
const assignZIndex = () => {
|
|
762
|
-
// Window가 1번째로 열릴 때, z-index 값을 시작값으로 설정
|
|
763
|
-
if (activeWindows.windows.length === 1) {
|
|
764
|
-
zIndexService.resetToLower();
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
const nextZIndex = zIndexService.getNext();
|
|
768
|
-
setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
|
|
769
|
-
};
|
|
770
|
-
|
|
771
|
-
const sameAsCurrent = windowData => String(windowData.sequence)
|
|
772
|
-
=== windowRef.value.dataset.sequence;
|
|
773
|
-
|
|
774
|
-
// 할당하려는 z-index 값이 상한일 때
|
|
775
|
-
const reassignZIndex = () => {
|
|
776
|
-
const activeWindowsZIndexAsc = getActiveWindowsOrderByZIndexAsc();
|
|
777
|
-
|
|
778
|
-
const overCountLimit = activeWindows.windows.length > zIndexService.getAllocableCount();
|
|
779
|
-
// 할당 가능한 z-index 수보다 많은 Window를 띄웠을 때
|
|
780
|
-
if (overCountLimit) {
|
|
781
|
-
const activeWindowsZIndexDesc = activeWindowsZIndexAsc.reverse();
|
|
782
|
-
|
|
783
|
-
// z-index 기준 내림차순으로 정렬한 Window의 z-index 값을 UPPER에서 LOWER로 1씩 감소한 값 할당
|
|
784
|
-
let interval = 0;
|
|
785
|
-
activeWindowsZIndexDesc.forEach((activeWindow) => {
|
|
786
|
-
if (sameAsCurrent(activeWindow)) return;
|
|
787
|
-
|
|
788
|
-
const prevZIndex = zIndexService.getPrevFrom(interval++);
|
|
789
|
-
setZIndexToWindow({ elem: activeWindow.elem, zIndex: prevZIndex });
|
|
790
|
-
});
|
|
791
|
-
|
|
792
|
-
// 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
|
|
793
|
-
const nextZIndex = zIndexService.getNextOverLimit();
|
|
794
|
-
setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
|
|
795
|
-
} else {
|
|
796
|
-
zIndexService.resetToLower();
|
|
797
|
-
|
|
798
|
-
activeWindowsZIndexAsc.forEach((activeWindow) => {
|
|
799
|
-
if (sameAsCurrent(activeWindow)) return;
|
|
800
|
-
|
|
801
|
-
const nextZIndex = zIndexService.getNext();
|
|
802
|
-
setZIndexToWindow({ elem: activeWindow.elem, zIndex: nextZIndex });
|
|
803
|
-
});
|
|
804
|
-
|
|
805
|
-
// 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
|
|
806
|
-
const nextZIndex = zIndexService.getNext();
|
|
807
|
-
setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
|
|
808
|
-
}
|
|
809
|
-
};
|
|
810
|
-
|
|
811
|
-
const checkLimitAndSetZIndex = () => {
|
|
812
|
-
if (zIndexService.isUpperLimitClose()) {
|
|
813
|
-
reassignZIndex();
|
|
814
|
-
} else {
|
|
815
|
-
assignZIndex();
|
|
816
|
-
}
|
|
817
|
-
};
|
|
818
|
-
|
|
819
|
-
const setFocus = () => {
|
|
820
|
-
// X 버튼을 클릭했을 때
|
|
821
|
-
if (!windowRef.value) return;
|
|
822
|
-
|
|
823
|
-
// focusable prop이 false인 경우에는 z-index를 높이지 않는다.
|
|
824
|
-
if (!props.focusable) return;
|
|
825
|
-
|
|
826
|
-
const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
|
|
827
|
-
const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
|
|
828
|
-
|
|
829
|
-
const isAlreadyTop = sameAsCurrent(topActiveWindow);
|
|
830
|
-
if (isAlreadyTop) return;
|
|
831
|
-
|
|
832
|
-
checkLimitAndSetZIndex();
|
|
833
|
-
};
|
|
834
|
-
// focusable 관련 로직 끝
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
/*
|
|
838
|
-
실행 시점(=Window 열림):
|
|
839
|
-
visible 초기값이 true일 때 watch를 실행시키지 않아 onMounted hook 사용
|
|
840
|
-
*/
|
|
841
|
-
onMounted(() => {
|
|
842
|
-
if (props.visible) {
|
|
843
|
-
setWindowActive();
|
|
844
|
-
timer = setTimeout(checkLimitAndSetZIndex, 0);
|
|
845
|
-
}
|
|
846
|
-
});
|
|
847
|
-
|
|
848
|
-
/*
|
|
849
|
-
실행 시점(=Window 닫힘):
|
|
850
|
-
예시. 배열을 통해 Window 여러 개 띄울 때, 배열 원소 삭제로 인해 해당 Window가 닫히는 경우
|
|
851
|
-
unmount가 발생해서 watch를 실행히시키지 않아 onBeforeUnmount hook 사용
|
|
852
|
-
*/
|
|
853
|
-
onBeforeUnmount(() => {
|
|
854
|
-
if (props.visible) {
|
|
855
|
-
setWindowInactive();
|
|
856
|
-
clearTimeout(timer);
|
|
857
|
-
}
|
|
858
|
-
});
|
|
859
|
-
|
|
860
|
-
/*
|
|
861
|
-
실행 시점:
|
|
862
|
-
1. visible 값이 false -> true로 변했을 때(=Window 열림)
|
|
863
|
-
2. visible 값이 true -> false로 변했을 때(=Window 닫힙)
|
|
864
|
-
*/
|
|
865
|
-
watch(
|
|
866
|
-
() => props.visible,
|
|
867
|
-
(visible) => {
|
|
868
|
-
nextTick(() => {
|
|
869
|
-
if (visible) {
|
|
870
|
-
// visible 값이 false -> true로 변경되었을 때
|
|
871
|
-
setWindowActive();
|
|
872
|
-
timer = setTimeout(checkLimitAndSetZIndex, 0);
|
|
873
|
-
} else {
|
|
874
|
-
// visible 값이 true -> false로 변경되었을 때
|
|
875
|
-
setWindowInactive();
|
|
876
|
-
clearTimeout(timer);
|
|
877
|
-
}
|
|
878
|
-
});
|
|
879
|
-
});
|
|
880
|
-
|
|
881
|
-
watch(
|
|
882
|
-
() => props.escClose,
|
|
883
|
-
(escClose) => {
|
|
884
|
-
if (!props.visible) return;
|
|
885
|
-
const currentWindow = activeWindows.getWindowBySequence(sequence);
|
|
886
|
-
if (currentWindow) currentWindow.escClose = escClose;
|
|
887
|
-
},
|
|
888
|
-
);
|
|
889
|
-
|
|
890
|
-
return {
|
|
891
|
-
setFocus,
|
|
892
|
-
};
|
|
893
|
-
};
|
|
894
|
-
|
|
895
|
-
export {
|
|
896
|
-
useModel,
|
|
897
|
-
useMouseEvent,
|
|
898
|
-
useEscCloseAndFocusable,
|
|
899
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
getCurrentInstance,
|
|
3
|
+
ref,
|
|
4
|
+
computed,
|
|
5
|
+
reactive,
|
|
6
|
+
watch,
|
|
7
|
+
nextTick,
|
|
8
|
+
onMounted,
|
|
9
|
+
onBeforeUnmount,
|
|
10
|
+
} from 'vue';
|
|
11
|
+
|
|
12
|
+
// 세로 스크롤 너비
|
|
13
|
+
const getVScrollWidth = () => window.innerWidth - document.documentElement.clientWidth;
|
|
14
|
+
// 가로 스크롤 너비
|
|
15
|
+
// const getHScrollWidth = () => window.innerHeight - document.documentElement.clientHeight;
|
|
16
|
+
|
|
17
|
+
const useModel = () => {
|
|
18
|
+
const { props, emit } = getCurrentInstance();
|
|
19
|
+
|
|
20
|
+
const windowRef = ref();
|
|
21
|
+
const headerRef = ref();
|
|
22
|
+
const isFullExpandWindow = ref(false);
|
|
23
|
+
const maximizableIcon = computed(() => (isFullExpandWindow.value ? 'ev-icon-compress' : 'ev-icon-expand'));
|
|
24
|
+
|
|
25
|
+
// body에 #ev-window-modal div append
|
|
26
|
+
let root = document.getElementById('ev-window-modal');
|
|
27
|
+
const initWrapperDiv = () => {
|
|
28
|
+
if (!root) {
|
|
29
|
+
const rootDiv = document.createElement('div');
|
|
30
|
+
rootDiv.id = 'ev-window-modal';
|
|
31
|
+
document.body.appendChild(rootDiv);
|
|
32
|
+
root = document.getElementById('ev-window-modal');
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
initWrapperDiv();
|
|
36
|
+
|
|
37
|
+
const numberToUnit = (input) => {
|
|
38
|
+
let output;
|
|
39
|
+
let result;
|
|
40
|
+
|
|
41
|
+
if (typeof input === 'string' || typeof input === 'number') {
|
|
42
|
+
const match = (/^(normal|(-*\d+(?:\.\d+)?)(px|%|vw|vh)?)$/).exec(input);
|
|
43
|
+
output = match ? { value: +match[2], unit: match[3] || undefined } : undefined;
|
|
44
|
+
} else {
|
|
45
|
+
output = undefined;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (output === null || output === undefined) {
|
|
49
|
+
result = undefined;
|
|
50
|
+
} else if (output.unit) {
|
|
51
|
+
result = `${output.value}${output.unit}`;
|
|
52
|
+
} else {
|
|
53
|
+
result = `${output.value}px`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return result;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const removeUnit = (input, direction = 'horizontal') => {
|
|
60
|
+
if (typeof input === 'number') {
|
|
61
|
+
return input;
|
|
62
|
+
} else if (!input) {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let result = 0;
|
|
67
|
+
const match = (/^(normal|(\d+(?:\.\d+)?)(px|%|vw|vh)?)$/).exec(input);
|
|
68
|
+
|
|
69
|
+
if (direction && ['%', 'vw', 'vh'].includes(match[3]) && match[2]) {
|
|
70
|
+
const standard = direction === 'horizontal' ? window.innerWidth : window.innerHeight;
|
|
71
|
+
result = Math.floor((standard * +match[2]) / 100);
|
|
72
|
+
} else if (match[2]) {
|
|
73
|
+
result = +match[2];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return result;
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// set base style
|
|
80
|
+
const basePosition = reactive({});
|
|
81
|
+
const baseStyle = computed(() => ({
|
|
82
|
+
...props.style,
|
|
83
|
+
...basePosition,
|
|
84
|
+
}));
|
|
85
|
+
|
|
86
|
+
const setBasePosition = () => {
|
|
87
|
+
basePosition.position = 'fixed';
|
|
88
|
+
|
|
89
|
+
if (props.fullscreen) {
|
|
90
|
+
basePosition.width = '100%';
|
|
91
|
+
basePosition.height = '100%';
|
|
92
|
+
basePosition.top = 0;
|
|
93
|
+
basePosition.left = 0;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
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
|
+
}
|
|
114
|
+
|
|
115
|
+
basePosition.top = `calc((100% - ${basePosition.height}) / 2)`;
|
|
116
|
+
basePosition.left = `calc((100% - ${basePosition.width}) / 2)`;
|
|
117
|
+
|
|
118
|
+
if (removeUnit(props.width, 'horizontal') > window.innerWidth) {
|
|
119
|
+
basePosition.left = 0;
|
|
120
|
+
}
|
|
121
|
+
if (removeUnit(props.height, 'vertical') > window.innerHeight) {
|
|
122
|
+
basePosition.top = 0;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// close window
|
|
127
|
+
const closeWin = (from) => {
|
|
128
|
+
if (from === 'layer' && !props.closeOnClickModal) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
emit('update:visible', false);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const changeBodyCls = (isVisible) => {
|
|
135
|
+
const hideScrollWindowCnt = root?.getElementsByClassName('scroll-lock')?.length;
|
|
136
|
+
const bodyElem = document.body;
|
|
137
|
+
|
|
138
|
+
if (isVisible) { // window open
|
|
139
|
+
if (props.hideScroll) {
|
|
140
|
+
// hideScroll 시, body 우측 padding 추가 & overflow hidden class 추가
|
|
141
|
+
if (!hideScrollWindowCnt) {
|
|
142
|
+
const scrollWidth = getVScrollWidth();
|
|
143
|
+
bodyElem.style.paddingRight = `${scrollWidth}px`;
|
|
144
|
+
}
|
|
145
|
+
bodyElem.classList.add('ev-window-scroll-lock');
|
|
146
|
+
}
|
|
147
|
+
} else if (props.hideScroll && hideScrollWindowCnt === 1) { // window close
|
|
148
|
+
bodyElem.style.removeProperty('padding-right');
|
|
149
|
+
bodyElem.classList.remove('ev-window-scroll-lock');
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
setBasePosition();
|
|
154
|
+
|
|
155
|
+
watch(
|
|
156
|
+
() => props.visible,
|
|
157
|
+
async (newVal) => {
|
|
158
|
+
changeBodyCls(newVal);
|
|
159
|
+
if (newVal) {
|
|
160
|
+
await nextTick(() => {
|
|
161
|
+
setBasePosition();
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
windowRef,
|
|
169
|
+
headerRef,
|
|
170
|
+
isFullExpandWindow,
|
|
171
|
+
maximizableIcon,
|
|
172
|
+
baseStyle,
|
|
173
|
+
closeWin,
|
|
174
|
+
numberToUnit,
|
|
175
|
+
removeUnit,
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
const useMouseEvent = (param) => {
|
|
180
|
+
const { props, emit } = getCurrentInstance();
|
|
181
|
+
const {
|
|
182
|
+
windowRef,
|
|
183
|
+
headerRef,
|
|
184
|
+
isFullExpandWindow,
|
|
185
|
+
numberToUnit,
|
|
186
|
+
removeUnit,
|
|
187
|
+
} = param;
|
|
188
|
+
|
|
189
|
+
const draggingMinSize = 50;
|
|
190
|
+
const grabbingBorderSize = 5;
|
|
191
|
+
const dragStyle = reactive({});
|
|
192
|
+
const clickedInfo = reactive({
|
|
193
|
+
state: '',
|
|
194
|
+
pressedSpot: '',
|
|
195
|
+
top: 0,
|
|
196
|
+
left: 0,
|
|
197
|
+
width: 0,
|
|
198
|
+
height: 0,
|
|
199
|
+
clientX: 0,
|
|
200
|
+
clientY: 0,
|
|
201
|
+
});
|
|
202
|
+
const draggedInfo = reactive({
|
|
203
|
+
top: 0,
|
|
204
|
+
left: 0,
|
|
205
|
+
});
|
|
206
|
+
const grabbingBorderPosInfo = reactive({
|
|
207
|
+
top: false,
|
|
208
|
+
right: false,
|
|
209
|
+
left: false,
|
|
210
|
+
bottom: false,
|
|
211
|
+
});
|
|
212
|
+
const beforeExpandPosInfo = reactive({
|
|
213
|
+
width: null,
|
|
214
|
+
height: null,
|
|
215
|
+
top: null,
|
|
216
|
+
left: null,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const isInHeader = (x, y) => {
|
|
220
|
+
if (x == null || y == null) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const rect = windowRef.value.getBoundingClientRect();
|
|
225
|
+
const posX = +x - rect.left;
|
|
226
|
+
const posY = +y - rect.top;
|
|
227
|
+
const headerAreaStyleInfo = headerRef.value.style;
|
|
228
|
+
const headerPaddingInfo = {
|
|
229
|
+
top: removeUnit(headerAreaStyleInfo.paddingTop, 'vertical'),
|
|
230
|
+
left: removeUnit(headerAreaStyleInfo.paddingLeft, 'horizontal'),
|
|
231
|
+
right: removeUnit(headerAreaStyleInfo.paddingRight, 'horizontal'),
|
|
232
|
+
};
|
|
233
|
+
const startPosX = headerPaddingInfo.left;
|
|
234
|
+
const endPosX = rect.width - headerPaddingInfo.right;
|
|
235
|
+
const startPosY = headerPaddingInfo.top;
|
|
236
|
+
const endPosY = startPosY + headerRef.value.offsetHeight;
|
|
237
|
+
|
|
238
|
+
return posX > startPosX && posX < endPosX && posY > startPosY && posY < endPosY;
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const setDragStyle = (paramObj) => {
|
|
242
|
+
if (paramObj === null || typeof paramObj !== 'object') {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
let top;
|
|
247
|
+
let left;
|
|
248
|
+
let width;
|
|
249
|
+
let height;
|
|
250
|
+
let tMinWidth;
|
|
251
|
+
let tMinHeight;
|
|
252
|
+
const windowEl = windowRef.value;
|
|
253
|
+
const hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
254
|
+
|
|
255
|
+
if (hasOwnProperty.call(paramObj, 'top')) {
|
|
256
|
+
top = paramObj.top;
|
|
257
|
+
} else {
|
|
258
|
+
top = clickedInfo.top;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (hasOwnProperty.call(paramObj, 'left')) {
|
|
262
|
+
left = paramObj.left;
|
|
263
|
+
} else {
|
|
264
|
+
left = clickedInfo.left;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (hasOwnProperty.call(paramObj, 'width')) {
|
|
268
|
+
width = paramObj.width;
|
|
269
|
+
} else {
|
|
270
|
+
width = windowEl.offsetWidth;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (hasOwnProperty.call(paramObj, 'height')) {
|
|
274
|
+
height = paramObj.height;
|
|
275
|
+
} else {
|
|
276
|
+
height = windowEl.offsetHeight;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (hasOwnProperty.call(paramObj, 'minWidth')) {
|
|
280
|
+
tMinWidth = paramObj.minWidth;
|
|
281
|
+
} else {
|
|
282
|
+
tMinWidth = props.minWidth;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (hasOwnProperty.call(paramObj, 'minHeight')) {
|
|
286
|
+
tMinHeight = paramObj.minHeight;
|
|
287
|
+
} else {
|
|
288
|
+
tMinHeight = props.minHeight;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
width = removeUnit(width, 'horizontal') > removeUnit(tMinWidth, 'horizontal') ? width : tMinWidth;
|
|
292
|
+
height = removeUnit(height, 'vertical') > removeUnit(tMinHeight, 'vertical') ? height : tMinHeight;
|
|
293
|
+
|
|
294
|
+
dragStyle.top = numberToUnit(top);
|
|
295
|
+
dragStyle.left = numberToUnit(left);
|
|
296
|
+
dragStyle.width = numberToUnit(width);
|
|
297
|
+
dragStyle.height = numberToUnit(height);
|
|
298
|
+
dragStyle.minWidth = numberToUnit(tMinWidth);
|
|
299
|
+
dragStyle.minHeight = numberToUnit(tMinHeight);
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
const changeMouseCursor = (e) => {
|
|
303
|
+
if (!windowRef.value || clickedInfo.pressedSpot) {
|
|
304
|
+
return;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (props.resizable) {
|
|
308
|
+
const rect = windowRef.value.getBoundingClientRect();
|
|
309
|
+
const x = e.clientX - rect.left;
|
|
310
|
+
const y = e.clientY - rect.top;
|
|
311
|
+
const top = y < grabbingBorderSize;
|
|
312
|
+
const left = x < grabbingBorderSize;
|
|
313
|
+
const right = x >= (rect.width - grabbingBorderSize);
|
|
314
|
+
const bottom = y >= (rect.height - grabbingBorderSize);
|
|
315
|
+
|
|
316
|
+
if ((top && left) || (bottom && right)) {
|
|
317
|
+
windowRef.value.style.cursor = 'nwse-resize';
|
|
318
|
+
} else if ((top && right) || (bottom && left)) {
|
|
319
|
+
windowRef.value.style.cursor = 'nesw-resize';
|
|
320
|
+
} else if (right || left) {
|
|
321
|
+
windowRef.value.style.cursor = 'ew-resize';
|
|
322
|
+
} else if (bottom || top) {
|
|
323
|
+
windowRef.value.style.cursor = 'ns-resize';
|
|
324
|
+
} else if (props.draggable && isInHeader(e.clientX, e.clientY)) {
|
|
325
|
+
windowRef.value.style.cursor = 'move';
|
|
326
|
+
} else {
|
|
327
|
+
windowRef.value.style.cursor = 'default';
|
|
328
|
+
}
|
|
329
|
+
} else if (props.draggable && isInHeader(e.clientX, e.clientY)) {
|
|
330
|
+
windowRef.value.style.cursor = 'move';
|
|
331
|
+
} else {
|
|
332
|
+
windowRef.value.style.cursor = 'default';
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
// window resize
|
|
337
|
+
const resizeWindow = (e) => {
|
|
338
|
+
const windowWidth = window.innerWidth;
|
|
339
|
+
const windowHeight = window.innerHeight;
|
|
340
|
+
const isTop = grabbingBorderPosInfo.top;
|
|
341
|
+
const isLeft = grabbingBorderPosInfo.left;
|
|
342
|
+
const isRight = grabbingBorderPosInfo.right;
|
|
343
|
+
const isBottom = grabbingBorderPosInfo.bottom;
|
|
344
|
+
const minWidth = removeUnit(props.minWidth, 'horizontal');
|
|
345
|
+
const minHeight = removeUnit(props.minHeight, 'vertical');
|
|
346
|
+
const clientX = e.clientX >= windowWidth ? windowWidth : e.clientX;
|
|
347
|
+
let clientY = e.clientY >= windowHeight ? windowHeight : e.clientY;
|
|
348
|
+
clientY = e.clientY > 0 ? clientY : 0;
|
|
349
|
+
const diffX = clientX - clickedInfo.clientX;
|
|
350
|
+
const diffY = clientY - clickedInfo.clientY;
|
|
351
|
+
|
|
352
|
+
let top = clickedInfo.top;
|
|
353
|
+
let left = clickedInfo.left;
|
|
354
|
+
let width = clickedInfo.width;
|
|
355
|
+
let height = clickedInfo.height;
|
|
356
|
+
const maxTop = (top + clickedInfo.height) - minHeight;
|
|
357
|
+
const maxLeft = (left + clickedInfo.width) - minWidth;
|
|
358
|
+
|
|
359
|
+
if (isTop) {
|
|
360
|
+
top = clickedInfo.top + diffY;
|
|
361
|
+
height = clickedInfo.height - diffY;
|
|
362
|
+
|
|
363
|
+
if (top > maxTop) {
|
|
364
|
+
top = maxTop;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
if (isLeft) {
|
|
369
|
+
left = clickedInfo.left + diffX;
|
|
370
|
+
width = clickedInfo.width - diffX;
|
|
371
|
+
|
|
372
|
+
if (left > maxLeft) {
|
|
373
|
+
left = maxLeft;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (isRight) {
|
|
378
|
+
width = clickedInfo.width + diffX;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
if (isBottom) {
|
|
382
|
+
height = clickedInfo.height + diffY;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
width = Math.min(Math.max(width, minWidth), windowWidth);
|
|
386
|
+
height = Math.min(Math.max(height, minHeight), windowHeight);
|
|
387
|
+
|
|
388
|
+
const positionInfo = { top, left, width, height };
|
|
389
|
+
setDragStyle(positionInfo);
|
|
390
|
+
emit('resize', e, { ...positionInfo });
|
|
391
|
+
};
|
|
392
|
+
|
|
393
|
+
// 브라우저 상하 위치 제약
|
|
394
|
+
const getValidTop = (windowHeight, top) => {
|
|
395
|
+
let tempTop = top;
|
|
396
|
+
|
|
397
|
+
if (tempTop < 0) { // 상
|
|
398
|
+
tempTop = 0;
|
|
399
|
+
} else if (tempTop > windowHeight - draggingMinSize) { // 하
|
|
400
|
+
tempTop = Math.floor(windowHeight - draggingMinSize);
|
|
401
|
+
}
|
|
402
|
+
return tempTop;
|
|
403
|
+
};
|
|
404
|
+
// 브라우저 좌우 위치 제약
|
|
405
|
+
const getValidLeft = (windowWidth, left) => {
|
|
406
|
+
let tempLeft = left;
|
|
407
|
+
if (tempLeft < -(clickedInfo.width - draggingMinSize)) { // 좌
|
|
408
|
+
tempLeft = -Math.floor(clickedInfo.width - draggingMinSize);
|
|
409
|
+
} else if (tempLeft > windowWidth - draggingMinSize) { // 우
|
|
410
|
+
tempLeft = Math.floor(windowWidth - draggingMinSize);
|
|
411
|
+
}
|
|
412
|
+
return tempLeft;
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
// mousedown > mousemove: 마우스 드래그
|
|
416
|
+
const dragging = (e) => {
|
|
417
|
+
e.preventDefault();
|
|
418
|
+
clickedInfo.state = 'mousedown-mousemove';
|
|
419
|
+
|
|
420
|
+
// window header를 통해 mouseMove 됐을 경우
|
|
421
|
+
if (props.draggable && clickedInfo.pressedSpot === 'header') {
|
|
422
|
+
const windowWidth = document.documentElement.clientWidth;
|
|
423
|
+
const windowHeight = document.documentElement.clientHeight;
|
|
424
|
+
const diffTop = e.clientY - clickedInfo.clientY;
|
|
425
|
+
const diffLeft = e.clientX - clickedInfo.clientX;
|
|
426
|
+
|
|
427
|
+
let tempTop = clickedInfo.top + diffTop;
|
|
428
|
+
let tempLeft = clickedInfo.left + diffLeft;
|
|
429
|
+
|
|
430
|
+
tempTop = getValidTop(windowHeight, tempTop);
|
|
431
|
+
tempLeft = getValidLeft(windowWidth, tempLeft);
|
|
432
|
+
|
|
433
|
+
setDragStyle({
|
|
434
|
+
top: `${tempTop}px`,
|
|
435
|
+
left: `${tempLeft}px`,
|
|
436
|
+
width: dragStyle.width ?? props.width,
|
|
437
|
+
height: dragStyle.height ?? props.height,
|
|
438
|
+
});
|
|
439
|
+
} else if (props.resizable && clickedInfo.pressedSpot === 'border') {
|
|
440
|
+
resizeWindow(e);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
emit('mousedown-mousemove', e);
|
|
444
|
+
};
|
|
445
|
+
|
|
446
|
+
// mousedown > mouseup: 마우스 드래그 종료
|
|
447
|
+
const endDrag = (e) => {
|
|
448
|
+
clickedInfo.state = '';
|
|
449
|
+
clickedInfo.pressedSpot = '';
|
|
450
|
+
|
|
451
|
+
emit('mousedown-mouseup', e);
|
|
452
|
+
|
|
453
|
+
window.removeEventListener('mousemove', dragging);
|
|
454
|
+
window.removeEventListener('mouseup', endDrag);
|
|
455
|
+
};
|
|
456
|
+
|
|
457
|
+
// mousedown: 드래그 시작
|
|
458
|
+
const startDrag = (e) => {
|
|
459
|
+
if (!windowRef.value || (!props.resizable && !props.draggable)) {
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
let pressedSpot = '';
|
|
463
|
+
if (props.resizable) {
|
|
464
|
+
const clientRect = windowRef.value.getBoundingClientRect();
|
|
465
|
+
const x = e.clientX - clientRect.left;
|
|
466
|
+
const y = e.clientY - clientRect.top;
|
|
467
|
+
const isGrabTop = y < grabbingBorderSize;
|
|
468
|
+
const isGrabLeft = x < grabbingBorderSize;
|
|
469
|
+
const isGrabRight = x >= (clientRect.width - grabbingBorderSize);
|
|
470
|
+
const isGrabBottom = y >= (clientRect.height - grabbingBorderSize);
|
|
471
|
+
|
|
472
|
+
grabbingBorderPosInfo.top = isGrabTop;
|
|
473
|
+
grabbingBorderPosInfo.left = isGrabLeft;
|
|
474
|
+
grabbingBorderPosInfo.right = isGrabRight;
|
|
475
|
+
grabbingBorderPosInfo.bottom = isGrabBottom;
|
|
476
|
+
|
|
477
|
+
if (isGrabTop || isGrabLeft || isGrabRight || isGrabBottom) {
|
|
478
|
+
pressedSpot = 'border';
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
if (pressedSpot !== 'border' && isInHeader(e.clientX, e.clientY)) {
|
|
483
|
+
pressedSpot = 'header';
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
if (!pressedSpot
|
|
487
|
+
|| (!props.draggable && pressedSpot === 'header')
|
|
488
|
+
|| (!props.resizable && pressedSpot === 'border')
|
|
489
|
+
) {
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
clickedInfo.state = 'mousedown';
|
|
494
|
+
clickedInfo.pressedSpot = pressedSpot;
|
|
495
|
+
clickedInfo.top = windowRef.value.offsetTop;
|
|
496
|
+
clickedInfo.left = windowRef.value.offsetLeft;
|
|
497
|
+
clickedInfo.width = windowRef.value.offsetWidth;
|
|
498
|
+
clickedInfo.height = windowRef.value.offsetHeight;
|
|
499
|
+
clickedInfo.clientX = e.clientX;
|
|
500
|
+
clickedInfo.clientY = e.clientY;
|
|
501
|
+
|
|
502
|
+
emit('mousedown', { ...clickedInfo });
|
|
503
|
+
|
|
504
|
+
window.addEventListener('mousemove', dragging);
|
|
505
|
+
window.addEventListener('mouseup', endDrag);
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
const moveMouse = (e) => {
|
|
509
|
+
if (!props.draggable && !props.resizable) {
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
changeMouseCursor(e);
|
|
513
|
+
};
|
|
514
|
+
|
|
515
|
+
const clickExpandBtn = () => {
|
|
516
|
+
isFullExpandWindow.value = !isFullExpandWindow.value;
|
|
517
|
+
nextTick(() => {
|
|
518
|
+
if (isFullExpandWindow.value) {
|
|
519
|
+
beforeExpandPosInfo.top = windowRef.value.offsetTop;
|
|
520
|
+
beforeExpandPosInfo.left = windowRef.value.offsetLeft;
|
|
521
|
+
beforeExpandPosInfo.width = windowRef.value.offsetWidth;
|
|
522
|
+
beforeExpandPosInfo.height = windowRef.value.offsetHeight;
|
|
523
|
+
|
|
524
|
+
setDragStyle({
|
|
525
|
+
top: 0,
|
|
526
|
+
left: 0,
|
|
527
|
+
width: document.body.clientWidth,
|
|
528
|
+
height: document.body.clientHeight,
|
|
529
|
+
});
|
|
530
|
+
} else {
|
|
531
|
+
setDragStyle({
|
|
532
|
+
top: beforeExpandPosInfo.top,
|
|
533
|
+
left: beforeExpandPosInfo.left,
|
|
534
|
+
width: beforeExpandPosInfo.width,
|
|
535
|
+
height: beforeExpandPosInfo.height,
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
emit('expand', {
|
|
540
|
+
top: beforeExpandPosInfo.top,
|
|
541
|
+
left: beforeExpandPosInfo.left,
|
|
542
|
+
width: beforeExpandPosInfo.width,
|
|
543
|
+
height: beforeExpandPosInfo.height,
|
|
544
|
+
});
|
|
545
|
+
});
|
|
546
|
+
};
|
|
547
|
+
|
|
548
|
+
const initWindowInfo = () => {
|
|
549
|
+
isFullExpandWindow.value = false;
|
|
550
|
+
|
|
551
|
+
clickedInfo.state = '';
|
|
552
|
+
clickedInfo.pressedSpot = '';
|
|
553
|
+
clickedInfo.top = 0;
|
|
554
|
+
clickedInfo.left = 0;
|
|
555
|
+
clickedInfo.width = 0;
|
|
556
|
+
clickedInfo.height = 0;
|
|
557
|
+
clickedInfo.clientX = 0;
|
|
558
|
+
clickedInfo.clientY = 0;
|
|
559
|
+
|
|
560
|
+
draggedInfo.top = 0;
|
|
561
|
+
draggedInfo.left = 0;
|
|
562
|
+
|
|
563
|
+
grabbingBorderPosInfo.top = false;
|
|
564
|
+
grabbingBorderPosInfo.left = false;
|
|
565
|
+
grabbingBorderPosInfo.right = false;
|
|
566
|
+
grabbingBorderPosInfo.bottom = false;
|
|
567
|
+
|
|
568
|
+
beforeExpandPosInfo.top = null;
|
|
569
|
+
beforeExpandPosInfo.left = null;
|
|
570
|
+
beforeExpandPosInfo.width = null;
|
|
571
|
+
beforeExpandPosInfo.height = null;
|
|
572
|
+
|
|
573
|
+
Object.keys(dragStyle).forEach((key) => {
|
|
574
|
+
delete dragStyle[key];
|
|
575
|
+
});
|
|
576
|
+
};
|
|
577
|
+
|
|
578
|
+
watch(
|
|
579
|
+
() => props.visible,
|
|
580
|
+
(newVal) => {
|
|
581
|
+
if (!newVal) {
|
|
582
|
+
initWindowInfo();
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
);
|
|
586
|
+
|
|
587
|
+
return {
|
|
588
|
+
dragStyle,
|
|
589
|
+
startDrag,
|
|
590
|
+
moveMouse,
|
|
591
|
+
clickExpandBtn,
|
|
592
|
+
};
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
const activeWindows = (() => {
|
|
596
|
+
let windows = [];
|
|
597
|
+
let sequence = 0;
|
|
598
|
+
|
|
599
|
+
return {
|
|
600
|
+
add(activeWindow) {
|
|
601
|
+
if (activeWindow === null || activeWindow === undefined) return;
|
|
602
|
+
|
|
603
|
+
activeWindow.sequence = sequence++;
|
|
604
|
+
windows.push(activeWindow);
|
|
605
|
+
|
|
606
|
+
// eslint-disable-next-line consistent-return
|
|
607
|
+
return activeWindow.sequence;
|
|
608
|
+
},
|
|
609
|
+
remove(inactiveWindow) {
|
|
610
|
+
if (inactiveWindow === null || inactiveWindow === undefined) return;
|
|
611
|
+
windows = windows.filter(activeWindow => activeWindow.sequence !== inactiveWindow.sequence);
|
|
612
|
+
},
|
|
613
|
+
|
|
614
|
+
get windows() {
|
|
615
|
+
return windows.slice();
|
|
616
|
+
},
|
|
617
|
+
getWindowBySequence(targetSequence) {
|
|
618
|
+
return windows.find(activeWindow => activeWindow.sequence === targetSequence);
|
|
619
|
+
},
|
|
620
|
+
|
|
621
|
+
isEmpty() {
|
|
622
|
+
return windows.length <= 0;
|
|
623
|
+
},
|
|
624
|
+
isFirstWindowOpen() {
|
|
625
|
+
return sequence === 1;
|
|
626
|
+
},
|
|
627
|
+
};
|
|
628
|
+
})();
|
|
629
|
+
|
|
630
|
+
const zIndexService = (() => {
|
|
631
|
+
const LOWER = 700;
|
|
632
|
+
const UPPER = 750;
|
|
633
|
+
|
|
634
|
+
const INCREMENT = 1;
|
|
635
|
+
const PADDING = INCREMENT * 2;
|
|
636
|
+
|
|
637
|
+
const UPPER_LIMIT = UPPER - PADDING;
|
|
638
|
+
|
|
639
|
+
let current = LOWER;
|
|
640
|
+
|
|
641
|
+
return {
|
|
642
|
+
getNext() {
|
|
643
|
+
if (current >= UPPER_LIMIT) {
|
|
644
|
+
return UPPER_LIMIT;
|
|
645
|
+
}
|
|
646
|
+
current += INCREMENT;
|
|
647
|
+
return current;
|
|
648
|
+
},
|
|
649
|
+
getNextOverLimit() {
|
|
650
|
+
return UPPER_LIMIT + INCREMENT;
|
|
651
|
+
},
|
|
652
|
+
getPrevFrom(index) {
|
|
653
|
+
const prev = current - (index * INCREMENT);
|
|
654
|
+
|
|
655
|
+
if (prev <= LOWER) return LOWER;
|
|
656
|
+
return prev;
|
|
657
|
+
},
|
|
658
|
+
isUpperLimitClose() {
|
|
659
|
+
return current >= UPPER_LIMIT;
|
|
660
|
+
},
|
|
661
|
+
resetToLower() {
|
|
662
|
+
current = LOWER;
|
|
663
|
+
},
|
|
664
|
+
getAllocableCount() {
|
|
665
|
+
return Math.floor((UPPER_LIMIT - LOWER) / INCREMENT);
|
|
666
|
+
},
|
|
667
|
+
};
|
|
668
|
+
})();
|
|
669
|
+
|
|
670
|
+
const getZIndexFromElement = (element) => {
|
|
671
|
+
const zIndex = window.getComputedStyle(element).getPropertyValue('z-index').trim();
|
|
672
|
+
|
|
673
|
+
if (!zIndex || isNaN(zIndex)) return 700; // window 초기 z-index 값
|
|
674
|
+
|
|
675
|
+
return parseInt(zIndex);
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
const getActiveWindowsOrderByZIndexAsc = () => {
|
|
679
|
+
// zIndex 클수록, 최근에 열린 것일수록(sequence 클수록) 뒤에 위치
|
|
680
|
+
const compareByZIndex = (window1, window2) => {
|
|
681
|
+
if (window1.zIndex > window2.zIndex) return 1;
|
|
682
|
+
if (window1.zIndex < window2.zIndex) return -1;
|
|
683
|
+
|
|
684
|
+
if (window1.sequence > window2.sequence) return 1;
|
|
685
|
+
return -1;
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
const activeWindowsSorted = Array.prototype.map.call(activeWindows.windows, activeWindow => ({
|
|
689
|
+
...activeWindow,
|
|
690
|
+
zIndex: getZIndexFromElement(activeWindow.elem),
|
|
691
|
+
})).sort(compareByZIndex);
|
|
692
|
+
|
|
693
|
+
return activeWindowsSorted;
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
const useEscCloseAndFocusable = ({ closeWin, windowRef }) => {
|
|
697
|
+
const { props } = getCurrentInstance();
|
|
698
|
+
|
|
699
|
+
let sequence = null;
|
|
700
|
+
let timer = null;
|
|
701
|
+
|
|
702
|
+
// escClose 관련 로직 시작
|
|
703
|
+
const addActiveWindow = () => {
|
|
704
|
+
const windowSequence = activeWindows.add({
|
|
705
|
+
sequence,
|
|
706
|
+
closeWin,
|
|
707
|
+
elem: windowRef.value,
|
|
708
|
+
escClose: props.escClose,
|
|
709
|
+
});
|
|
710
|
+
return windowSequence;
|
|
711
|
+
};
|
|
712
|
+
|
|
713
|
+
const removeInactiveWindow = (inactiveWindow) => {
|
|
714
|
+
activeWindows.remove(inactiveWindow);
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
const keydownEsc = (event) => {
|
|
718
|
+
if (activeWindows.isEmpty()) return;
|
|
719
|
+
|
|
720
|
+
const { code } = event;
|
|
721
|
+
if (code !== 'Escape') return;
|
|
722
|
+
|
|
723
|
+
const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
|
|
724
|
+
const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
|
|
725
|
+
|
|
726
|
+
// 예시 상황) Nested에서 외부 Window의 escClose는 true이고, 내부 Window의 escClose는 false인 경우,
|
|
727
|
+
// esc 눌러도 외부 Window는 닫히지 않고, 가장 상단에 있는 내부 Window가 수동으로 닫힌 후에 닫히도록 하기 위해
|
|
728
|
+
if (!topActiveWindow.escClose) return;
|
|
729
|
+
|
|
730
|
+
topActiveWindow.closeWin();
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
const setWindowActive = () => {
|
|
734
|
+
sequence = addActiveWindow();
|
|
735
|
+
// DOM의 dataset에 sequence 값 추가해 식별 가능하도록
|
|
736
|
+
windowRef.value.dataset.sequence = sequence;
|
|
737
|
+
|
|
738
|
+
if (activeWindows.isFirstWindowOpen()) {
|
|
739
|
+
document.addEventListener('keydown', keydownEsc);
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
|
|
743
|
+
const setWindowInactive = () => {
|
|
744
|
+
const inactiveWindow = activeWindows.getWindowBySequence(sequence);
|
|
745
|
+
removeInactiveWindow(inactiveWindow);
|
|
746
|
+
};
|
|
747
|
+
// escClose 관련 로직 끝
|
|
748
|
+
|
|
749
|
+
|
|
750
|
+
// focusable 관련 로직 시작
|
|
751
|
+
const setZIndexToWindow = ({ elem, zIndex }) => {
|
|
752
|
+
// 모달인 경우에는 dim layer도 같이 z-index 높여준다.
|
|
753
|
+
if (props.isModal) {
|
|
754
|
+
const dimLayerElem = elem.parentElement.getElementsByClassName('ev-window-dim-layer')[0];
|
|
755
|
+
dimLayerElem.style.zIndex = zIndex;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
elem.style.zIndex = zIndex;
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
const assignZIndex = () => {
|
|
762
|
+
// Window가 1번째로 열릴 때, z-index 값을 시작값으로 설정
|
|
763
|
+
if (activeWindows.windows.length === 1) {
|
|
764
|
+
zIndexService.resetToLower();
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
const nextZIndex = zIndexService.getNext();
|
|
768
|
+
setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
const sameAsCurrent = windowData => String(windowData.sequence)
|
|
772
|
+
=== windowRef.value.dataset.sequence;
|
|
773
|
+
|
|
774
|
+
// 할당하려는 z-index 값이 상한일 때
|
|
775
|
+
const reassignZIndex = () => {
|
|
776
|
+
const activeWindowsZIndexAsc = getActiveWindowsOrderByZIndexAsc();
|
|
777
|
+
|
|
778
|
+
const overCountLimit = activeWindows.windows.length > zIndexService.getAllocableCount();
|
|
779
|
+
// 할당 가능한 z-index 수보다 많은 Window를 띄웠을 때
|
|
780
|
+
if (overCountLimit) {
|
|
781
|
+
const activeWindowsZIndexDesc = activeWindowsZIndexAsc.reverse();
|
|
782
|
+
|
|
783
|
+
// z-index 기준 내림차순으로 정렬한 Window의 z-index 값을 UPPER에서 LOWER로 1씩 감소한 값 할당
|
|
784
|
+
let interval = 0;
|
|
785
|
+
activeWindowsZIndexDesc.forEach((activeWindow) => {
|
|
786
|
+
if (sameAsCurrent(activeWindow)) return;
|
|
787
|
+
|
|
788
|
+
const prevZIndex = zIndexService.getPrevFrom(interval++);
|
|
789
|
+
setZIndexToWindow({ elem: activeWindow.elem, zIndex: prevZIndex });
|
|
790
|
+
});
|
|
791
|
+
|
|
792
|
+
// 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
|
|
793
|
+
const nextZIndex = zIndexService.getNextOverLimit();
|
|
794
|
+
setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
|
|
795
|
+
} else {
|
|
796
|
+
zIndexService.resetToLower();
|
|
797
|
+
|
|
798
|
+
activeWindowsZIndexAsc.forEach((activeWindow) => {
|
|
799
|
+
if (sameAsCurrent(activeWindow)) return;
|
|
800
|
+
|
|
801
|
+
const nextZIndex = zIndexService.getNext();
|
|
802
|
+
setZIndexToWindow({ elem: activeWindow.elem, zIndex: nextZIndex });
|
|
803
|
+
});
|
|
804
|
+
|
|
805
|
+
// 가장 상단으로 와야하는 현재 Window의 z-index 값을 최대로
|
|
806
|
+
const nextZIndex = zIndexService.getNext();
|
|
807
|
+
setZIndexToWindow({ elem: windowRef.value, zIndex: nextZIndex });
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
const checkLimitAndSetZIndex = () => {
|
|
812
|
+
if (zIndexService.isUpperLimitClose()) {
|
|
813
|
+
reassignZIndex();
|
|
814
|
+
} else {
|
|
815
|
+
assignZIndex();
|
|
816
|
+
}
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
const setFocus = () => {
|
|
820
|
+
// X 버튼을 클릭했을 때
|
|
821
|
+
if (!windowRef.value) return;
|
|
822
|
+
|
|
823
|
+
// focusable prop이 false인 경우에는 z-index를 높이지 않는다.
|
|
824
|
+
if (!props.focusable) return;
|
|
825
|
+
|
|
826
|
+
const activeWindowsSorted = getActiveWindowsOrderByZIndexAsc();
|
|
827
|
+
const topActiveWindow = activeWindowsSorted[activeWindowsSorted.length - 1];
|
|
828
|
+
|
|
829
|
+
const isAlreadyTop = sameAsCurrent(topActiveWindow);
|
|
830
|
+
if (isAlreadyTop) return;
|
|
831
|
+
|
|
832
|
+
checkLimitAndSetZIndex();
|
|
833
|
+
};
|
|
834
|
+
// focusable 관련 로직 끝
|
|
835
|
+
|
|
836
|
+
|
|
837
|
+
/*
|
|
838
|
+
실행 시점(=Window 열림):
|
|
839
|
+
visible 초기값이 true일 때 watch를 실행시키지 않아 onMounted hook 사용
|
|
840
|
+
*/
|
|
841
|
+
onMounted(() => {
|
|
842
|
+
if (props.visible) {
|
|
843
|
+
setWindowActive();
|
|
844
|
+
timer = setTimeout(checkLimitAndSetZIndex, 0);
|
|
845
|
+
}
|
|
846
|
+
});
|
|
847
|
+
|
|
848
|
+
/*
|
|
849
|
+
실행 시점(=Window 닫힘):
|
|
850
|
+
예시. 배열을 통해 Window 여러 개 띄울 때, 배열 원소 삭제로 인해 해당 Window가 닫히는 경우
|
|
851
|
+
unmount가 발생해서 watch를 실행히시키지 않아 onBeforeUnmount hook 사용
|
|
852
|
+
*/
|
|
853
|
+
onBeforeUnmount(() => {
|
|
854
|
+
if (props.visible) {
|
|
855
|
+
setWindowInactive();
|
|
856
|
+
clearTimeout(timer);
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
|
|
860
|
+
/*
|
|
861
|
+
실행 시점:
|
|
862
|
+
1. visible 값이 false -> true로 변했을 때(=Window 열림)
|
|
863
|
+
2. visible 값이 true -> false로 변했을 때(=Window 닫힙)
|
|
864
|
+
*/
|
|
865
|
+
watch(
|
|
866
|
+
() => props.visible,
|
|
867
|
+
(visible) => {
|
|
868
|
+
nextTick(() => {
|
|
869
|
+
if (visible) {
|
|
870
|
+
// visible 값이 false -> true로 변경되었을 때
|
|
871
|
+
setWindowActive();
|
|
872
|
+
timer = setTimeout(checkLimitAndSetZIndex, 0);
|
|
873
|
+
} else {
|
|
874
|
+
// visible 값이 true -> false로 변경되었을 때
|
|
875
|
+
setWindowInactive();
|
|
876
|
+
clearTimeout(timer);
|
|
877
|
+
}
|
|
878
|
+
});
|
|
879
|
+
});
|
|
880
|
+
|
|
881
|
+
watch(
|
|
882
|
+
() => props.escClose,
|
|
883
|
+
(escClose) => {
|
|
884
|
+
if (!props.visible) return;
|
|
885
|
+
const currentWindow = activeWindows.getWindowBySequence(sequence);
|
|
886
|
+
if (currentWindow) currentWindow.escClose = escClose;
|
|
887
|
+
},
|
|
888
|
+
);
|
|
889
|
+
|
|
890
|
+
return {
|
|
891
|
+
setFocus,
|
|
892
|
+
};
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
export {
|
|
896
|
+
useModel,
|
|
897
|
+
useMouseEvent,
|
|
898
|
+
useEscCloseAndFocusable,
|
|
899
|
+
};
|