iobroker.staticsfilefolder 0.0.10 → 0.0.11
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/io-package.json +4 -1
- package/package.json +1 -1
- package/www/app.js +114 -10
- package/www/index.html +20 -19
package/io-package.json
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "staticsfilefolder",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.11",
|
|
5
5
|
"news": {
|
|
6
|
+
"0.0.11": {
|
|
7
|
+
"en": "Added multi-language support (English and Azerbaijani) with English as the default."
|
|
8
|
+
},
|
|
6
9
|
"0.0.10": {
|
|
7
10
|
"en": "Updated README.md with detailed instructions for instance configuration settings."
|
|
8
11
|
},
|
package/package.json
CHANGED
package/www/app.js
CHANGED
|
@@ -16,6 +16,7 @@ const btnBack = document.getElementById('btn-back');
|
|
|
16
16
|
const btnForward = document.getElementById('btn-forward');
|
|
17
17
|
const btnHome = document.getElementById('btn-home');
|
|
18
18
|
const btnTheme = document.getElementById('btn-theme');
|
|
19
|
+
const btnLang = document.getElementById('btn-lang');
|
|
19
20
|
const searchBox = document.getElementById('search-box');
|
|
20
21
|
const typeFilter = document.getElementById('type-filter');
|
|
21
22
|
const sortSelect = document.getElementById('sort-select');
|
|
@@ -33,11 +34,105 @@ const modalBtnDownload = document.getElementById('modal-btn-download');
|
|
|
33
34
|
let currentOpenItem = null;
|
|
34
35
|
let currentFilesList = [];
|
|
35
36
|
|
|
37
|
+
// Localization Settings
|
|
38
|
+
const translations = {
|
|
39
|
+
en: {
|
|
40
|
+
back: "← Back",
|
|
41
|
+
forward: "Forward →",
|
|
42
|
+
home: "Home",
|
|
43
|
+
searchPlaceholder: "Search...",
|
|
44
|
+
allTypes: "All Types",
|
|
45
|
+
sortAz: "Sort A-Z",
|
|
46
|
+
sortZa: "Sort Z-A",
|
|
47
|
+
sortNewest: "Newest First",
|
|
48
|
+
sortOldest: "Oldest First",
|
|
49
|
+
title: "Omni Reports",
|
|
50
|
+
loadingPdf: "Loading PDF...",
|
|
51
|
+
loadingExcel: "Loading Excel...",
|
|
52
|
+
loadingWord: "Loading Word...",
|
|
53
|
+
emptyFolder: "This folder is empty.",
|
|
54
|
+
root: "Root",
|
|
55
|
+
themeTooltip: "Toggle Dark/Light Mode",
|
|
56
|
+
langTooltip: "Change Language / Dili Dəyiş",
|
|
57
|
+
modalTitle: "File Viewer",
|
|
58
|
+
modalBack: "← Back",
|
|
59
|
+
modalForward: "Next →",
|
|
60
|
+
modalPrint: "🖨️ Print / PDF",
|
|
61
|
+
modalDownload: "📥 Download",
|
|
62
|
+
todayBadge: "Today",
|
|
63
|
+
errorLoading: "An error occurred: "
|
|
64
|
+
},
|
|
65
|
+
az: {
|
|
66
|
+
back: "← Geri",
|
|
67
|
+
forward: "İrəli →",
|
|
68
|
+
home: "Ev (Home)",
|
|
69
|
+
searchPlaceholder: "Axtarış...",
|
|
70
|
+
allTypes: "Bütün Tiplər",
|
|
71
|
+
sortAz: "A-Z Sırala",
|
|
72
|
+
sortZa: "Z-A Sırala",
|
|
73
|
+
sortNewest: "Ən Yeni",
|
|
74
|
+
sortOldest: "Ən Köhnə",
|
|
75
|
+
title: "Omni Hesabatlar",
|
|
76
|
+
loadingPdf: "PDF Yüklənir...",
|
|
77
|
+
loadingExcel: "Excel Yüklənir...",
|
|
78
|
+
loadingWord: "Word Yüklənir...",
|
|
79
|
+
emptyFolder: "Bu qovluq boşdur.",
|
|
80
|
+
root: "Kök",
|
|
81
|
+
themeTooltip: "Gecə/Gündüz Rejimi",
|
|
82
|
+
langTooltip: "Change Language / Dili Dəyiş",
|
|
83
|
+
modalTitle: "Fayl Baxışı",
|
|
84
|
+
modalBack: "← Geri",
|
|
85
|
+
modalForward: "İrəli →",
|
|
86
|
+
modalPrint: "🖨️ Çap / PDF",
|
|
87
|
+
modalDownload: "📥 Yüklə",
|
|
88
|
+
todayBadge: "Bu gün",
|
|
89
|
+
errorLoading: "Xəta baş verdi: "
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
let currentLang = 'en'; // default English
|
|
94
|
+
|
|
36
95
|
// Setup PDF.js worker
|
|
37
96
|
if (window.pdfjsLib) {
|
|
38
97
|
window.pdfjsLib.GlobalWorkerOptions.workerSrc = 'libs/pdfjs/pdf.worker.min.mjs';
|
|
39
98
|
}
|
|
40
99
|
|
|
100
|
+
// Language Initialization
|
|
101
|
+
function initLang() {
|
|
102
|
+
currentLang = localStorage.getItem('staticsfilefolder_lang') || 'en';
|
|
103
|
+
applyTranslations();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function toggleLang() {
|
|
107
|
+
currentLang = currentLang === 'en' ? 'az' : 'en';
|
|
108
|
+
localStorage.setItem('staticsfilefolder_lang', currentLang);
|
|
109
|
+
applyTranslations();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function applyTranslations() {
|
|
113
|
+
const t = translations[currentLang];
|
|
114
|
+
|
|
115
|
+
// Update elements with data-i18n attribute
|
|
116
|
+
document.querySelectorAll('[data-i18n]').forEach(el => {
|
|
117
|
+
const key = el.getAttribute('data-i18n');
|
|
118
|
+
if (t[key]) {
|
|
119
|
+
if (el.tagName === 'INPUT') {
|
|
120
|
+
el.placeholder = t[key];
|
|
121
|
+
} else {
|
|
122
|
+
el.textContent = t[key];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Update search placeholder and other specific inputs
|
|
128
|
+
searchBox.placeholder = t.searchPlaceholder;
|
|
129
|
+
btnLang.textContent = currentLang === 'en' ? '🌐 AZ' : '🌐 EN';
|
|
130
|
+
|
|
131
|
+
// Refresh UI to update dynamic content like dates/breadcrumbs
|
|
132
|
+
updateBreadcrumb();
|
|
133
|
+
renderItems();
|
|
134
|
+
}
|
|
135
|
+
|
|
41
136
|
// Theme Initialization
|
|
42
137
|
function initTheme() {
|
|
43
138
|
const savedTheme = localStorage.getItem('staticsfilefolder_theme') || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
|
@@ -56,6 +151,7 @@ function toggleTheme() {
|
|
|
56
151
|
// Initialize
|
|
57
152
|
document.addEventListener('DOMContentLoaded', () => {
|
|
58
153
|
initTheme();
|
|
154
|
+
initLang();
|
|
59
155
|
loadPath('');
|
|
60
156
|
|
|
61
157
|
// Event Listeners
|
|
@@ -63,6 +159,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
|
63
159
|
btnForward.addEventListener('click', goForward);
|
|
64
160
|
btnHome.addEventListener('click', () => navigateTo(''));
|
|
65
161
|
btnTheme.addEventListener('click', toggleTheme);
|
|
162
|
+
btnLang.addEventListener('click', toggleLang);
|
|
66
163
|
|
|
67
164
|
searchBox.addEventListener('input', renderItems);
|
|
68
165
|
typeFilter.addEventListener('change', renderItems);
|
|
@@ -132,13 +229,14 @@ function updateNavButtons() {
|
|
|
132
229
|
}
|
|
133
230
|
|
|
134
231
|
function updateBreadcrumb() {
|
|
232
|
+
const rootName = translations[currentLang]?.root || 'Root';
|
|
135
233
|
if (!currentPath) {
|
|
136
|
-
breadcrumbEl.innerHTML =
|
|
234
|
+
breadcrumbEl.innerHTML = `<span><i class="icon">🏠</i> ${rootName}</span>`;
|
|
137
235
|
return;
|
|
138
236
|
}
|
|
139
237
|
|
|
140
238
|
const parts = currentPath.split('/');
|
|
141
|
-
let html =
|
|
239
|
+
let html = `<span data-path="">🏠 ${rootName}</span>`;
|
|
142
240
|
let buildPath = '';
|
|
143
241
|
|
|
144
242
|
parts.forEach((part, index) => {
|
|
@@ -216,7 +314,8 @@ function renderItems() {
|
|
|
216
314
|
const isToday = itemDate.setHours(0,0,0,0) === today;
|
|
217
315
|
if (isToday) div.classList.add('is-today');
|
|
218
316
|
|
|
219
|
-
const
|
|
317
|
+
const locale = currentLang === 'en' ? 'en-US' : 'az-AZ';
|
|
318
|
+
const dateStr = new Date(item.mtime).toLocaleString(locale);
|
|
220
319
|
|
|
221
320
|
let sizeStr = '';
|
|
222
321
|
if (!item.isDirectory) {
|
|
@@ -224,11 +323,13 @@ function renderItems() {
|
|
|
224
323
|
else sizeStr = (item.size / 1024).toFixed(2) + ' KB';
|
|
225
324
|
}
|
|
226
325
|
|
|
326
|
+
const todayText = translations[currentLang]?.todayBadge || 'Today';
|
|
327
|
+
|
|
227
328
|
div.innerHTML = `
|
|
228
329
|
<div class="file-icon">${icon}</div>
|
|
229
330
|
<div class="file-name" title="${item.name}">${item.name}</div>
|
|
230
331
|
<div class="file-meta">${dateStr}<br>${sizeStr}</div>
|
|
231
|
-
${isToday ?
|
|
332
|
+
${isToday ? `<div class="today-badge">${todayText}</div>` : ''}
|
|
232
333
|
`;
|
|
233
334
|
|
|
234
335
|
div.addEventListener('click', () => handleItemClick(item));
|
|
@@ -352,7 +453,7 @@ function downloadCurrentFile() {
|
|
|
352
453
|
|
|
353
454
|
async function openPdf(url) {
|
|
354
455
|
viewerModal.style.display = 'block';
|
|
355
|
-
viewerBody.innerHTML = '
|
|
456
|
+
viewerBody.innerHTML = `<h2>${translations[currentLang]?.loadingPdf || 'Loading PDF...'}</h2>`;
|
|
356
457
|
|
|
357
458
|
try {
|
|
358
459
|
const loadingTask = window.pdfjsLib.getDocument({ url: url });
|
|
@@ -379,13 +480,14 @@ async function openPdf(url) {
|
|
|
379
480
|
await page.render(renderContext).promise;
|
|
380
481
|
}
|
|
381
482
|
} catch (e) {
|
|
382
|
-
|
|
483
|
+
const errorText = translations[currentLang]?.errorLoading || 'An error occurred: ';
|
|
484
|
+
viewerBody.innerHTML = `<h2 style="color:red">${errorText}${e.message}</h2>`;
|
|
383
485
|
}
|
|
384
486
|
}
|
|
385
487
|
|
|
386
488
|
async function openExcel(url) {
|
|
387
489
|
viewerModal.style.display = 'block';
|
|
388
|
-
viewerBody.innerHTML = '
|
|
490
|
+
viewerBody.innerHTML = `<h2>${translations[currentLang]?.loadingExcel || 'Loading Excel...'}</h2>`;
|
|
389
491
|
|
|
390
492
|
try {
|
|
391
493
|
const res = await fetch(url);
|
|
@@ -407,13 +509,14 @@ async function openExcel(url) {
|
|
|
407
509
|
if(table) table.className = 'sheetjs-table';
|
|
408
510
|
|
|
409
511
|
} catch (e) {
|
|
410
|
-
|
|
512
|
+
const errorText = translations[currentLang]?.errorLoading || 'An error occurred: ';
|
|
513
|
+
viewerBody.innerHTML = `<h2 style="color:red">${errorText}${e.message}</h2>`;
|
|
411
514
|
}
|
|
412
515
|
}
|
|
413
516
|
|
|
414
517
|
async function openWord(url) {
|
|
415
518
|
viewerModal.style.display = 'block';
|
|
416
|
-
viewerBody.innerHTML =
|
|
519
|
+
viewerBody.innerHTML = `<h2>${translations[currentLang]?.loadingWord || 'Loading Word...'}</h2>`;
|
|
417
520
|
|
|
418
521
|
try {
|
|
419
522
|
const res = await fetch(url);
|
|
@@ -425,6 +528,7 @@ async function openWord(url) {
|
|
|
425
528
|
${result.value}
|
|
426
529
|
</div>`;
|
|
427
530
|
} catch (e) {
|
|
428
|
-
|
|
531
|
+
const errorText = translations[currentLang]?.errorLoading || 'An error occurred: ';
|
|
532
|
+
viewerBody.innerHTML = `<h2 style="color:red">${errorText}${e.message}</h2>`;
|
|
429
533
|
}
|
|
430
534
|
}
|
package/www/index.html
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html lang="
|
|
2
|
+
<html lang="en">
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
@@ -16,31 +16,32 @@
|
|
|
16
16
|
<div class="app-container">
|
|
17
17
|
<!-- Header & Toolbar -->
|
|
18
18
|
<header class="app-header">
|
|
19
|
-
<div class="header-title">Omni Reports</div>
|
|
19
|
+
<div class="header-title" id="app-title" data-i18n="title">Omni Reports</div>
|
|
20
20
|
|
|
21
21
|
<div class="toolbar">
|
|
22
|
-
<button id="btn-back" class="nav-btn" disabled>←
|
|
23
|
-
<button id="btn-forward" class="nav-btn" disabled
|
|
24
|
-
<button id="btn-home" class="nav-btn">
|
|
22
|
+
<button id="btn-back" class="nav-btn" data-i18n="back" disabled>← Back</button>
|
|
23
|
+
<button id="btn-forward" class="nav-btn" data-i18n="forward" disabled>Forward →</button>
|
|
24
|
+
<button id="btn-home" class="nav-btn" data-i18n="home">Home</button>
|
|
25
25
|
|
|
26
26
|
<div class="breadcrumb" id="breadcrumb">
|
|
27
27
|
<!-- Path will be injected here -->
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
30
|
<div class="filters">
|
|
31
|
-
<button id="btn-
|
|
32
|
-
<
|
|
31
|
+
<button id="btn-lang" class="nav-btn" title="Change Language / Dili Dəyiş">🌐 AZ</button>
|
|
32
|
+
<button id="btn-theme" class="nav-btn" title="Toggle Dark/Light Mode">🌙</button>
|
|
33
|
+
<input type="text" id="search-box" placeholder="Search...">
|
|
33
34
|
<select id="type-filter">
|
|
34
|
-
<option value="all">
|
|
35
|
+
<option value="all" data-i18n="allTypes">All Types</option>
|
|
35
36
|
<option value=".pdf">PDF</option>
|
|
36
37
|
<option value=".xlsx">Excel</option>
|
|
37
38
|
<option value=".docx">Word</option>
|
|
38
39
|
</select>
|
|
39
40
|
<select id="sort-select">
|
|
40
|
-
<option value="name-asc">A-Z
|
|
41
|
-
<option value="name-desc">Z-A
|
|
42
|
-
<option value="date-desc"
|
|
43
|
-
<option value="date-asc"
|
|
41
|
+
<option value="name-asc" data-i18n="sortAz">Sort A-Z</option>
|
|
42
|
+
<option value="name-desc" data-i18n="sortZa">Sort Z-A</option>
|
|
43
|
+
<option value="date-desc" data-i18n="sortNewest">Newest First</option>
|
|
44
|
+
<option value="date-asc" data-i18n="sortOldest">Oldest First</option>
|
|
44
45
|
</select>
|
|
45
46
|
</div>
|
|
46
47
|
</div>
|
|
@@ -51,8 +52,8 @@
|
|
|
51
52
|
<div id="file-list" class="file-list">
|
|
52
53
|
<!-- File items will be injected here -->
|
|
53
54
|
</div>
|
|
54
|
-
<div id="empty-state" class="empty-state" style="display: none;">
|
|
55
|
-
|
|
55
|
+
<div id="empty-state" class="empty-state" data-i18n="emptyFolder" style="display: none;">
|
|
56
|
+
This folder is empty.
|
|
56
57
|
</div>
|
|
57
58
|
</main>
|
|
58
59
|
</div>
|
|
@@ -61,12 +62,12 @@
|
|
|
61
62
|
<div id="viewer-modal" class="modal">
|
|
62
63
|
<div class="modal-content">
|
|
63
64
|
<header class="modal-header">
|
|
64
|
-
<div class="modal-title" id="modal-title">
|
|
65
|
+
<div class="modal-title" id="modal-title" data-i18n="modalTitle">File Viewer</div>
|
|
65
66
|
<div class="modal-toolbar">
|
|
66
|
-
<button id="modal-btn-prev" class="nav-btn" title="
|
|
67
|
-
<button id="modal-btn-next" class="nav-btn" title="
|
|
68
|
-
<button id="modal-btn-print" class="nav-btn" title="
|
|
69
|
-
<button id="modal-btn-download" class="nav-btn" title="
|
|
67
|
+
<button id="modal-btn-prev" class="nav-btn" data-i18n="modalBack" title="Previous">← Back</button>
|
|
68
|
+
<button id="modal-btn-next" class="nav-btn" data-i18n="modalForward" title="Next">Next →</button>
|
|
69
|
+
<button id="modal-btn-print" class="nav-btn" data-i18n="modalPrint" title="Print / Save as PDF">🖨️ Print / PDF</button>
|
|
70
|
+
<button id="modal-btn-download" class="nav-btn" data-i18n="modalDownload" title="Download File">📥 Download</button>
|
|
70
71
|
<span id="close-modal" class="close-button">×</span>
|
|
71
72
|
</div>
|
|
72
73
|
</header>
|