-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathScript.js
More file actions
226 lines (192 loc) · 7.75 KB
/
Script.js
File metadata and controls
226 lines (192 loc) · 7.75 KB
1
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
32
33
34
35
36
37
38
39
40
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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
// Initialize a stack to track navigation history for directory browsing
const historyStack = [];
// Main function to handle directory selection
async function selectDirectory() {
try {
const directoryHandle = await window.showDirectoryPicker();
historyStack.length = 0; // Reset history when selecting a new directory
historyStack.push(directoryHandle);
await displayFolderContents(directoryHandle);
} catch (error) {
console.error('Error selecting directory:', error);
showError('Failed to select directory. Please try again.');
}
}
// Display contents of the selected folder
async function displayFolderContents(folderHandle) {
const fileList = document.getElementById('files-container');
const imageDisplay = document.getElementById('image-display');
if (!fileList || !imageDisplay) {
showError('Required elements not found. Please refresh the page.');
return;
}
clearElement(fileList);
clearElement(imageDisplay);
if (historyStack.length > 1) {
addGoBackOption(fileList);
}
try {
for await (const entry of folderHandle.values()) {
const itemElement = document.createElement('div');
itemElement.className = entry.kind === 'directory' ? 'folder' : 'file';
itemElement.textContent = entry.name;
if (entry.kind === 'directory') {
itemElement.onclick = async () => {
historyStack.push(entry);
await displayFolderContents(entry);
};
} else if (entry.kind === 'file' && entry.name.toLowerCase().endsWith('.zip')) {
itemElement.onclick = () => displayZipContents(entry);
}
fileList.appendChild(itemElement);
}
} catch (error) {
console.error('Error displaying folder contents:', error);
showError('Failed to display folder contents. Please try again.');
}
}
// Helper function to add a "Go Back" option in the file list
function addGoBackOption(parent) {
const goBackElement = document.createElement('div');
goBackElement.className = 'folder';
goBackElement.textContent = '.. (Go Back)';
goBackElement.onclick = () => {
if (historyStack.length > 1) {
historyStack.pop();
displayFolderContents(historyStack[historyStack.length - 1]);
}
};
parent.appendChild(goBackElement);
}
// Utility function to safely clear an element's contents
function clearElement(element) {
if (element) {
element.innerHTML = '';
}
}
// Create or get the loader element
function getLoader() {
let loader = document.getElementById('loader');
if (!loader) {
// If loader doesn't exist, create it
loader = document.createElement('div');
loader.id = 'loader';
loader.style.display = 'none';
loader.setAttribute('role', 'status');
loader.setAttribute('aria-live', 'polite');
loader.textContent = 'Loading...';
const imageDisplay = document.getElementById('image-display');
if (imageDisplay) {
imageDisplay.insertBefore(loader, imageDisplay.firstChild);
}
}
return loader;
}
// Display contents of a ZIP file
async function displayZipContents(fileHandle) {
const loader = getLoader();
if (!loader) {
showError('Unable to initialize loader. Please refresh the page.');
return;
}
loader.style.display = 'block';
try {
const file = await fileHandle.getFile();
const arrayBuffer = await file.arrayBuffer();
const zip = await JSZip.loadAsync(arrayBuffer);
const imageDisplay = document.getElementById('image-display');
if (!imageDisplay) {
throw new Error('Image display element not found');
}
clearElement(imageDisplay);
// Filter and sort image files from the ZIP
const imageFiles = Object.entries(zip.files)
.filter(([relativePath, zipEntry]) =>
!zipEntry.dir && /\.(jpg|jpeg|png|gif)$/i.test(relativePath))
.sort(([pathA], [pathB]) => naturalSort(pathA, pathB));
for (const [relativePath, zipEntry] of imageFiles) {
try {
const blob = await zipEntry.async('blob');
const imageUrl = URL.createObjectURL(blob);
const imageItem = document.createElement('div');
imageItem.className = 'image-item';
const imgElement = document.createElement('img');
imgElement.src = imageUrl;
imgElement.loading = 'lazy'; // Enable lazy loading for better performance
const captionElement = document.createElement('div');
captionElement.className = 'image-caption';
captionElement.textContent = relativePath;
imageItem.appendChild(imgElement);
imageItem.appendChild(captionElement);
imageDisplay.appendChild(imageItem);
// Clean up the object URL after the image loads
imgElement.onload = () => URL.revokeObjectURL(imageUrl);
} catch (error) {
console.error(`Error processing image ${relativePath}:`, error);
// Continue with other images if one fails
}
}
} catch (error) {
console.error('Error displaying ZIP contents:', error);
showError('Failed to display ZIP contents. Please try again.');
} finally {
loader.style.display = 'none';
}
}
// Natural sort function for file names
function naturalSort(a, b) {
const collator = new Intl.Collator(undefined, { numeric: true, sensitivity: 'base' });
return collator.compare(a, b);
}
// Initialize the application when the DOM is fully loaded
document.addEventListener('DOMContentLoaded', () => {
const themeToggle = document.getElementById('theme-toggle');
const body = document.body;
const searchBox = document.getElementById('search-box');
if (themeToggle && body) {
// Set up theme toggle functionality
themeToggle.addEventListener('click', () => {
body.classList.toggle('dark-mode');
const isDarkMode = body.classList.contains('dark-mode');
themeToggle.textContent = isDarkMode ? 'Light Mode' : 'Dark Mode';
localStorage.setItem('darkMode', isDarkMode);
});
// Restore theme preference
if (localStorage.getItem('darkMode') === 'true') {
body.classList.add('dark-mode');
themeToggle.textContent = 'Light Mode';
}
}
if (searchBox) {
// Set up search functionality with debouncing
searchBox.addEventListener('input', debounce((e) => {
const query = e.target.value.toLowerCase();
const items = document.querySelectorAll('#files-container .file, #files-container .folder');
items.forEach(item => {
item.style.display = item.textContent.toLowerCase().includes(query) ? '' : 'none';
});
}, 300));
}
});
// Display error messages to the user
function showError(message) {
const errorDiv = document.getElementById('error-message');
if (errorDiv) {
errorDiv.style.display = 'block';
errorDiv.textContent = message;
// Hide error message after 5 seconds
setTimeout(() => {
errorDiv.style.display = 'none';
}, 5000);
} else {
console.error('Error:', message);
}
}
// Debounce utility function to limit the rate of function calls
function debounce(func, wait) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}