@kupola/kupola 1.2.0 → 1.4.0
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 -0
- package/README.md +330 -286
- package/adapters/axios.d.ts +34 -0
- package/adapters/axios.js +122 -0
- package/adapters/navios-http.d.ts +110 -0
- package/adapters/navios-http.js +151 -0
- package/css/components-ext.css +157 -0
- package/css/components.css +69 -0
- package/css/theme-dark.css +5 -5
- package/css/utilities.css +119 -1
- package/dist/css/accessibility.css +119 -0
- package/dist/css/animations.css +224 -0
- package/dist/css/brand-themes.css +300 -0
- package/dist/css/colors_and_type.css +441 -0
- package/dist/css/components-ext.css +4165 -0
- package/dist/css/components.css +1483 -0
- package/dist/css/kupola.css +1 -12
- package/dist/css/kupola.min.css +1 -0
- package/dist/css/responsive.css +697 -0
- package/dist/css/scaffold.css +145 -0
- package/dist/css/states.css +316 -0
- package/dist/css/theme-dark.css +296 -0
- package/dist/css/theme-light.css +296 -0
- package/dist/css/utilities.css +171 -0
- package/dist/icons.svg +284 -0
- package/dist/kupola.cjs.js +17409 -257
- package/dist/kupola.cjs.js.map +1 -1
- package/dist/kupola.css +9000 -0
- package/dist/kupola.esm.js +17183 -7597
- package/dist/kupola.esm.js.map +1 -1
- package/dist/kupola.min.css +1 -0
- package/dist/kupola.min.js +2 -0
- package/dist/kupola.min.js.map +1 -0
- package/dist/kupola.umd.js +17415 -257
- package/dist/kupola.umd.js.map +1 -1
- package/dist/plugins/vite-plugin-kupola.js +120 -0
- package/dist/types/kupola.d.ts +421 -323
- package/js/calendar.js +334 -25
- package/js/carousel.js +182 -48
- package/js/collapse.js +148 -34
- package/js/color-picker.js +416 -108
- package/js/component.js +8 -19
- package/js/countdown.js +9 -8
- package/js/data-bind.js +73 -16
- package/js/datepicker.js +488 -110
- package/js/depends.js +710 -0
- package/js/dialog.js +4 -2
- package/js/drawer.js +172 -8
- package/js/dropdown.js +272 -17
- package/js/dynamic-tags.js +156 -40
- package/js/fileupload.js +9 -8
- package/js/form.js +280 -254
- package/js/global-events.js +281 -188
- package/js/heatmap.js +10 -7
- package/js/i18n.js +18 -10
- package/js/icons.js +141 -161
- package/js/image-preview.js +146 -2
- package/js/initializer.js +151 -71
- package/js/kupola-core.js +123 -45
- package/js/kupola-lifecycle.js +13 -11
- package/js/message.js +8 -1
- package/js/modal.js +207 -59
- package/js/notification.js +8 -1
- package/js/numberinput.js +9 -8
- package/js/pagination.js +263 -0
- package/js/registry.js +29 -12
- package/js/select.js +482 -27
- package/js/slide-captcha.js +11 -2
- package/js/slider.js +442 -25
- package/js/statcard.js +9 -7
- package/js/table.js +1210 -0
- package/js/tag.js +268 -14
- package/js/theme-standalone.js +88 -0
- package/js/theme.js +14 -43
- package/js/timepicker.js +335 -66
- package/js/tooltip.js +317 -86
- package/js/utils.js +6 -2
- package/js/validation.js +6 -2
- package/js/virtual-list.js +11 -7
- package/js/web-components.js +288 -0
- package/package.json +81 -67
- package/plugins/vite-plugin-kupola.js +120 -0
- package/scripts/build-css.cjs +113 -0
- package/scripts/build-svg-sprite.cjs +107 -0
- package/types/kupola.d.ts +421 -323
- package/CHANGELOG.md +0 -130
- package/INTEGRATION.md +0 -440
- package/PROJECT_SUMMARY.md +0 -312
- package/SKILL.md +0 -572
- package/dist/utils/utils/Kupola.cs +0 -77
- package/dist/utils/utils/Kupola.java +0 -104
- package/dist/utils/utils/kupola.go +0 -120
- package/dist/utils/utils/kupola.js +0 -63
- package/dist/utils/utils/kupola.py +0 -1392
- package/dist/utils/utils/kupola.rb +0 -69
- package/js/composition-api.js +0 -458
- package/js/error-handler.js +0 -181
- package/js/http.js +0 -419
- package/js/kupola-devtools.js +0 -598
- package/js/performance.js +0 -250
- package/js/router.js +0 -396
- package/js/security.js +0 -189
- package/js/test-utils.js +0 -251
- package/templates/base.html +0 -30
- package/templates/base_dashboard.html +0 -99
- package/utils/Kupola.cs +0 -77
- package/utils/Kupola.java +0 -104
- package/utils/kupola.go +0 -120
- package/utils/kupola.js +0 -63
- package/utils/kupola.py +0 -1392
- package/utils/kupola.rb +0 -69
package/js/pagination.js
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* KupolaPagination - Standalone pagination component
|
|
3
|
+
* Works with useDeps or plain data
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ref } from './data-bind.js';
|
|
7
|
+
|
|
8
|
+
class KupolaPagination {
|
|
9
|
+
constructor(element, options = {}) {
|
|
10
|
+
this.element = typeof element === 'string' ? document.querySelector(element) : element;
|
|
11
|
+
this.options = options;
|
|
12
|
+
|
|
13
|
+
// State
|
|
14
|
+
this._current = options.current || 1;
|
|
15
|
+
this._total = options.total || 0;
|
|
16
|
+
this._pageSize = options.pageSize || 10;
|
|
17
|
+
this._maxPages = options.maxPages || 7;
|
|
18
|
+
this._showTotal = options.showTotal !== false;
|
|
19
|
+
this._showSizeChanger = options.showSizeChanger || false;
|
|
20
|
+
this._pageSizes = options.pageSizes || [10, 20, 50, 100];
|
|
21
|
+
this._simple = options.simple || false;
|
|
22
|
+
|
|
23
|
+
// Refs for reactive integration
|
|
24
|
+
this.current = ref(this._current);
|
|
25
|
+
this.total = ref(this._total);
|
|
26
|
+
|
|
27
|
+
// Callbacks
|
|
28
|
+
this.onChange = options.onChange || null;
|
|
29
|
+
this.onPageSizeChange = options.onPageSizeChange || null;
|
|
30
|
+
|
|
31
|
+
this._init();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
_init() {
|
|
35
|
+
this.element.classList.add('kupola-pagination');
|
|
36
|
+
this.render();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
get totalPages() {
|
|
40
|
+
return Math.max(1, Math.ceil(this._total / this._pageSize));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setCurrent(page) {
|
|
44
|
+
page = Math.max(1, Math.min(page, this.totalPages));
|
|
45
|
+
if (page === this._current) return;
|
|
46
|
+
this._current = page;
|
|
47
|
+
this.current.value = page;
|
|
48
|
+
if (this.onChange) this.onChange(page, this._pageSize);
|
|
49
|
+
this.render();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
setTotal(total) {
|
|
53
|
+
if (total && typeof total === 'object' && 'value' in total) {
|
|
54
|
+
this._total = total.value || 0;
|
|
55
|
+
total._subscribers?.add((val) => {
|
|
56
|
+
this._total = val || 0;
|
|
57
|
+
if (this._current > this.totalPages) {
|
|
58
|
+
this.setCurrent(this.totalPages);
|
|
59
|
+
} else {
|
|
60
|
+
this.render();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
} else {
|
|
64
|
+
this._total = total;
|
|
65
|
+
}
|
|
66
|
+
this.total.value = this._total;
|
|
67
|
+
this.render();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setPageSize(size) {
|
|
71
|
+
this._pageSize = size;
|
|
72
|
+
this._current = 1;
|
|
73
|
+
this.current.value = 1;
|
|
74
|
+
if (this.onPageSizeChange) this.onPageSizeChange(size, this._current);
|
|
75
|
+
this.render();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
render() {
|
|
79
|
+
const el = this.element;
|
|
80
|
+
el.innerHTML = '';
|
|
81
|
+
|
|
82
|
+
if (this._total <= 0) return;
|
|
83
|
+
|
|
84
|
+
if (this._simple) {
|
|
85
|
+
this._renderSimple(el);
|
|
86
|
+
} else {
|
|
87
|
+
this._renderFull(el);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_renderSimple(el) {
|
|
92
|
+
const total = this.totalPages;
|
|
93
|
+
|
|
94
|
+
const prev = this._btn('‹', () => this.setCurrent(this._current - 1));
|
|
95
|
+
prev.disabled = this._current <= 1;
|
|
96
|
+
el.appendChild(prev);
|
|
97
|
+
|
|
98
|
+
const info = document.createElement('span');
|
|
99
|
+
info.className = 'kupola-pagination-simple-info';
|
|
100
|
+
info.textContent = `${this._current} / ${total}`;
|
|
101
|
+
el.appendChild(info);
|
|
102
|
+
|
|
103
|
+
const next = this._btn('›', () => this.setCurrent(this._current + 1));
|
|
104
|
+
next.disabled = this._current >= total;
|
|
105
|
+
el.appendChild(next);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
_renderFull(el) {
|
|
109
|
+
const total = this.totalPages;
|
|
110
|
+
|
|
111
|
+
// Total info
|
|
112
|
+
if (this._showTotal) {
|
|
113
|
+
const info = document.createElement('span');
|
|
114
|
+
info.className = 'kupola-pagination-total';
|
|
115
|
+
info.textContent = `共 ${this._total} 条`;
|
|
116
|
+
el.appendChild(info);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Size changer
|
|
120
|
+
if (this._showSizeChanger) {
|
|
121
|
+
const select = document.createElement('select');
|
|
122
|
+
select.className = 'kupola-pagination-size';
|
|
123
|
+
this._pageSizes.forEach(size => {
|
|
124
|
+
const opt = document.createElement('option');
|
|
125
|
+
opt.value = size;
|
|
126
|
+
opt.textContent = `${size} 条/页`;
|
|
127
|
+
if (size === this._pageSize) opt.selected = true;
|
|
128
|
+
select.appendChild(opt);
|
|
129
|
+
});
|
|
130
|
+
select.addEventListener('change', () => this.setPageSize(parseInt(select.value)));
|
|
131
|
+
el.appendChild(select);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Page buttons container
|
|
135
|
+
const pages = document.createElement('div');
|
|
136
|
+
pages.className = 'kupola-pagination-pages';
|
|
137
|
+
|
|
138
|
+
// Prev
|
|
139
|
+
const prev = this._btn('‹', () => this.setCurrent(this._current - 1));
|
|
140
|
+
prev.disabled = this._current <= 1;
|
|
141
|
+
pages.appendChild(prev);
|
|
142
|
+
|
|
143
|
+
// Page numbers
|
|
144
|
+
this._getPageRange().forEach(p => {
|
|
145
|
+
if (p === '...') {
|
|
146
|
+
const span = document.createElement('span');
|
|
147
|
+
span.className = 'kupola-pagination-ellipsis';
|
|
148
|
+
span.textContent = '···';
|
|
149
|
+
pages.appendChild(span);
|
|
150
|
+
} else {
|
|
151
|
+
const btn = this._btn(p, () => this.setCurrent(p));
|
|
152
|
+
if (p === this._current) btn.classList.add('active');
|
|
153
|
+
pages.appendChild(btn);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// Next
|
|
158
|
+
const next = this._btn('›', () => this.setCurrent(this._current + 1));
|
|
159
|
+
next.disabled = this._current >= total;
|
|
160
|
+
pages.appendChild(next);
|
|
161
|
+
|
|
162
|
+
el.appendChild(pages);
|
|
163
|
+
|
|
164
|
+
// Jumper
|
|
165
|
+
if (total > 10) {
|
|
166
|
+
const jumper = document.createElement('span');
|
|
167
|
+
jumper.className = 'kupola-pagination-jumper';
|
|
168
|
+
jumper.innerHTML = '跳至 <input type="number" min="1" max="' + total + '" value="' + this._current + '"> 页';
|
|
169
|
+
const input = jumper.querySelector('input');
|
|
170
|
+
input.addEventListener('change', () => {
|
|
171
|
+
const page = parseInt(input.value);
|
|
172
|
+
if (page >= 1 && page <= total) {
|
|
173
|
+
this.setCurrent(page);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
input.addEventListener('keydown', (e) => {
|
|
177
|
+
if (e.key === 'Enter') {
|
|
178
|
+
const page = parseInt(input.value);
|
|
179
|
+
if (page >= 1 && page <= total) {
|
|
180
|
+
this.setCurrent(page);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
el.appendChild(jumper);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
_btn(text, onClick) {
|
|
189
|
+
const btn = document.createElement('button');
|
|
190
|
+
btn.className = 'kupola-pagination-btn';
|
|
191
|
+
btn.textContent = text;
|
|
192
|
+
btn.type = 'button';
|
|
193
|
+
btn.addEventListener('click', onClick);
|
|
194
|
+
return btn;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
_getPageRange() {
|
|
198
|
+
const total = this.totalPages;
|
|
199
|
+
const max = this._maxPages;
|
|
200
|
+
|
|
201
|
+
if (total <= max) {
|
|
202
|
+
return Array.from({ length: total }, (_, i) => i + 1);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const range = [];
|
|
206
|
+
const half = Math.floor(max / 2);
|
|
207
|
+
|
|
208
|
+
if (this._current <= half + 1) {
|
|
209
|
+
for (let i = 1; i <= max - 2; i++) range.push(i);
|
|
210
|
+
range.push('...', total);
|
|
211
|
+
} else if (this._current >= total - half) {
|
|
212
|
+
range.push(1, '...');
|
|
213
|
+
for (let i = total - max + 3; i <= total; i++) range.push(i);
|
|
214
|
+
} else {
|
|
215
|
+
range.push(1, '...');
|
|
216
|
+
for (let i = this._current - half + 2; i <= this._current + half - 2; i++) range.push(i);
|
|
217
|
+
range.push('...', total);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
return range;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
destroy() {
|
|
224
|
+
this.element.innerHTML = '';
|
|
225
|
+
this.element.classList.remove('kupola-pagination');
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// CSS styles
|
|
230
|
+
let stylesInjected = false;
|
|
231
|
+
function injectPaginationStyles() {
|
|
232
|
+
if (stylesInjected || typeof document === 'undefined') return;
|
|
233
|
+
const style = document.createElement('style');
|
|
234
|
+
style.textContent = `
|
|
235
|
+
.kupola-pagination { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
|
|
236
|
+
.kupola-pagination-pages { display: flex; gap: 4px; align-items: center; }
|
|
237
|
+
.kupola-pagination-btn { min-width: 32px; height: 32px; border: 1px solid #d9d9d9; border-radius: 4px; background: #fff; cursor: pointer; font-size: 14px; display: flex; align-items: center; justify-content: center; transition: all 0.2s; }
|
|
238
|
+
.kupola-pagination-btn:hover:not(:disabled):not(.active) { border-color: #1890ff; color: #1890ff; }
|
|
239
|
+
.kupola-pagination-btn.active { background: #1890ff; color: #fff; border-color: #1890ff; }
|
|
240
|
+
.kupola-pagination-btn:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
241
|
+
.kupola-pagination-ellipsis { padding: 0 4px; color: #999; user-select: none; }
|
|
242
|
+
.kupola-pagination-total { color: #666; font-size: 14px; }
|
|
243
|
+
.kupola-pagination-size { padding: 4px 8px; border: 1px solid #d9d9d9; border-radius: 4px; font-size: 13px; }
|
|
244
|
+
.kupola-pagination-simple-info { padding: 0 8px; font-size: 14px; color: #333; }
|
|
245
|
+
.kupola-pagination-jumper { font-size: 14px; color: #666; }
|
|
246
|
+
.kupola-pagination-jumper input { width: 50px; height: 28px; margin: 0 4px; padding: 0 8px; border: 1px solid #d9d9d9; border-radius: 4px; text-align: center; font-size: 13px; }
|
|
247
|
+
.kupola-pagination-jumper input:focus { outline: none; border-color: #1890ff; }
|
|
248
|
+
`;
|
|
249
|
+
document.head.appendChild(style);
|
|
250
|
+
stylesInjected = true;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function initPagination(element, options) {
|
|
254
|
+
injectPaginationStyles();
|
|
255
|
+
return new KupolaPagination(element, options);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
export { KupolaPagination, initPagination };
|
|
259
|
+
|
|
260
|
+
if (typeof window !== 'undefined') {
|
|
261
|
+
window.KupolaPagination = KupolaPagination;
|
|
262
|
+
window.initPagination = initPagination;
|
|
263
|
+
}
|
package/js/registry.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
import { KupolaComponent, applyMixin } from './component.js';
|
|
2
|
+
import { kupolaInitializer } from './initializer.js';
|
|
3
|
+
|
|
4
|
+
export class KupolaComponentRegistry {
|
|
2
5
|
constructor() {
|
|
3
6
|
this.components = new Map();
|
|
4
7
|
this.lazyComponents = new Map();
|
|
@@ -10,7 +13,7 @@ class KupolaComponentRegistry {
|
|
|
10
13
|
}
|
|
11
14
|
|
|
12
15
|
register(name, componentClass) {
|
|
13
|
-
if (!(componentClass.prototype instanceof
|
|
16
|
+
if (!(componentClass.prototype instanceof KupolaComponent)) {
|
|
14
17
|
throw new Error(`Component ${name} must extend KupolaComponent`);
|
|
15
18
|
}
|
|
16
19
|
this.components.set(name, componentClass);
|
|
@@ -48,7 +51,7 @@ class KupolaComponentRegistry {
|
|
|
48
51
|
try {
|
|
49
52
|
const result = await loader();
|
|
50
53
|
const componentClass = result.default || result;
|
|
51
|
-
if (!(componentClass.prototype instanceof
|
|
54
|
+
if (!(componentClass.prototype instanceof KupolaComponent)) {
|
|
52
55
|
throw new Error(`Component ${name} must extend KupolaComponent`);
|
|
53
56
|
}
|
|
54
57
|
this.loadedComponents.set(name, componentClass);
|
|
@@ -70,8 +73,8 @@ class KupolaComponentRegistry {
|
|
|
70
73
|
useMixin(componentClass, ...mixinNames) {
|
|
71
74
|
mixinNames.forEach(name => {
|
|
72
75
|
const mixin = this.mixins.get(name);
|
|
73
|
-
if (mixin
|
|
74
|
-
|
|
76
|
+
if (mixin) {
|
|
77
|
+
applyMixin(componentClass, mixin);
|
|
75
78
|
}
|
|
76
79
|
});
|
|
77
80
|
}
|
|
@@ -98,8 +101,8 @@ class KupolaComponentRegistry {
|
|
|
98
101
|
try {
|
|
99
102
|
const componentName = element.getAttribute('data-component');
|
|
100
103
|
|
|
101
|
-
if (
|
|
102
|
-
const initializer =
|
|
104
|
+
if (componentName) {
|
|
105
|
+
const initializer = kupolaInitializer.get(componentName);
|
|
103
106
|
if (initializer) {
|
|
104
107
|
try {
|
|
105
108
|
await initializer(element);
|
|
@@ -127,11 +130,11 @@ class KupolaComponentRegistry {
|
|
|
127
130
|
|
|
128
131
|
const mixinNames = element.getAttribute('data-mixins');
|
|
129
132
|
const componentClass = ComponentClass;
|
|
130
|
-
if (mixinNames
|
|
133
|
+
if (mixinNames) {
|
|
131
134
|
mixinNames.split(',').forEach(name => {
|
|
132
135
|
const mixin = this.mixins.get(name.trim());
|
|
133
136
|
if (mixin) {
|
|
134
|
-
|
|
137
|
+
applyMixin(componentClass, mixin);
|
|
135
138
|
}
|
|
136
139
|
});
|
|
137
140
|
}
|
|
@@ -152,15 +155,26 @@ class KupolaComponentRegistry {
|
|
|
152
155
|
mutations.forEach(mutation => {
|
|
153
156
|
mutation.addedNodes.forEach(node => {
|
|
154
157
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
158
|
+
// Try registry first (class components via data-component)
|
|
155
159
|
if (node.hasAttribute('data-component')) {
|
|
156
160
|
this._upgradeElement(node).catch(e => console.error(e));
|
|
157
161
|
}
|
|
158
162
|
this._upgradeElements(node).catch(e => console.error(e));
|
|
163
|
+
// Also try initializer (function components via data-* attributes / CSS classes)
|
|
164
|
+
kupolaInitializer.initialize(node).catch(() => {});
|
|
165
|
+
// Check children too
|
|
166
|
+
const selector = kupolaInitializer._buildSelector();
|
|
167
|
+
if (selector) {
|
|
168
|
+
node.querySelectorAll?.(selector).forEach(child => {
|
|
169
|
+
kupolaInitializer.initialize(child).catch(() => {});
|
|
170
|
+
});
|
|
171
|
+
}
|
|
159
172
|
}
|
|
160
173
|
});
|
|
161
174
|
|
|
162
175
|
mutation.removedNodes.forEach(node => {
|
|
163
176
|
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
177
|
+
// Cleanup registry instances
|
|
164
178
|
const instance = this.instances.get(node);
|
|
165
179
|
if (instance) {
|
|
166
180
|
instance.unmount();
|
|
@@ -173,6 +187,11 @@ class KupolaComponentRegistry {
|
|
|
173
187
|
this.instances.delete(child);
|
|
174
188
|
}
|
|
175
189
|
});
|
|
190
|
+
// Cleanup initializer instances
|
|
191
|
+
kupolaInitializer.cleanup(node);
|
|
192
|
+
node.querySelectorAll?.('*').forEach(child => {
|
|
193
|
+
kupolaInitializer.cleanup(child);
|
|
194
|
+
});
|
|
176
195
|
}
|
|
177
196
|
});
|
|
178
197
|
});
|
|
@@ -198,8 +217,6 @@ class KupolaComponentRegistry {
|
|
|
198
217
|
}
|
|
199
218
|
}
|
|
200
219
|
|
|
201
|
-
if (typeof
|
|
202
|
-
module.exports = { KupolaComponentRegistry };
|
|
203
|
-
} else {
|
|
220
|
+
if (typeof window !== 'undefined') {
|
|
204
221
|
window.KupolaComponentRegistry = KupolaComponentRegistry;
|
|
205
222
|
}
|