@kupola/kupola 1.5.2 → 1.5.4
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/css/components-ext.css +58 -0
- package/dist/css/components-ext.css +58 -0
- package/dist/kupola.cjs.js +21 -21
- package/dist/kupola.cjs.js.map +1 -1
- package/dist/kupola.esm.js +1110 -970
- package/dist/kupola.esm.js.map +1 -1
- package/dist/kupola.umd.js +26 -26
- package/dist/kupola.umd.js.map +1 -1
- package/dist/types/kupola.d.ts +135 -0
- package/js/datepicker.js +177 -106
- package/js/dropdown.js +186 -98
- package/js/kupola-config.js +64 -36
- package/js/message.js +66 -53
- package/js/modal.js +62 -59
- package/js/notification.js +63 -60
- package/js/security.js +52 -0
- package/js/select.js +88 -3
- package/js/tooltip.js +300 -297
- package/js/validation.js +155 -140
- package/package.json +2 -1
- package/types/kupola.d.ts +135 -0
package/js/message.js
CHANGED
|
@@ -1,62 +1,75 @@
|
|
|
1
|
+
import { getMessageConfig } from './kupola-config.js';
|
|
2
|
+
|
|
1
3
|
const Message = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
4
|
+
normal: function (message, options = {}) {
|
|
5
|
+
this.show(message, 'normal', options);
|
|
6
|
+
},
|
|
7
|
+
success: function (message, options = {}) {
|
|
8
|
+
this.show(message, 'success', options);
|
|
9
|
+
},
|
|
10
|
+
error: function (message, options = {}) {
|
|
11
|
+
this.show(message, 'error', options);
|
|
12
|
+
},
|
|
13
|
+
warning: function (message, options = {}) {
|
|
14
|
+
this.show(message, 'warning', options);
|
|
15
|
+
},
|
|
16
|
+
info: function (message, options = {}) {
|
|
17
|
+
this.show(message, 'info', options);
|
|
18
|
+
},
|
|
19
|
+
show: function (message, type = 'normal', options = {}) {
|
|
20
|
+
const msgConfig = getMessageConfig();
|
|
21
|
+
const { duration = msgConfig.duration, position = msgConfig.position } = options;
|
|
22
|
+
const maxCount = msgConfig.maxCount || 5;
|
|
23
|
+
|
|
24
|
+
const msg = document.createElement('div');
|
|
25
|
+
msg.className = `ds-message__item ds-message__item--${type}`;
|
|
26
|
+
|
|
27
|
+
const icons = {
|
|
28
|
+
normal: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',
|
|
29
|
+
success: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>',
|
|
30
|
+
error: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>',
|
|
31
|
+
warning: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
|
|
32
|
+
info: '<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
msg.innerHTML = `
|
|
32
36
|
<div class="ds-message__icon ds-message__icon--${type}">${icons[type]}</div>
|
|
33
37
|
<div class="ds-message__content"></div>
|
|
34
38
|
`;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
39
|
+
msg.querySelector('.ds-message__content').textContent = message;
|
|
40
|
+
|
|
41
|
+
let container = document.querySelector('.ds-message');
|
|
42
|
+
if (!container) {
|
|
43
|
+
container = document.createElement('div');
|
|
44
|
+
container.className = `ds-message ds-message--${position}`;
|
|
45
|
+
document.body.appendChild(container);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Remove excess messages if maxCount exceeded
|
|
49
|
+
const existingMessages = container.querySelectorAll('.ds-message__item');
|
|
50
|
+
if (existingMessages.length >= maxCount) {
|
|
51
|
+
const oldest = existingMessages[0];
|
|
52
|
+
oldest.classList.remove('is-visible');
|
|
53
|
+
oldest.classList.add('is-exiting');
|
|
54
|
+
setTimeout(() => oldest.remove(), 300);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
container.appendChild(msg);
|
|
58
|
+
|
|
59
|
+
setTimeout(() => {
|
|
60
|
+
msg.classList.add('is-visible');
|
|
61
|
+
}, 10);
|
|
62
|
+
|
|
63
|
+
if (duration > 0) {
|
|
64
|
+
setTimeout(() => {
|
|
65
|
+
msg.classList.remove('is-visible');
|
|
66
|
+
msg.classList.add('is-exiting');
|
|
67
|
+
setTimeout(() => msg.remove(), 300);
|
|
68
|
+
}, duration);
|
|
57
69
|
}
|
|
70
|
+
},
|
|
58
71
|
};
|
|
59
72
|
|
|
60
73
|
function initMessages() {}
|
|
61
74
|
|
|
62
|
-
export { Message, initMessages };
|
|
75
|
+
export { Message, initMessages };
|
package/js/modal.js
CHANGED
|
@@ -7,10 +7,13 @@ class Modal {
|
|
|
7
7
|
this.mask = element.querySelector('.ds-modal-mask');
|
|
8
8
|
this.modal = element.querySelector('.ds-modal');
|
|
9
9
|
this.closeBtn = element.querySelector('.ds-modal__close');
|
|
10
|
-
|
|
11
|
-
// Options
|
|
10
|
+
|
|
11
|
+
// Options - use config default for backdropClick
|
|
12
|
+
const uiConfig = getUiConfig();
|
|
13
|
+
const defaultBackdropClick = uiConfig.modal?.backdropClick !== undefined ? uiConfig.modal.backdropClick : true;
|
|
14
|
+
|
|
12
15
|
this.fullscreen = options.fullscreen || element.hasAttribute('data-modal-fullscreen');
|
|
13
|
-
this.closableOnMask = options.closableOnMask !==
|
|
16
|
+
this.closableOnMask = options.closableOnMask !== undefined ? options.closableOnMask : defaultBackdropClick;
|
|
14
17
|
this.escClose = options.escClose !== false;
|
|
15
18
|
this.width = options.width || element.getAttribute('data-modal-width') || '';
|
|
16
19
|
this.center = options.center !== false;
|
|
@@ -18,54 +21,54 @@ class Modal {
|
|
|
18
21
|
this.onBeforeClose = options.onBeforeClose || null;
|
|
19
22
|
this.onOpened = options.onOpened || null;
|
|
20
23
|
this.onClosed = options.onClosed || null;
|
|
21
|
-
|
|
24
|
+
|
|
22
25
|
this._isOpen = false; // 实例级跟踪,防止 _openCount 不匹配
|
|
23
|
-
|
|
26
|
+
|
|
24
27
|
this._keydownHandler = (e) => {
|
|
25
28
|
if (this.escClose && e.key === 'Escape' && this.isVisible()) {
|
|
26
29
|
this.close();
|
|
27
30
|
}
|
|
28
31
|
};
|
|
29
|
-
|
|
32
|
+
|
|
30
33
|
this._closeBtnClickHandler = () => this.close();
|
|
31
|
-
|
|
34
|
+
|
|
32
35
|
this._maskClickHandler = (e) => {
|
|
33
36
|
if (this.closableOnMask && e.target === this.mask) {
|
|
34
37
|
this.close();
|
|
35
38
|
}
|
|
36
39
|
};
|
|
37
|
-
|
|
40
|
+
|
|
38
41
|
this.init();
|
|
39
42
|
}
|
|
40
|
-
|
|
43
|
+
|
|
41
44
|
init() {
|
|
42
45
|
if (this.closeBtn) {
|
|
43
46
|
this.closeBtn.addEventListener('click', this._closeBtnClickHandler);
|
|
44
47
|
}
|
|
45
|
-
|
|
48
|
+
|
|
46
49
|
if (this.mask) {
|
|
47
50
|
this.mask.addEventListener('click', this._maskClickHandler);
|
|
48
51
|
}
|
|
49
|
-
|
|
52
|
+
|
|
50
53
|
document.addEventListener('keydown', this._keydownHandler);
|
|
51
|
-
|
|
54
|
+
|
|
52
55
|
// Apply fullscreen
|
|
53
56
|
if (this.fullscreen && this.modal) {
|
|
54
57
|
this.modal.classList.add('ds-modal--fullscreen');
|
|
55
58
|
}
|
|
56
|
-
|
|
59
|
+
|
|
57
60
|
// Apply custom width
|
|
58
61
|
if (this.width && this.modal) {
|
|
59
62
|
this.modal.style.maxWidth = this.width;
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
|
-
|
|
65
|
+
|
|
63
66
|
open() {
|
|
64
67
|
if (this.onBeforeOpen) {
|
|
65
68
|
const result = this.onBeforeOpen();
|
|
66
|
-
if (result === false) return;
|
|
69
|
+
if (result === false) {return;}
|
|
67
70
|
}
|
|
68
|
-
|
|
71
|
+
|
|
69
72
|
if (this.mask) {
|
|
70
73
|
this.mask.classList.add('is-visible');
|
|
71
74
|
this.mask.classList.add('ds-modal-fade-enter');
|
|
@@ -79,26 +82,26 @@ class Modal {
|
|
|
79
82
|
this.modal.classList.add('ds-modal-zoom-enter-active');
|
|
80
83
|
});
|
|
81
84
|
}
|
|
82
|
-
|
|
85
|
+
|
|
83
86
|
if (!this._isOpen) {
|
|
84
87
|
Modal._openCount = (Modal._openCount || 0) + 1;
|
|
85
88
|
this._isOpen = true;
|
|
86
89
|
}
|
|
87
90
|
document.body.style.overflow = 'hidden';
|
|
88
|
-
|
|
91
|
+
|
|
89
92
|
if (this.onOpened) {
|
|
90
93
|
setTimeout(() => this.onOpened(), 300);
|
|
91
94
|
}
|
|
92
|
-
|
|
95
|
+
|
|
93
96
|
this.element.dispatchEvent(new CustomEvent('kupola:modal-open', { bubbles: true }));
|
|
94
97
|
}
|
|
95
|
-
|
|
98
|
+
|
|
96
99
|
close() {
|
|
97
100
|
if (this.onBeforeClose) {
|
|
98
101
|
const result = this.onBeforeClose();
|
|
99
|
-
if (result === false) return;
|
|
102
|
+
if (result === false) {return;}
|
|
100
103
|
}
|
|
101
|
-
|
|
104
|
+
|
|
102
105
|
if (this.mask) {
|
|
103
106
|
this.mask.classList.remove('ds-modal-fade-enter-active');
|
|
104
107
|
this.mask.classList.add('ds-modal-fade-leave-active');
|
|
@@ -107,7 +110,7 @@ class Modal {
|
|
|
107
110
|
this.modal.classList.remove('ds-modal-zoom-enter-active');
|
|
108
111
|
this.modal.classList.add('ds-modal-zoom-leave-active');
|
|
109
112
|
}
|
|
110
|
-
|
|
113
|
+
|
|
111
114
|
setTimeout(() => {
|
|
112
115
|
if (this.mask) {
|
|
113
116
|
this.mask.classList.remove('is-visible', 'ds-modal-fade-enter', 'ds-modal-fade-leave-active');
|
|
@@ -116,7 +119,7 @@ class Modal {
|
|
|
116
119
|
this.modal.classList.remove('ds-modal-zoom-enter', 'ds-modal-zoom-leave-active');
|
|
117
120
|
}
|
|
118
121
|
}, 300);
|
|
119
|
-
|
|
122
|
+
|
|
120
123
|
if (this._isOpen) {
|
|
121
124
|
Modal._openCount = Math.max(0, (Modal._openCount || 0) - 1);
|
|
122
125
|
this._isOpen = false;
|
|
@@ -124,25 +127,25 @@ class Modal {
|
|
|
124
127
|
document.body.style.overflow = '';
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
|
-
|
|
130
|
+
|
|
128
131
|
if (this.onClosed) {
|
|
129
132
|
setTimeout(() => this.onClosed(), 300);
|
|
130
133
|
}
|
|
131
|
-
|
|
134
|
+
|
|
132
135
|
this.element.dispatchEvent(new CustomEvent('kupola:modal-close', { bubbles: true }));
|
|
133
136
|
}
|
|
134
|
-
|
|
137
|
+
|
|
135
138
|
toggleFullscreen() {
|
|
136
139
|
this.fullscreen = !this.fullscreen;
|
|
137
140
|
if (this.modal) {
|
|
138
141
|
this.modal.classList.toggle('ds-modal--fullscreen', this.fullscreen);
|
|
139
142
|
}
|
|
140
143
|
}
|
|
141
|
-
|
|
144
|
+
|
|
142
145
|
isVisible() {
|
|
143
146
|
return this.mask && this.mask.classList.contains('is-visible');
|
|
144
147
|
}
|
|
145
|
-
|
|
148
|
+
|
|
146
149
|
destroy() {
|
|
147
150
|
document.removeEventListener('keydown', this._keydownHandler);
|
|
148
151
|
if (this.closeBtn) {
|
|
@@ -184,14 +187,14 @@ function createModal(options = {}) {
|
|
|
184
187
|
onOpen,
|
|
185
188
|
onClose,
|
|
186
189
|
footer = null,
|
|
187
|
-
size = getUiConfig().defaultSize
|
|
190
|
+
size = getUiConfig().defaultSize,
|
|
188
191
|
} = options;
|
|
189
|
-
|
|
192
|
+
|
|
190
193
|
const sizeClass = size === 'sm' ? 'ds-btn--sm' : size === 'lg' ? 'ds-btn--lg' : '';
|
|
191
|
-
|
|
194
|
+
|
|
192
195
|
const container = document.createElement('div');
|
|
193
196
|
container.className = 'ds-modal-container';
|
|
194
|
-
|
|
197
|
+
|
|
195
198
|
let footerHTML = '';
|
|
196
199
|
if (footer !== null) {
|
|
197
200
|
if (typeof footer === 'string') {
|
|
@@ -203,7 +206,7 @@ function createModal(options = {}) {
|
|
|
203
206
|
</div>`;
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
|
-
|
|
209
|
+
|
|
207
210
|
container.innerHTML = `
|
|
208
211
|
<div class="ds-modal-mask">
|
|
209
212
|
<div class="ds-modal${fullscreen ? ' ds-modal--fullscreen' : ''}" style="${!fullscreen ? 'max-width: ' + width : ''}">
|
|
@@ -220,13 +223,13 @@ function createModal(options = {}) {
|
|
|
220
223
|
</div>
|
|
221
224
|
</div>
|
|
222
225
|
`;
|
|
223
|
-
|
|
226
|
+
|
|
224
227
|
document.body.appendChild(container);
|
|
225
|
-
|
|
228
|
+
|
|
226
229
|
const modal = new Modal(container, { fullscreen, closableOnMask: maskClosable });
|
|
227
|
-
|
|
230
|
+
|
|
228
231
|
const titleEl = container.querySelector('.ds-modal__title');
|
|
229
|
-
if (titleEl) titleEl.textContent = title;
|
|
232
|
+
if (titleEl) {titleEl.textContent = title;}
|
|
230
233
|
const bodyEl = container.querySelector('.ds-modal__body');
|
|
231
234
|
if (bodyEl) {
|
|
232
235
|
if (html) {
|
|
@@ -235,12 +238,12 @@ function createModal(options = {}) {
|
|
|
235
238
|
bodyEl.textContent = content;
|
|
236
239
|
}
|
|
237
240
|
}
|
|
238
|
-
|
|
241
|
+
|
|
239
242
|
const confirmBtn = container.querySelector('[data-modal-confirm]');
|
|
240
243
|
const cancelBtn = container.querySelector('[data-modal-cancel]');
|
|
241
|
-
|
|
244
|
+
|
|
242
245
|
let isConfirming = false;
|
|
243
|
-
|
|
246
|
+
|
|
244
247
|
const confirmHandler = async () => {
|
|
245
248
|
if (onConfirm) {
|
|
246
249
|
// Support async onConfirm
|
|
@@ -253,7 +256,7 @@ function createModal(options = {}) {
|
|
|
253
256
|
confirmBtn.classList.remove('is-loading');
|
|
254
257
|
return;
|
|
255
258
|
}
|
|
256
|
-
} catch(e) {
|
|
259
|
+
} catch (e) {
|
|
257
260
|
confirmBtn.disabled = false;
|
|
258
261
|
confirmBtn.classList.remove('is-loading');
|
|
259
262
|
return;
|
|
@@ -262,34 +265,34 @@ function createModal(options = {}) {
|
|
|
262
265
|
isConfirming = true;
|
|
263
266
|
modal.close();
|
|
264
267
|
};
|
|
265
|
-
|
|
268
|
+
|
|
266
269
|
const cancelHandler = () => {
|
|
267
|
-
if (onCancel) onCancel();
|
|
270
|
+
if (onCancel) {onCancel();}
|
|
268
271
|
modal.close();
|
|
269
272
|
};
|
|
270
|
-
|
|
271
|
-
if (confirmBtn) confirmBtn.addEventListener('click', confirmHandler);
|
|
272
|
-
if (cancelBtn) cancelBtn.addEventListener('click', cancelHandler);
|
|
273
|
-
|
|
273
|
+
|
|
274
|
+
if (confirmBtn) {confirmBtn.addEventListener('click', confirmHandler);}
|
|
275
|
+
if (cancelBtn) {cancelBtn.addEventListener('click', cancelHandler);}
|
|
276
|
+
|
|
274
277
|
const closeAndDestroy = () => {
|
|
275
278
|
setTimeout(() => {
|
|
276
|
-
if (confirmBtn) confirmBtn.removeEventListener('click', confirmHandler);
|
|
277
|
-
if (cancelBtn) cancelBtn.removeEventListener('click', cancelHandler);
|
|
279
|
+
if (confirmBtn) {confirmBtn.removeEventListener('click', confirmHandler);}
|
|
280
|
+
if (cancelBtn) {cancelBtn.removeEventListener('click', cancelHandler);}
|
|
278
281
|
modal.destroy();
|
|
279
282
|
container.remove();
|
|
280
|
-
if (onClose) onClose(isConfirming);
|
|
283
|
+
if (onClose) {onClose(isConfirming);}
|
|
281
284
|
}, 300);
|
|
282
285
|
};
|
|
283
|
-
|
|
286
|
+
|
|
284
287
|
const originalClose = modal.close.bind(modal);
|
|
285
288
|
modal.close = () => {
|
|
286
289
|
originalClose();
|
|
287
290
|
closeAndDestroy();
|
|
288
291
|
};
|
|
289
|
-
|
|
292
|
+
|
|
290
293
|
modal.open();
|
|
291
|
-
if (onOpen) setTimeout(() => onOpen(), 50);
|
|
292
|
-
|
|
294
|
+
if (onOpen) {setTimeout(() => onOpen(), 50);}
|
|
295
|
+
|
|
293
296
|
return modal;
|
|
294
297
|
}
|
|
295
298
|
|
|
@@ -301,7 +304,7 @@ function confirmModal(options) {
|
|
|
301
304
|
return createModal({
|
|
302
305
|
...options,
|
|
303
306
|
showCancel: true,
|
|
304
|
-
showConfirm: true
|
|
307
|
+
showConfirm: true,
|
|
305
308
|
});
|
|
306
309
|
}
|
|
307
310
|
|
|
@@ -312,12 +315,12 @@ function alertModal(options) {
|
|
|
312
315
|
return createModal({
|
|
313
316
|
...options,
|
|
314
317
|
showCancel: false,
|
|
315
|
-
showConfirm: true
|
|
318
|
+
showConfirm: true,
|
|
316
319
|
});
|
|
317
320
|
}
|
|
318
321
|
|
|
319
322
|
function initModal(element) {
|
|
320
|
-
if (element.__kupolaInitialized) return;
|
|
323
|
+
if (element.__kupolaInitialized) {return;}
|
|
321
324
|
|
|
322
325
|
const modal = new Modal(element);
|
|
323
326
|
element.__kupolaInstance = modal;
|
|
@@ -325,7 +328,7 @@ function initModal(element) {
|
|
|
325
328
|
}
|
|
326
329
|
|
|
327
330
|
function cleanupModal(element) {
|
|
328
|
-
if (!element.__kupolaInitialized || !element.__kupolaInstance) return;
|
|
331
|
+
if (!element.__kupolaInitialized || !element.__kupolaInstance) {return;}
|
|
329
332
|
|
|
330
333
|
const modal = element.__kupolaInstance;
|
|
331
334
|
modal.destroy();
|
package/js/notification.js
CHANGED
|
@@ -1,34 +1,37 @@
|
|
|
1
|
+
import { getNotificationConfig } from './kupola-config.js';
|
|
2
|
+
|
|
1
3
|
const Notification = {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
4
|
+
normal: function (options) {
|
|
5
|
+
this.show({ ...options, type: 'normal' });
|
|
6
|
+
},
|
|
7
|
+
success: function (options) {
|
|
8
|
+
this.show({ ...options, type: 'success' });
|
|
9
|
+
},
|
|
10
|
+
error: function (options) {
|
|
11
|
+
this.show({ ...options, type: 'error' });
|
|
12
|
+
},
|
|
13
|
+
warning: function (options) {
|
|
14
|
+
this.show({ ...options, type: 'warning' });
|
|
15
|
+
},
|
|
16
|
+
info: function (options) {
|
|
17
|
+
this.show({ ...options, type: 'info' });
|
|
18
|
+
},
|
|
19
|
+
show: function (options) {
|
|
20
|
+
const notifConfig = getNotificationConfig();
|
|
21
|
+
const { title, message, type = 'normal', duration = notifConfig.duration, position = notifConfig.position } = options;
|
|
22
|
+
|
|
23
|
+
const notification = document.createElement('div');
|
|
24
|
+
notification.className = `ds-notification__item ds-notification__item--${type}`;
|
|
25
|
+
|
|
26
|
+
const icons = {
|
|
27
|
+
normal: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',
|
|
28
|
+
success: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg>',
|
|
29
|
+
error: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>',
|
|
30
|
+
warning: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>',
|
|
31
|
+
info: '<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
notification.innerHTML = `
|
|
32
35
|
<div class="ds-notification__icon ds-notification__icon--${type}">${icons[type]}</div>
|
|
33
36
|
<div class="ds-notification__content">
|
|
34
37
|
${title ? '<div class="ds-notification__title"></div>' : ''}
|
|
@@ -38,38 +41,38 @@ const Notification = {
|
|
|
38
41
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
|
|
39
42
|
</button>
|
|
40
43
|
`;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
44
|
+
if (title) {notification.querySelector('.ds-notification__title').textContent = title;}
|
|
45
|
+
if (message) {notification.querySelector('.ds-notification__message').textContent = message;}
|
|
46
|
+
|
|
47
|
+
let container = document.querySelector('.ds-notification');
|
|
48
|
+
if (!container) {
|
|
49
|
+
container = document.createElement('div');
|
|
50
|
+
container.className = `ds-notification ds-notification--${position}`;
|
|
51
|
+
document.body.appendChild(container);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
container.appendChild(notification);
|
|
55
|
+
|
|
56
|
+
setTimeout(() => {
|
|
57
|
+
notification.classList.add('is-visible');
|
|
58
|
+
}, 10);
|
|
59
|
+
|
|
60
|
+
notification.querySelector('.ds-notification__close').addEventListener('click', () => {
|
|
61
|
+
notification.classList.remove('is-visible');
|
|
62
|
+
notification.classList.add('is-exiting');
|
|
63
|
+
setTimeout(() => notification.remove(), 300);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
if (duration > 0) {
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
notification.classList.remove('is-visible');
|
|
69
|
+
notification.classList.add('is-exiting');
|
|
70
|
+
setTimeout(() => notification.remove(), 300);
|
|
71
|
+
}, duration);
|
|
70
72
|
}
|
|
73
|
+
},
|
|
71
74
|
};
|
|
72
75
|
|
|
73
76
|
function initNotifications() {}
|
|
74
77
|
|
|
75
|
-
export { Notification, initNotifications };
|
|
78
|
+
export { Notification, initNotifications };
|
package/js/security.js
CHANGED
|
@@ -58,4 +58,56 @@ export function stripHtml(html) {
|
|
|
58
58
|
const domParser = new DOMParser();
|
|
59
59
|
const doc = domParser.parseFromString(html, 'text/html');
|
|
60
60
|
return doc.body.textContent || '';
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function maskData(value, type, options = {}) {
|
|
64
|
+
const securityConfig = getSecurityConfig();
|
|
65
|
+
const maskConfig = securityConfig?.maskData || {};
|
|
66
|
+
|
|
67
|
+
if (!maskConfig.enabled && !options.force) {
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (value === null || value === undefined) {
|
|
72
|
+
return value;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const patterns = options.patterns || maskConfig.patterns || {};
|
|
76
|
+
const pattern = patterns[type];
|
|
77
|
+
|
|
78
|
+
if (!pattern) {
|
|
79
|
+
return value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const regex = typeof pattern.regex === 'string'
|
|
83
|
+
? new RegExp(pattern.regex)
|
|
84
|
+
: pattern.regex;
|
|
85
|
+
|
|
86
|
+
return String(value).replace(regex, pattern.replace);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function generateSecureId(length, prefix) {
|
|
90
|
+
const securityConfig = getSecurityConfig();
|
|
91
|
+
const secureIdConfig = securityConfig?.secureId || {};
|
|
92
|
+
|
|
93
|
+
const idLength = length || secureIdConfig.length || 16;
|
|
94
|
+
const charset = secureIdConfig.charset || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
95
|
+
|
|
96
|
+
if (typeof crypto === 'undefined' || !crypto.getRandomValues) {
|
|
97
|
+
let result = '';
|
|
98
|
+
for (let i = 0; i < idLength; i++) {
|
|
99
|
+
result += charset[Math.floor(Math.random() * charset.length)];
|
|
100
|
+
}
|
|
101
|
+
return prefix ? `${prefix}_${result}` : result;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const array = new Uint32Array(idLength);
|
|
105
|
+
crypto.getRandomValues(array);
|
|
106
|
+
|
|
107
|
+
let result = '';
|
|
108
|
+
for (let i = 0; i < idLength; i++) {
|
|
109
|
+
result += charset[array[i] % charset.length];
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return prefix ? `${prefix}_${result}` : result;
|
|
61
113
|
}
|