@kupola/kupola 1.2.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +330 -286
  3. package/adapters/axios.d.ts +34 -0
  4. package/adapters/axios.js +122 -0
  5. package/adapters/navios-http.d.ts +110 -0
  6. package/adapters/navios-http.js +151 -0
  7. package/dist/css/accessibility.css +119 -0
  8. package/dist/css/animations.css +224 -0
  9. package/dist/css/brand-themes.css +300 -0
  10. package/dist/css/colors_and_type.css +441 -0
  11. package/dist/css/components-ext.css +4165 -0
  12. package/dist/css/components.css +1483 -0
  13. package/dist/css/responsive.css +697 -0
  14. package/dist/css/scaffold.css +145 -0
  15. package/dist/css/states.css +316 -0
  16. package/dist/css/theme-dark.css +296 -0
  17. package/dist/css/theme-light.css +296 -0
  18. package/dist/css/utilities.css +171 -0
  19. package/dist/kupola.cjs.js +219 -161
  20. package/dist/kupola.cjs.js.map +1 -1
  21. package/dist/kupola.esm.js +6643 -5709
  22. package/dist/kupola.esm.js.map +1 -1
  23. package/dist/kupola.umd.js +219 -161
  24. package/dist/kupola.umd.js.map +1 -1
  25. package/dist/plugins/vite-plugin-kupola.js +120 -0
  26. package/dist/types/kupola.d.ts +421 -323
  27. package/js/calendar.js +334 -25
  28. package/js/carousel.js +182 -48
  29. package/js/collapse.js +148 -34
  30. package/js/color-picker.js +416 -108
  31. package/js/component.js +8 -19
  32. package/js/countdown.js +9 -8
  33. package/js/data-bind.js +73 -16
  34. package/js/datepicker.js +488 -110
  35. package/js/depends.js +710 -0
  36. package/js/dialog.js +4 -2
  37. package/js/drawer.js +172 -8
  38. package/js/dropdown.js +272 -17
  39. package/js/dynamic-tags.js +156 -40
  40. package/js/fileupload.js +9 -8
  41. package/js/form.js +280 -254
  42. package/js/global-events.js +281 -188
  43. package/js/heatmap.js +10 -7
  44. package/js/i18n.js +18 -10
  45. package/js/icons.js +141 -161
  46. package/js/image-preview.js +146 -2
  47. package/js/initializer.js +113 -71
  48. package/js/kupola-core.js +123 -45
  49. package/js/kupola-lifecycle.js +13 -11
  50. package/js/message.js +8 -1
  51. package/js/modal.js +207 -59
  52. package/js/notification.js +8 -1
  53. package/js/numberinput.js +9 -8
  54. package/js/pagination.js +263 -0
  55. package/js/registry.js +29 -12
  56. package/js/select.js +482 -27
  57. package/js/slide-captcha.js +11 -2
  58. package/js/slider.js +442 -25
  59. package/js/statcard.js +9 -7
  60. package/js/table.js +1210 -0
  61. package/js/tag.js +268 -14
  62. package/js/theme.js +14 -43
  63. package/js/timepicker.js +335 -66
  64. package/js/tooltip.js +317 -86
  65. package/js/utils.js +6 -2
  66. package/js/validation.js +6 -2
  67. package/js/virtual-list.js +11 -7
  68. package/js/web-components.js +288 -0
  69. package/package.json +77 -67
  70. package/plugins/vite-plugin-kupola.js +120 -0
  71. package/types/kupola.d.ts +421 -323
  72. package/CHANGELOG.md +0 -130
  73. package/INTEGRATION.md +0 -440
  74. package/PROJECT_SUMMARY.md +0 -312
  75. package/SKILL.md +0 -572
  76. package/dist/utils/utils/Kupola.cs +0 -77
  77. package/dist/utils/utils/Kupola.java +0 -104
  78. package/dist/utils/utils/kupola.go +0 -120
  79. package/dist/utils/utils/kupola.js +0 -63
  80. package/dist/utils/utils/kupola.py +0 -1392
  81. package/dist/utils/utils/kupola.rb +0 -69
  82. package/js/composition-api.js +0 -458
  83. package/js/error-handler.js +0 -181
  84. package/js/http.js +0 -419
  85. package/js/kupola-devtools.js +0 -598
  86. package/js/performance.js +0 -250
  87. package/js/router.js +0 -396
  88. package/js/security.js +0 -189
  89. package/js/test-utils.js +0 -251
  90. package/templates/base.html +0 -30
  91. package/templates/base_dashboard.html +0 -99
  92. package/utils/Kupola.cs +0 -77
  93. package/utils/Kupola.java +0 -104
  94. package/utils/kupola.go +0 -120
  95. package/utils/kupola.js +0 -63
  96. package/utils/kupola.py +0 -1392
  97. package/utils/kupola.rb +0 -69
@@ -1,598 +0,0 @@
1
- class KupolaDevTools {
2
- constructor(options = {}) {
3
- this.enabled = options.enabled ?? false;
4
- this.panel = null;
5
- this.isOpen = false;
6
- this.activeTab = 'storage';
7
- this.activeStorageType = 'cookies';
8
- this.requestHistory = [];
9
- this.maxHistorySize = 50;
10
- }
11
-
12
- init() {
13
- if (!this.enabled) return;
14
- try {
15
- this.createToggleButton();
16
- this.createPanel();
17
- this.setupNetworkInterceptor();
18
- } catch (error) {
19
- console.error('Error in init:', error);
20
- }
21
- }
22
-
23
- createToggleButton() {
24
- const button = document.createElement('button');
25
- button.className = 'kupola-devtools__toggle';
26
- button.textContent = '🛠️';
27
- button.style.cssText = `
28
- position: fixed;
29
- bottom: 28px;
30
- left: 50px;
31
- width: 48px;
32
- height: 48px;
33
- border-radius: 50%;
34
- background: #535164;
35
- color: white;
36
- border: none;
37
- cursor: pointer;
38
- z-index: 9999;
39
- font-size: 20px;
40
- box-shadow: 0 4px 12px rgba(0,0,0,0.3);
41
- transition: transform 0.2s;
42
- `;
43
- button.addEventListener('click', () => this.togglePanel());
44
- document.body.appendChild(button);
45
- this.toggleButton = button;
46
- }
47
-
48
- createPanel() {
49
- const panel = document.createElement('div');
50
- panel.className = 'kupola-devtools__panel';
51
- panel.style.cssText = `
52
- position: fixed;
53
- bottom: 80px;
54
- left: 28px;
55
- width: 550px;
56
- max-height: 650px;
57
- background: #1e1e1e;
58
- border-radius: 12px;
59
- box-shadow: 0 8px 32px rgba(0,0,0,0.4);
60
- z-index: 9998;
61
- display: none;
62
- flex-direction: column;
63
- overflow: hidden;
64
- border: 1px solid #333;
65
- `;
66
-
67
- panel.innerHTML = `
68
- <div class="kupola-devtools__header">
69
- <span class="kupola-devtools__title">DevTools</span>
70
- <button class="kupola-devtools__close">✕</button>
71
- </div>
72
- <div class="kupola-devtools__tabs">
73
- <button data-tab="storage" class="kupola-devtools__tab active">Storage</button>
74
- <button data-tab="network" class="kupola-devtools__tab">Network</button>
75
- </div>
76
- <div class="kupola-devtools__sub-tabs" id="storage-sub-tabs">
77
- <button class="kupola-devtools__sub-tab active" data-storage="cookies">Cookies</button>
78
- <button class="kupola-devtools__sub-tab" data-storage="localStorage">LocalStorage</button>
79
- <button class="kupola-devtools__sub-tab" data-storage="sessionStorage">SessionStorage</button>
80
- </div>
81
- <div class="kupola-devtools__sub-tabs" id="network-sub-tabs" style="display:none;">
82
- <button class="kupola-devtools__network-action" data-action="clear">Clear</button>
83
- </div>
84
- <div class="kupola-devtools__content">
85
- ${this.getStorageContent('cookies')}
86
- </div>
87
- `;
88
-
89
- document.body.appendChild(panel);
90
- this.panel = panel;
91
-
92
- panel.querySelector('.kupola-devtools__close').addEventListener('click', () => this.togglePanel());
93
- panel.querySelectorAll('.kupola-devtools__tab').forEach(tab => {
94
- tab.addEventListener('click', () => this.switchTab(tab.dataset.tab));
95
- });
96
- this.setupStorageListener();
97
- this.makeDraggable();
98
- this.injectStyles();
99
- }
100
-
101
- switchTab(tabName) {
102
- this.activeTab = tabName;
103
-
104
- this.panel.querySelectorAll('.kupola-devtools__tab').forEach(tab => {
105
- tab.classList.toggle('active', tab.dataset.tab === tabName);
106
- });
107
-
108
- const storageSubTabs = this.panel.querySelector('#storage-sub-tabs');
109
- const networkSubTabs = this.panel.querySelector('#network-sub-tabs');
110
-
111
- if (tabName === 'storage') {
112
- storageSubTabs.style.display = 'flex';
113
- networkSubTabs.style.display = 'none';
114
- this.renderStorageContent();
115
- } else {
116
- storageSubTabs.style.display = 'none';
117
- networkSubTabs.style.display = 'flex';
118
- this.renderNetworkContent();
119
- }
120
- }
121
-
122
- renderStorageContent() {
123
- const content = this.panel.querySelector('.kupola-devtools__content');
124
- if (content) {
125
- content.innerHTML = this.getStorageContent(this.activeStorageType);
126
- }
127
- }
128
-
129
- renderNetworkContent() {
130
- const content = this.panel.querySelector('.kupola-devtools__content');
131
- if (!content) return;
132
-
133
- if (this.requestHistory.length === 0) {
134
- content.innerHTML = '<div class="kupola-devtools__loading">No network requests captured</div>';
135
- return;
136
- }
137
-
138
- let html = '';
139
- this.requestHistory.forEach((req, index) => {
140
- const statusClass = req.status >= 200 && req.status < 300 ? 'success' :
141
- req.status >= 400 ? 'error' : 'warning';
142
- const duration = req.duration ? `${req.duration}ms` : '-';
143
-
144
- html += `
145
- <div class="kupola-devtools__network-item" data-index="${index}">
146
- <div class="kupola-devtools__network-header">
147
- <span class="kupola-devtools__network-method">${req.method}</span>
148
- <span class="kupola-devtools__network-url">${req.url}</span>
149
- <span class="kupola-devtools__network-status ${statusClass}">${req.status}</span>
150
- <span class="kupola-devtools__network-duration">${duration}</span>
151
- </div>
152
- <div class="kupola-devtools__network-details" style="display:none;">
153
- ${req.params ? `<div class="kupola-devtools__network-detail"><strong>Params:</strong><pre>${this.truncateContent(JSON.stringify(req.params, null, 2), 1000)}</pre></div>` : ''}
154
- ${req.requestBody ? `<div class="kupola-devtools__network-detail"><strong>Request Body:</strong><pre>${this.truncateContent(req.requestBody, 1000)}</pre></div>` : ''}
155
- ${req.response ? `<div class="kupola-devtools__network-detail"><strong>Response:</strong><pre>${this.truncateContent(req.response, 1500)}</pre></div>` : ''}
156
- </div>
157
- </div>
158
- `;
159
- });
160
-
161
- content.innerHTML = html;
162
-
163
- content.querySelectorAll('.kupola-devtools__network-item').forEach(item => {
164
- item.addEventListener('click', () => {
165
- const details = item.querySelector('.kupola-devtools__network-details');
166
- details.style.display = details.style.display === 'none' ? 'block' : 'none';
167
- });
168
- });
169
-
170
- const clearBtn = this.panel.querySelector('[data-action="clear"]');
171
- if (clearBtn) {
172
- clearBtn.addEventListener('click', (e) => {
173
- e.stopPropagation();
174
- this.clearNetworkHistory();
175
- });
176
- }
177
- }
178
-
179
- clearNetworkHistory() {
180
- this.requestHistory = [];
181
- this.renderNetworkContent();
182
- }
183
-
184
- truncateContent(content, maxLength) {
185
- if (!content) return '-';
186
- const str = typeof content === 'string' ? content : JSON.stringify(content);
187
- if (str.length <= maxLength) return str;
188
- return str.substring(0, maxLength) + `... (truncated, ${str.length} chars)`;
189
- }
190
-
191
- setupNetworkInterceptor() {
192
- const devTools = this;
193
-
194
- const originalFetch = window.fetch;
195
- window.fetch = async function(url, options = {}) {
196
- const startTime = Date.now();
197
- const requestId = Date.now() + Math.random();
198
-
199
- let requestBody = null;
200
- if (options.body) {
201
- if (typeof options.body === 'string') {
202
- requestBody = options.body;
203
- } else if (options.body instanceof FormData) {
204
- try {
205
- requestBody = JSON.stringify(Object.fromEntries(options.body));
206
- } catch {}
207
- } else {
208
- try {
209
- requestBody = JSON.stringify(options.body);
210
- } catch {}
211
- }
212
- }
213
-
214
- let params = null;
215
- try {
216
- const urlObj = new URL(typeof url === 'string' ? url : url.href);
217
- if (urlObj.search) {
218
- params = Object.fromEntries(urlObj.searchParams);
219
- }
220
- } catch {}
221
-
222
- const entry = {
223
- id: requestId,
224
- method: options.method || 'GET',
225
- url: typeof url === 'string' ? url : url.href,
226
- params,
227
- requestBody,
228
- status: 0,
229
- response: null,
230
- duration: null
231
- };
232
-
233
- devTools.addRequest(entry);
234
-
235
- try {
236
- const response = await originalFetch.apply(this, arguments);
237
-
238
- entry.status = response.status;
239
- entry.duration = Date.now() - startTime;
240
-
241
- try {
242
- const clone = response.clone();
243
- const text = await clone.text();
244
- try {
245
- entry.response = JSON.parse(text);
246
- } catch {
247
- entry.response = text;
248
- }
249
- } catch {}
250
-
251
- devTools.updateRequest(entry);
252
-
253
- return response;
254
- } catch (error) {
255
- entry.status = -1;
256
- entry.response = error.message;
257
- entry.duration = Date.now() - startTime;
258
- devTools.updateRequest(entry);
259
- throw error;
260
- }
261
- };
262
-
263
- const originalOpen = XMLHttpRequest.prototype.open;
264
- XMLHttpRequest.prototype.open = function(method, url) {
265
- this.__kupolaRequest = {
266
- method,
267
- url,
268
- params: null,
269
- requestBody: null,
270
- status: 0,
271
- response: null,
272
- startTime: Date.now()
273
- };
274
-
275
- try {
276
- const urlObj = new URL(url);
277
- if (urlObj.search) {
278
- this.__kupolaRequest.params = Object.fromEntries(urlObj.searchParams);
279
- }
280
- } catch {}
281
-
282
- originalOpen.apply(this, arguments);
283
- };
284
-
285
- const originalSend = XMLHttpRequest.prototype.send;
286
- XMLHttpRequest.prototype.send = function(body) {
287
- if (this.__kupolaRequest) {
288
- if (body) {
289
- if (typeof body === 'string') {
290
- this.__kupolaRequest.requestBody = body;
291
- } else if (body instanceof FormData) {
292
- try {
293
- this.__kupolaRequest.requestBody = JSON.stringify(Object.fromEntries(body));
294
- } catch {}
295
- }
296
- }
297
-
298
- const entry = { ...this.__kupolaRequest };
299
- devTools.addRequest(entry);
300
- this.__kupolaEntry = entry;
301
- }
302
-
303
- originalSend.apply(this, arguments);
304
- };
305
-
306
- const originalOnReadyStateChange = XMLHttpRequest.prototype.onreadystatechange;
307
- XMLHttpRequest.prototype.onreadystatechange = function() {
308
- if (this.__kupolaEntry && this.readyState === 4) {
309
- this.__kupolaEntry.status = this.status;
310
- this.__kupolaEntry.duration = Date.now() - this.__kupolaRequest.startTime;
311
-
312
- try {
313
- const responseText = this.responseText;
314
- try {
315
- this.__kupolaEntry.response = JSON.parse(responseText);
316
- } catch {
317
- this.__kupolaEntry.response = responseText;
318
- }
319
- } catch {}
320
-
321
- devTools.updateRequest(this.__kupolaEntry);
322
- }
323
-
324
- if (typeof originalOnReadyStateChange === 'function') {
325
- originalOnReadyStateChange.apply(this, arguments);
326
- }
327
- };
328
- }
329
-
330
- addRequest(entry) {
331
- this.requestHistory.unshift(entry);
332
- if (this.requestHistory.length > this.maxHistorySize) {
333
- this.requestHistory.pop();
334
- }
335
-
336
- if (this.isOpen && this.activeTab === 'network') {
337
- this.renderNetworkContent();
338
- }
339
- }
340
-
341
- updateRequest(entry) {
342
- const index = this.requestHistory.findIndex(r => r.id === entry.id ||
343
- (r.url === entry.url && r.method === entry.method && !r.status));
344
- if (index !== -1) {
345
- this.requestHistory[index] = entry;
346
-
347
- if (this.isOpen && this.activeTab === 'network') {
348
- this.renderNetworkContent();
349
- }
350
- }
351
- }
352
-
353
- setupStorageListener() {
354
- const devTools = this;
355
-
356
- window.addEventListener('storage', (e) => {
357
- if (devTools.isOpen && devTools.activeTab === 'storage') {
358
- const content = devTools.panel?.querySelector('.kupola-devtools__content');
359
- if (content) {
360
- const type = e.storageArea === localStorage ? 'localStorage' : 'sessionStorage';
361
- devTools.activeStorageType = type;
362
- devTools.updateStorageTabs();
363
- content.innerHTML = devTools.getStorageContent(type);
364
- }
365
- }
366
- });
367
-
368
- const originalSetItem = Storage.prototype.setItem;
369
- Storage.prototype.setItem = function(key, value) {
370
- const oldValue = this.getItem(key);
371
- originalSetItem.call(this, key, value);
372
- const event = new StorageEvent('storage', {
373
- key,
374
- oldValue,
375
- newValue: value,
376
- url: window.location.href,
377
- storageArea: this
378
- });
379
- window.dispatchEvent(event);
380
- };
381
-
382
- const originalRemoveItem = Storage.prototype.removeItem;
383
- Storage.prototype.removeItem = function(key) {
384
- const oldValue = this.getItem(key);
385
- originalRemoveItem.call(this, key);
386
- const event = new StorageEvent('storage', {
387
- key,
388
- oldValue,
389
- newValue: null,
390
- url: window.location.href,
391
- storageArea: this
392
- });
393
- window.dispatchEvent(event);
394
- };
395
- }
396
-
397
- injectStyles() {
398
- const styles = document.createElement('style');
399
- styles.textContent = `
400
- .kupola-devtools__header { display: flex; justify-content: space-between; align-items: center; padding: 12px 16px; background: #2d2d2d; border-bottom: 1px solid #333; }
401
- .kupola-devtools__title { color: #535164; font-weight: 600; font-size: 14px; }
402
- .kupola-devtools__close { background: none; border: none; color: #888; cursor: pointer; font-size: 14px; padding: 4px; }
403
- .kupola-devtools__close:hover { color: #fff; }
404
- .kupola-devtools__tabs { display: flex; background: #252525; border-bottom: 1px solid #333; }
405
- .kupola-devtools__tab { flex: 1; padding: 10px 8px; background: none; border: none; color: #888; cursor: pointer; font-size: 11px; border-bottom: 2px solid transparent; transition: all 0.2s; }
406
- .kupola-devtools__tab:hover { color: #fff; }
407
- .kupola-devtools__tab.active { color: #535164; border-bottom-color: #535164; }
408
- .kupola-devtools__sub-tabs { display: flex; gap: 4px; padding: 8px 12px; background: #1e1e1e; border-bottom: 1px solid #333; }
409
- .kupola-devtools__sub-tab { padding: 4px 8px; background: #333; border: none; color: #888; cursor: pointer; font-size: 11px; border-radius: 4px; }
410
- .kupola-devtools__sub-tab:hover { color: #fff; }
411
- .kupola-devtools__sub-tab.active { background: #535164; color: white; }
412
- .kupola-devtools__network-action { padding: 4px 8px; background: #333; border: none; color: #888; cursor: pointer; font-size: 11px; border-radius: 4px; }
413
- .kupola-devtools__network-action:hover { color: #fff; background: #444; }
414
- .kupola-devtools__content { flex: 1; overflow-y: auto; padding: 12px; font-family: 'Consolas', monospace; font-size: 12px; }
415
- .kupola-devtools__list-item { padding: 6px 8px; border-radius: 4px; margin-bottom: 4px; background: #2a2a2a; }
416
- .kupola-devtools__list-item:hover { background: #333; }
417
- .kupola-devtools__loading { display: flex; justify-content: center; align-items: center; height: 100px; color: #666; }
418
- .kupola-devtools__storage-key { color: #9cdcfe; margin-right: 8px; }
419
- .kupola-devtools__storage-value { color: #ce9178; word-break: break-all; }
420
- .kupola-devtools__network-item { padding: 6px 8px; border-radius: 4px; margin-bottom: 4px; background: #2a2a2a; cursor: pointer; }
421
- .kupola-devtools__network-item:hover { background: #333; }
422
- .kupola-devtools__network-header { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
423
- .kupola-devtools__network-method { padding: 2px 6px; border-radius: 3px; font-weight: 600; font-size: 11px; color: white; }
424
- .kupola-devtools__network-method.GET { background: #4CAF50; }
425
- .kupola-devtools__network-method.POST { background: #2196F3; }
426
- .kupola-devtools__network-method.PUT { background: #FF9800; }
427
- .kupola-devtools__network-method.DELETE { background: #F44336; }
428
- .kupola-devtools__network-method.PATCH { background: #9C27B0; }
429
- .kupola-devtools__network-url { flex: 1; color: #9cdcfe; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
430
- .kupola-devtools__network-status { padding: 2px 6px; border-radius: 3px; font-size: 11px; font-weight: 600; }
431
- .kupola-devtools__network-status.success { background: #4CAF50; color: white; }
432
- .kupola-devtools__network-status.error { background: #F44336; color: white; }
433
- .kupola-devtools__network-status.warning { background: #FF9800; color: white; }
434
- .kupola-devtools__network-duration { color: #888; font-size: 11px; }
435
- .kupola-devtools__network-details { margin-top: 8px; padding-top: 8px; border-top: 1px solid #333; }
436
- .kupola-devtools__network-detail { margin-bottom: 8px; }
437
- .kupola-devtools__network-detail strong { color: #535164; display: block; margin-bottom: 4px; }
438
- .kupola-devtools__network-detail pre { margin: 0; color: #ce9178; white-space: pre-wrap; word-break: break-all; }
439
- `;
440
- document.head.appendChild(styles);
441
- }
442
-
443
- makeDraggable() {
444
- const header = this.panel.querySelector('.kupola-devtools__header');
445
- let isDragging = false;
446
- let startX, startY, startLeft, startTop;
447
-
448
- this._dragMouseDownHandler = (e) => {
449
- if (e.target.closest('.kupola-devtools__close')) return;
450
- isDragging = true;
451
- startX = e.clientX;
452
- startY = e.clientY;
453
- startLeft = this.panel.offsetLeft;
454
- startTop = this.panel.offsetTop;
455
- };
456
-
457
- this._dragMouseMoveHandler = (e) => {
458
- if (!isDragging) return;
459
- const dx = e.clientX - startX;
460
- const dy = e.clientY - startY;
461
- this.panel.style.left = `${startLeft + dx}px`;
462
- this.panel.style.right = 'auto';
463
- this.panel.style.top = `${Math.max(0, startTop + dy)}px`;
464
- };
465
-
466
- this._dragMouseUpHandler = () => { isDragging = false; };
467
-
468
- header.addEventListener('mousedown', this._dragMouseDownHandler);
469
- document.addEventListener('mousemove', this._dragMouseMoveHandler);
470
- document.addEventListener('mouseup', this._dragMouseUpHandler);
471
- }
472
-
473
- destroy() {
474
- const header = this.panel.querySelector('.kupola-devtools__header');
475
-
476
- if (header && this._dragMouseDownHandler) {
477
- header.removeEventListener('mousedown', this._dragMouseDownHandler);
478
- }
479
-
480
- if (this._dragMouseMoveHandler) {
481
- document.removeEventListener('mousemove', this._dragMouseMoveHandler);
482
- }
483
-
484
- if (this._dragMouseUpHandler) {
485
- document.removeEventListener('mouseup', this._dragMouseUpHandler);
486
- }
487
-
488
- if (this.panel && this.panel.parentNode) {
489
- this.panel.parentNode.removeChild(this.panel);
490
- }
491
-
492
- this._dragMouseDownHandler = null;
493
- this._dragMouseMoveHandler = null;
494
- this._dragMouseUpHandler = null;
495
- this.panel = null;
496
- }
497
-
498
- togglePanel() {
499
- this.isOpen = !this.isOpen;
500
- this.panel.style.display = this.isOpen ? 'flex' : 'none';
501
-
502
- if (this.isOpen && this.activeTab === 'network') {
503
- this.renderNetworkContent();
504
- }
505
- }
506
-
507
- updateStorageTabs() {
508
- this.panel.querySelectorAll('.kupola-devtools__sub-tab').forEach(tab => {
509
- tab.classList.toggle('active', tab.dataset.storage === this.activeStorageType);
510
- });
511
- }
512
-
513
- getStorageContent(type) {
514
- let items = [];
515
-
516
- try {
517
- if (type === 'cookies') {
518
- items = document.cookie.split(';').map(c => c.trim()).filter(c => c).map(c => {
519
- const [key, ...valueParts] = c.split('=');
520
- return { key, value: valueParts.join('=') };
521
- });
522
- } else if (type === 'localStorage') {
523
- for (let i = 0; i < localStorage.length; i++) {
524
- items.push({ key: localStorage.key(i), value: localStorage.getItem(localStorage.key(i)) });
525
- }
526
- } else if (type === 'sessionStorage') {
527
- for (let i = 0; i < sessionStorage.length; i++) {
528
- items.push({ key: sessionStorage.key(i), value: sessionStorage.getItem(sessionStorage.key(i)) });
529
- }
530
- }
531
- } catch (e) {
532
- console.error('Error reading storage:', e);
533
- return '<div class="kupola-devtools__loading">Error reading storage</div>';
534
- }
535
-
536
- if (items.length === 0) return '<div class="kupola-devtools__loading">No data</div>';
537
-
538
- let html = '';
539
- items.forEach(item => {
540
- let displayValue = item.value;
541
- if (displayValue && displayValue.length > 0 && displayValue.length < 2000) {
542
- try {
543
- const parsed = JSON.parse(displayValue);
544
- displayValue = JSON.stringify(parsed, null, 2);
545
- } catch {}
546
- } else if (displayValue && displayValue.length >= 2000) {
547
- displayValue = displayValue.substring(0, 500) + '... (truncated, ' + displayValue.length + ' chars)';
548
- }
549
- html += `<div class="kupola-devtools__list-item"><div><span class="kupola-devtools__storage-key">${item.key}</span></div><div class="kupola-devtools__storage-value">${displayValue}</div></div>`;
550
- });
551
-
552
- return html;
553
- }
554
-
555
- handleStorageClick(e) {
556
- const target = e.target;
557
- if (target.classList.contains('kupola-devtools__sub-tab')) {
558
- e.stopPropagation();
559
- const type = target.dataset.storage;
560
- if (type) {
561
- this.activeStorageType = type;
562
- this.updateStorageTabs();
563
- const content = this.panel.querySelector('.kupola-devtools__content');
564
- if (content) {
565
- content.innerHTML = this.getStorageContent(type);
566
- }
567
- }
568
- }
569
- }
570
- }
571
-
572
- function initDevTools() {
573
- try {
574
- const urlParams = new URLSearchParams(window.location.search);
575
- const enabled = urlParams.has('dev') || urlParams.has('debug');
576
-
577
- if (enabled) {
578
- window.kupolaDevTools = new KupolaDevTools({ enabled: true });
579
- window.kupolaDevTools.init();
580
-
581
- window.addEventListener('click', (e) => {
582
- if (window.kupolaDevTools && window.kupolaDevTools.handleStorageClick) {
583
- window.kupolaDevTools.handleStorageClick(e);
584
- }
585
- });
586
- }
587
- } catch (error) {
588
- console.error('Error initializing Kupola DevTools:', error);
589
- }
590
- }
591
-
592
- if (document.readyState === 'loading') {
593
- document.addEventListener('DOMContentLoaded', initDevTools);
594
- } else {
595
- initDevTools();
596
- }
597
-
598
- window.KupolaDevTools = KupolaDevTools;