@emailmaker/filemanager 0.0.2 → 0.0.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.
@@ -1 +1 @@
1
- const PACKAGE_VERSION="2.10.3",INTEGRITY_CHECKSUM="f5825c521429caf22a4dd13b66e243af",IS_MOCKED_RESPONSE=Symbol("isMockedResponse"),activeClientIds=new Set;async function handleRequest(e,t){const n=await resolveMainClient(e),s=e.request.clone(),i=await getResponse(e,n,t);if(n&&activeClientIds.has(n.id)){const e=await serializeRequest(s),a=i.clone();sendToClient(n,{type:"RESPONSE",payload:{isMockedResponse:IS_MOCKED_RESPONSE in i,request:{id:t,...e},response:{type:a.type,status:a.status,statusText:a.statusText,headers:Object.fromEntries(a.headers.entries()),body:a.body}}},a.body?[e.body,a.body]:[])}return i}async function resolveMainClient(e){const t=await self.clients.get(e.clientId);return activeClientIds.has(e.clientId)||"top-level"===t?.frameType?t:(await self.clients.matchAll({type:"window"})).filter((e=>"visible"===e.visibilityState)).find((e=>activeClientIds.has(e.id)))}async function getResponse(e,t,n){const s=e.request.clone();function i(){const e=new Headers(s.headers),t=e.get("accept");if(t){const n=t.split(",").map((e=>e.trim())).filter((e=>"msw/passthrough"!==e));n.length>0?e.set("accept",n.join(", ")):e.delete("accept")}return fetch(s,{headers:e})}if(!t)return i();if(!activeClientIds.has(t.id))return i();const a=await serializeRequest(e.request),r=await sendToClient(t,{type:"REQUEST",payload:{id:n,...a}},[a.body]);switch(r.type){case"MOCK_RESPONSE":return respondWithMock(r.data);case"PASSTHROUGH":return i()}return i()}function sendToClient(e,t,n=[]){return new Promise(((s,i)=>{const a=new MessageChannel;a.port1.onmessage=e=>{if(e.data&&e.data.error)return i(e.data.error);s(e.data)},e.postMessage(t,[a.port2,...n.filter(Boolean)])}))}function respondWithMock(e){if(0===e.status)return Response.error();const t=new Response(e.body,e);return Reflect.defineProperty(t,IS_MOCKED_RESPONSE,{value:!0,enumerable:!0}),t}async function serializeRequest(e){return{url:e.url,mode:e.mode,method:e.method,headers:Object.fromEntries(e.headers.entries()),cache:e.cache,credentials:e.credentials,destination:e.destination,integrity:e.integrity,redirect:e.redirect,referrer:e.referrer,referrerPolicy:e.referrerPolicy,body:await e.arrayBuffer(),keepalive:e.keepalive}}addEventListener("install",(function(){self.skipWaiting()})),addEventListener("activate",(function(e){e.waitUntil(self.clients.claim())})),addEventListener("message",(async function(e){const t=Reflect.get(e.source||{},"id");if(!t||!self.clients)return;const n=await self.clients.get(t);if(!n)return;const s=await self.clients.matchAll({type:"window"});switch(e.data){case"KEEPALIVE_REQUEST":sendToClient(n,{type:"KEEPALIVE_RESPONSE"});break;case"INTEGRITY_CHECK_REQUEST":sendToClient(n,{type:"INTEGRITY_CHECK_RESPONSE",payload:{packageVersion:"2.10.3",checksum:INTEGRITY_CHECKSUM}});break;case"MOCK_ACTIVATE":activeClientIds.add(t),sendToClient(n,{type:"MOCKING_ENABLED",payload:{client:{id:n.id,frameType:n.frameType}}});break;case"MOCK_DEACTIVATE":activeClientIds.delete(t);break;case"CLIENT_CLOSED":{activeClientIds.delete(t);const e=s.filter((e=>e.id!==t));0===e.length&&self.registration.unregister();break}}})),addEventListener("fetch",(function(e){if("navigate"===e.request.mode)return;if("only-if-cached"===e.request.cache&&"same-origin"!==e.request.mode)return;if(0===activeClientIds.size)return;const t=crypto.randomUUID();e.respondWith(handleRequest(e,t))}));
1
+ const PACKAGE_VERSION="2.10.4",INTEGRITY_CHECKSUM="f5825c521429caf22a4dd13b66e243af",IS_MOCKED_RESPONSE=Symbol("isMockedResponse"),activeClientIds=new Set;async function handleRequest(e,t){const n=await resolveMainClient(e),s=e.request.clone(),i=await getResponse(e,n,t);if(n&&activeClientIds.has(n.id)){const e=await serializeRequest(s),a=i.clone();sendToClient(n,{type:"RESPONSE",payload:{isMockedResponse:IS_MOCKED_RESPONSE in i,request:{id:t,...e},response:{type:a.type,status:a.status,statusText:a.statusText,headers:Object.fromEntries(a.headers.entries()),body:a.body}}},a.body?[e.body,a.body]:[])}return i}async function resolveMainClient(e){const t=await self.clients.get(e.clientId);return activeClientIds.has(e.clientId)||"top-level"===t?.frameType?t:(await self.clients.matchAll({type:"window"})).filter(e=>"visible"===e.visibilityState).find(e=>activeClientIds.has(e.id))}async function getResponse(e,t,n){const s=e.request.clone();function i(){const e=new Headers(s.headers),t=e.get("accept");if(t){const n=t.split(",").map(e=>e.trim()).filter(e=>"msw/passthrough"!==e);n.length>0?e.set("accept",n.join(", ")):e.delete("accept")}return fetch(s,{headers:e})}if(!t)return i();if(!activeClientIds.has(t.id))return i();const a=await serializeRequest(e.request),r=await sendToClient(t,{type:"REQUEST",payload:{id:n,...a}},[a.body]);switch(r.type){case"MOCK_RESPONSE":return respondWithMock(r.data);case"PASSTHROUGH":return i()}return i()}function sendToClient(e,t,n=[]){return new Promise((s,i)=>{const a=new MessageChannel;a.port1.onmessage=e=>{if(e.data&&e.data.error)return i(e.data.error);s(e.data)},e.postMessage(t,[a.port2,...n.filter(Boolean)])})}function respondWithMock(e){if(0===e.status)return Response.error();const t=new Response(e.body,e);return Reflect.defineProperty(t,IS_MOCKED_RESPONSE,{value:!0,enumerable:!0}),t}async function serializeRequest(e){return{url:e.url,mode:e.mode,method:e.method,headers:Object.fromEntries(e.headers.entries()),cache:e.cache,credentials:e.credentials,destination:e.destination,integrity:e.integrity,redirect:e.redirect,referrer:e.referrer,referrerPolicy:e.referrerPolicy,body:await e.arrayBuffer(),keepalive:e.keepalive}}addEventListener("install",function(){self.skipWaiting()}),addEventListener("activate",function(e){e.waitUntil(self.clients.claim())}),addEventListener("message",async function(e){const t=Reflect.get(e.source||{},"id");if(!t||!self.clients)return;const n=await self.clients.get(t);if(!n)return;const s=await self.clients.matchAll({type:"window"});switch(e.data){case"KEEPALIVE_REQUEST":sendToClient(n,{type:"KEEPALIVE_RESPONSE"});break;case"INTEGRITY_CHECK_REQUEST":sendToClient(n,{type:"INTEGRITY_CHECK_RESPONSE",payload:{packageVersion:"2.10.4",checksum:INTEGRITY_CHECKSUM}});break;case"MOCK_ACTIVATE":activeClientIds.add(t),sendToClient(n,{type:"MOCKING_ENABLED",payload:{client:{id:n.id,frameType:n.frameType}}});break;case"MOCK_DEACTIVATE":activeClientIds.delete(t);break;case"CLIENT_CLOSED":{activeClientIds.delete(t);const e=s.filter(e=>e.id!==t);0===e.length&&self.registration.unregister();break}}}),addEventListener("fetch",function(e){if("navigate"===e.request.mode)return;if("only-if-cached"===e.request.cache&&"same-origin"!==e.request.mode)return;if(0===activeClientIds.size)return;const t=crypto.randomUUID();e.respondWith(handleRequest(e,t))});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@emailmaker/filemanager",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "main": "./file-manager.js",
5
5
  "module": "./file-manager.esm.js",
6
6
  "types": "./index.d.ts",
@@ -0,0 +1,105 @@
1
+ {
2
+ "files": [
3
+ {
4
+ "id": "sample-1",
5
+ "name": "Красивый закат.jpg",
6
+ "size": "2845",
7
+ "date": "2024-01-15T10:30:00Z",
8
+ "folderId": "",
9
+ "type": "image",
10
+ "url": "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=400&h=300&fit=crop",
11
+ "thumbnailUrl": "https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=150&h=100&fit=crop",
12
+ "extension": "jpg",
13
+ "isFolder": false,
14
+ "selected": false,
15
+ "dimensions": "1920x1080",
16
+ "aspectRatio": "16:9"
17
+ },
18
+ {
19
+ "id": "sample-2",
20
+ "name": "Горы и озеро.jpg",
21
+ "size": "3200",
22
+ "date": "2024-01-10T14:20:00Z",
23
+ "folderId": "nature-folder",
24
+ "type": "image",
25
+ "url": "https://images.unsplash.com/photo-1464822759380-8ed769e99d5c?w=400&h=300&fit=crop",
26
+ "thumbnailUrl": "https://images.unsplash.com/photo-1464822759380-8ed769e99d5c?w=150&h=100&fit=crop",
27
+ "extension": "jpg",
28
+ "isFolder": false,
29
+ "selected": false,
30
+ "dimensions": "1920x1280",
31
+ "aspectRatio": "3:2"
32
+ },
33
+ {
34
+ "id": "sample-3",
35
+ "name": "Отчет_2024.pdf",
36
+ "size": "1250",
37
+ "date": "2024-01-12T09:15:00Z",
38
+ "folderId": "documents-folder",
39
+ "type": "document",
40
+ "url": "https://via.placeholder.com/400x300/2196F3/white?text=PDF+Document",
41
+ "thumbnailUrl": "https://via.placeholder.com/150x100/2196F3/white?text=PDF",
42
+ "extension": "pdf",
43
+ "isFolder": false,
44
+ "selected": false
45
+ },
46
+ {
47
+ "id": "sample-4",
48
+ "name": "Презентация.pptx",
49
+ "size": "4500",
50
+ "date": "2024-01-08T16:45:00Z",
51
+ "folderId": "documents-folder",
52
+ "type": "document",
53
+ "url": "https://via.placeholder.com/400x300/FF9800/white?text=PowerPoint",
54
+ "thumbnailUrl": "https://via.placeholder.com/150x100/FF9800/white?text=PPT",
55
+ "extension": "pptx",
56
+ "isFolder": false,
57
+ "selected": false
58
+ },
59
+ {
60
+ "id": "sample-5",
61
+ "name": "Лес в тумане.jpg",
62
+ "size": "2100",
63
+ "date": "2024-01-05T11:30:00Z",
64
+ "folderId": "nature-folder",
65
+ "type": "image",
66
+ "url": "https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=400&h=300&fit=crop",
67
+ "thumbnailUrl": "https://images.unsplash.com/photo-1441974231531-c6227db76b6e?w=150&h=100&fit=crop",
68
+ "extension": "jpg",
69
+ "isFolder": false,
70
+ "selected": false,
71
+ "dimensions": "1920x1280",
72
+ "aspectRatio": "3:2"
73
+ },
74
+ {
75
+ "id": "sample-6",
76
+ "name": "Архивные_данные.zip",
77
+ "size": "15600",
78
+ "date": "2024-01-01T08:00:00Z",
79
+ "folderId": "",
80
+ "type": "archive",
81
+ "url": "https://via.placeholder.com/400x300/795548/white?text=ZIP+Archive",
82
+ "thumbnailUrl": "https://via.placeholder.com/150x100/795548/white?text=ZIP",
83
+ "extension": "zip",
84
+ "isFolder": false,
85
+ "selected": false
86
+ }
87
+ ],
88
+ "folders": [
89
+ {
90
+ "id": "nature-folder",
91
+ "name": "🌲 Природа",
92
+ "parentId": null
93
+ },
94
+ {
95
+ "id": "documents-folder",
96
+ "name": "📄 Документы",
97
+ "parentId": null
98
+ },
99
+ {
100
+ "id": "photos-subfolder",
101
+ "name": "📷 Фотографии",
102
+ "parentId": "nature-folder"
103
+ }
104
+ ]
105
+ }
@@ -1 +1 @@
1
- !function(){"use strict";console.log("🔧 Инициализация подавления ошибок ResizeObserver...");const e=console.error,o=window.onerror,n=e=>e&&"string"==typeof e&&e.includes("ResizeObserver loop completed with undelivered notifications");console.error=function(...o){const r=o[0]&&o[0].toString?o[0].toString():"";if(!n(r))return e.apply(console,o)},window.onerror=function(e,r,t,i,s){return!!(n(e)||s&&n(s.message))||!!o&&o.call(this,e,r,t,i,s)},window.addEventListener("error",(function(e){n(e.message)&&(e.stopImmediatePropagation(),e.preventDefault())}),!0),console.log("✅ Подавление ошибок ResizeObserver активировано")}();
1
+ !function(){"use strict";console.log("🔧 Инициализация подавления ошибок ResizeObserver...");const e=console.error,o=window.onerror,n=e=>e&&"string"==typeof e&&e.includes("ResizeObserver loop completed with undelivered notifications");console.error=function(...o){const r=o[0]&&o[0].toString?o[0].toString():"";if(!n(r))return e.apply(console,o)},window.onerror=function(e,r,t,i,s){return!!(n(e)||s&&n(s.message))||!!o&&o.call(this,e,r,t,i,s)},window.addEventListener("error",function(e){n(e.message)&&(e.stopImmediatePropagation(),e.preventDefault())},!0),console.log("✅ Подавление ошибок ResizeObserver активировано")}();
package/types.d.ts CHANGED
@@ -19,7 +19,9 @@ export interface File {
19
19
  date: string;
20
20
  folderId: string;
21
21
  type?: string;
22
+ url?: string;
22
23
  thumbnail?: string;
24
+ thumbnailUrl?: string;
23
25
  dimensions?: string;
24
26
  aspectRatio?: string;
25
27
  extension?: string;
@@ -125,6 +127,8 @@ export interface FileManagerDataProviders {
125
127
  getFiles: (options: {
126
128
  folderId?: string;
127
129
  search?: string;
130
+ sortBy?: SortState['sortBy'];
131
+ sortOrder?: SortState['sortOrder'];
128
132
  }) => Promise<File[]>;
129
133
  createFolder: (data: {
130
134
  name: string;
@@ -224,6 +228,12 @@ export interface Config {
224
228
  locale?: string;
225
229
  mode?: 'fileManager' | 'imageCenter' | 'plugin';
226
230
  enabledTabs?: string[];
231
+ dataProcessingMode?: 'server' | 'client' | 'auto';
232
+ enableClientSideProcessing?: boolean;
233
+ staticData?: {
234
+ files?: File[];
235
+ folders?: Folder[];
236
+ };
227
237
  customTheme?: {
228
238
  colors?: {
229
239
  primary?: string;
@@ -263,11 +273,16 @@ export interface Config {
263
273
  /** billing page url */
264
274
  billingPageUrl?: string;
265
275
  notification?: void;
266
- sendAIImageRequest?: any;
267
- sseQuery?: () => Promise<void>;
276
+ sendAIImageRequest?: (params: object) => Promise<unknown>;
277
+ sseQuery?: (params: object) => void;
268
278
  customLocale?: object;
269
279
  activeLibraryItem?: LibraryMenuKey;
270
280
  fileForEdit?: string;
281
+ messages?: MessageType[];
282
+ handleLimitUsageEmitter?: {
283
+ fire: (args: object) => void;
284
+ };
285
+ token?: Partial<import('antd/es/theme/interface').AliasToken>;
271
286
  }
272
287
  export type LibraryMenuKey = typeof MY_FILES | typeof GIF | typeof STOCK_IMAGES | typeof AI | typeof EDITOR;
273
288
  export interface GifItem {
@@ -320,12 +335,11 @@ export interface ImageStockProps {
320
335
  customRequest: (data: string) => void;
321
336
  }
322
337
  export interface ImageAIProps {
323
- setModalHeight: React.Dispatch<React.SetStateAction<string | number>>;
324
- customRequest: (args: {
325
- file: File;
326
- }) => void;
338
+ customRequest: (file: {
339
+ file: globalThis.File;
340
+ }) => Promise<void | File>;
327
341
  aiTabRef: RefObject<HTMLElement>;
328
- inputAiRef: RefObject<any>;
342
+ inputAiRef: React.RefObject<HTMLTextAreaElement>;
329
343
  isImageUploaded: boolean;
330
344
  setIsImageUploaded: (val: boolean) => void;
331
345
  aiImageRequest: string;
@@ -340,9 +354,9 @@ export interface ArrowProps {
340
354
  onClick?: () => void;
341
355
  }
342
356
  export interface UseImageAIGenerationProps {
343
- setModalHeight: React.Dispatch<React.SetStateAction<string | number>>;
357
+ setFrameHeight: React.Dispatch<React.SetStateAction<string | number>>;
344
358
  customRequest: (args: {
345
- file: File;
359
+ file: globalThis.File;
346
360
  }) => void;
347
361
  aiTabRef: React.RefObject<HTMLElement>;
348
362
  isImageUploaded: boolean;
@@ -377,4 +391,11 @@ export interface UseImageAIGenerationReturn {
377
391
  setCurrentReqId: React.Dispatch<React.SetStateAction<string | null>>;
378
392
  limitsInPlugin: boolean;
379
393
  }
394
+ export type MessageType = {
395
+ status?: string;
396
+ images?: unknown[];
397
+ progress?: number;
398
+ data?: unknown;
399
+ [key: string]: unknown;
400
+ };
380
401
  export {};
@@ -0,0 +1,60 @@
1
+ import { FileManagerDataProviders, File, Folder, Config } from '../types';
2
+ export declare class JSONDataProvider implements FileManagerDataProviders {
3
+ private files;
4
+ private folders;
5
+ constructor(config?: Config);
6
+ loadFromJSON: (data: {
7
+ files?: File[];
8
+ folders?: Folder[];
9
+ }) => void;
10
+ loadFromURL: (url: string) => Promise<void>;
11
+ addFiles: (newFiles: File[]) => void;
12
+ addFolders: (newFolders: Folder[]) => void;
13
+ getFile: (fileId: string) => Promise<Blob>;
14
+ getFolders: () => Promise<Folder[]>;
15
+ getFiles: (options?: {
16
+ folderId?: string;
17
+ search?: string;
18
+ sortBy?: "name" | "size" | "date" | "type";
19
+ sortOrder?: "asc" | "desc";
20
+ }) => Promise<File[]>;
21
+ createFolder: (data: {
22
+ name: string;
23
+ parentId?: string | null;
24
+ }) => Promise<Folder>;
25
+ deleteFolder: (folderId: string) => Promise<boolean>;
26
+ uploadFile: (file: {
27
+ name: string;
28
+ size: string;
29
+ type: string;
30
+ folderId?: string | null;
31
+ data: Blob | string;
32
+ thumbnail?: string;
33
+ dimensions?: string;
34
+ aspectRatio?: string;
35
+ extension?: string;
36
+ }) => Promise<File>;
37
+ uploadFileByUrl: (data: {
38
+ url: string;
39
+ folderId?: string | null;
40
+ noFolder?: boolean;
41
+ }) => Promise<File>;
42
+ deleteFile: (fileId: string) => Promise<boolean>;
43
+ renameFile: (fileId: string, newName: string) => Promise<File>;
44
+ moveItem: (options: {
45
+ itemId: string;
46
+ targetFolderId: string;
47
+ isFolder: boolean;
48
+ }) => Promise<boolean>;
49
+ private getFileTypeFromExtension;
50
+ exportToJSON: () => {
51
+ files: File[];
52
+ folders: Folder[];
53
+ };
54
+ clear: () => void;
55
+ getStats: () => {
56
+ totalFiles: number;
57
+ totalFolders: number;
58
+ filesByType: Record<string, number>;
59
+ };
60
+ }
@@ -0,0 +1,3 @@
1
+ import { File } from '../types';
2
+ export declare const sortFiles: (files: File[], sortBy?: "name" | "size" | "date" | "type", sortOrder?: "asc" | "desc") => File[];
3
+ export declare const filterFiles: (files: File[], searchTerm: string) => File[];
File without changes
package/index.html DELETED
@@ -1,141 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="ru">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>File Manager Debug</title>
7
-
8
- <!-- Скрипт для подавления ошибок ResizeObserver -->
9
- <script src="/suppress-resize-observer-errors.js"></script>
10
-
11
- <style>
12
- body {
13
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
14
- line-height: 1.5;
15
- margin: 0;
16
- padding: 0;
17
- background-color: #f5f5f5;
18
- }
19
-
20
- .header {
21
- background-color: #1890ff;
22
- color: white;
23
- padding: 20px;
24
- text-align: center;
25
- margin-bottom: 20px;
26
- }
27
-
28
- .header h1 {
29
- margin: 0;
30
- font-size: 24px;
31
- }
32
-
33
- .container {
34
- max-width: 1200px;
35
- margin: 0 auto;
36
- padding: 0 20px;
37
- }
38
-
39
- .debug-info {
40
- background-color: #fff;
41
- border: 1px solid #ddd;
42
- border-radius: 4px;
43
- padding: 15px;
44
- margin-bottom: 20px;
45
- }
46
-
47
- .debug-info h2 {
48
- margin-top: 0;
49
- color: #1890ff;
50
- }
51
-
52
- .error-container {
53
- background-color: #fff2f0;
54
- border: 1px solid #ffccc7;
55
- border-radius: 4px;
56
- padding: 15px;
57
- margin-bottom: 20px;
58
- display: none;
59
- }
60
-
61
- .error-container h2 {
62
- color: #ff4d4f;
63
- margin-top: 0;
64
- }
65
-
66
- #error-details {
67
- font-family: monospace;
68
- white-space: pre-wrap;
69
- background-color: #fafafa;
70
- padding: 10px;
71
- border-radius: 4px;
72
- border: 1px solid #f0f0f0;
73
- }
74
- </style>
75
- </head>
76
- <body>
77
- <div class="header">
78
- <h1>Отладка и тестирование файлового менеджера</h1>
79
- </div>
80
-
81
- <div class="container">
82
- <div class="debug-info">
83
- <h2>Информация об окружении</h2>
84
- <p>Эта страница предназначена для отладки и тестирования файлового менеджера.</p>
85
- <p>Текущий URL: <span id="current-url"></span></p>
86
- <p>User Agent: <span id="user-agent"></span></p>
87
- <p>Время загрузки: <span id="load-time"></span></p>
88
- </div>
89
-
90
- <div class="error-container" id="error-container">
91
- <h2>Произошла ошибка</h2>
92
- <div id="error-details"></div>
93
- </div>
94
-
95
- <div id="root"></div>
96
- </div>
97
-
98
- <script>
99
-
100
- document.getElementById('current-url').textContent = window.location.href;
101
- document.getElementById('user-agent').textContent = navigator.userAgent;
102
-
103
-
104
- const startTime = new Date();
105
-
106
-
107
- window.onerror = function(message, source, lineno, colno, error) {
108
- const errorContainer = document.getElementById('error-container');
109
- const errorDetails = document.getElementById('error-details');
110
-
111
- errorContainer.style.display = 'block';
112
- errorDetails.textContent = `Сообщение: ${message}\nИсточник: ${source}\nСтрока: ${lineno}, Колонка: ${colno}\n\nСтек вызовов:\n${error && error.stack ? error.stack : 'Недоступно'}`;
113
-
114
- console.error('Перехвачена ошибка:', error);
115
- return false;
116
- };
117
-
118
-
119
- window.addEventListener('load', function() {
120
- const endTime = new Date();
121
- const loadTime = (endTime - startTime) / 1000;
122
- document.getElementById('load-time').textContent = loadTime.toFixed(2) + ' сек';
123
-
124
-
125
- setTimeout(() => {
126
- const script = document.createElement('script');
127
- script.src = '/debug-script.js';
128
- script.onerror = (error) => {
129
- console.error('Ошибка загрузки скрипта отладки:', error);
130
- const errorContainer = document.getElementById('error-container');
131
- const errorDetails = document.getElementById('error-details');
132
-
133
- errorContainer.style.display = 'block';
134
- errorDetails.textContent = `Не удалось загрузить скрипт отладки: ${error}`;
135
- };
136
- document.body.appendChild(script);
137
- }, 500);
138
- });
139
- </script>
140
- </body>
141
- </html>