diff --git a/www/css/app.css b/www/css/app.css index ed742f368..484972255 100644 --- a/www/css/app.css +++ b/www/css/app.css @@ -98,7 +98,6 @@ width: 100%; font-size: large; height: 2em; - } /* Custom file input */ diff --git a/www/js/app.js b/www/js/app.js index b19ad4295..2504879b2 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -1261,8 +1261,8 @@ function displayFileSelect () { const isFileSystemAPISupported = typeof window.showOpenFilePicker === 'function' const isWebkitSupported = 'webkitdirectory' in document.createElement('input') - console.log('[DEBUG]: File system api supported', isFileSystemAPISupported); - console.log('[DEBUG]: Webkit supported', isWebkitSupported); + console.debug('[DEBUG]: File system api supported', isFileSystemAPISupported); + console.debug('[DEBUG]: Webkit supported', isWebkitSupported); document.getElementById('openLocalFiles').style.display = 'block'; if (isFileSystemAPISupported || isWebkitSupported) { @@ -1287,13 +1287,11 @@ function displayFileSelect () { document.getElementById('zimSelectDropdown').addEventListener('change', async function (e) { // handle zim selection from dropdown if multiple files are loaded via webkitdirectory or filesystem api - console.log(e.target.value); if (isFileSystemAPISupported) { const files = await fileSystem.getSelectedZimFromCache(e.target.value) setLocalArchiveFromFileList(files); } else { const files = fileSystem.getSelectedZimFromWebkitList(webKitFileList, e.target.value) - console.log(files); setLocalArchiveFromFileList(files); } }); @@ -1302,7 +1300,7 @@ function displayFileSelect () { // Handles Folder selection when showDirectoryPicker is supported document.getElementById('folderSelect').addEventListener('click', async function (e) { e.preventDefault(); - await fileSystem.selectDirectoryFromPicker() + await fileSystem.selectDirectoryFromPickerViaFileSystemApi() }) } if (isWebkitSupported && !isFileSystemAPISupported) { @@ -1315,17 +1313,17 @@ function displayFileSelect () { } webKitFileList = e.target.files await fileSystem.updateZimDropdownOptions({ fileOrDirHandle: null, files: filenames }, '') - // setLocalArchiveFromFileList(e.target.files); }) } - // This handles use of the file picker if (isFileSystemAPISupported) { + // Handles File selection when showOpenFilePicker is supported and uses the filesystem api document.getElementById('archiveFiles').addEventListener('click', async function (e) { e.preventDefault(); - const files = await fileSystem.selectFileFromPicker(e) + const files = await fileSystem.selectFileFromPickerViaFileSystemApi(e) setLocalArchiveFromFileList(files); }); } else { + // Fallbacks to simple file input with multi file selection document.getElementById('archiveFiles').addEventListener('change', async function (e) { if (isWebkitSupported || isFileSystemAPISupported) { const activeFilename = e.target.files[0].name @@ -1368,8 +1366,11 @@ async function handleFileDrop (packet) { const isFSAPIsupported = typeof window.showOpenFilePicker === 'function' const isWebkitSupported = 'webkitdirectory' in document.createElement('input') + // value will be set to true if a folder is dropped then there will be no need to + // call the `setLocalArchiveFromFileList` let loadZim = false; - if (isFSAPIsupported) loadZim = await fileSystem.handleFolderDropViaFSAPI(packet) + + if (isFSAPIsupported) loadZim = await fileSystem.handleFolderDropViaFileSystemAPI(packet) if (isWebkitSupported) { const ret = await fileSystem.handleFolderDropViaWebkit(packet) loadZim = ret.loadZim diff --git a/www/js/lib/fileSystem.js b/www/js/lib/fileSystem.js index 1ae30dadb..1c64b7bcf 100644 --- a/www/js/lib/fileSystem.js +++ b/www/js/lib/fileSystem.js @@ -1,3 +1,5 @@ +// refer to this article for easy explanation of File System API https://developer.chrome.com/articles/file-system-access/ + /** * @typedef {Object} FileSystemHandlers * @property {Array} files All the File names to be shown in the dropdown @@ -7,7 +9,8 @@ import cache from './cache.js'; /** - * @param {FileSystemHandlers} fileSystemHandler + * @param {FileSystemHandlers} fileSystemHandler The FileSystemHandlers object containing filenames and File/Directory handle + * @param {string} selectedFile The name of the file to be selected in the dropdown */ async function updateZimDropdownOptions (fileSystemHandler, selectedFile) { const select = document.getElementById('zimSelectDropdown') @@ -20,7 +23,10 @@ async function updateZimDropdownOptions (fileSystemHandler, selectedFile) { document.getElementById('zimSelectDropdown').value = selectedFile } -async function selectDirectoryFromPicker () { +/** + * Opens the File System API to select a directory + */ +async function selectDirectoryFromPickerViaFileSystemApi () { const handle = await window.showDirectoryPicker(); const fileNames = [] for await (const entry of handle.values()) { @@ -38,7 +44,11 @@ async function selectDirectoryFromPicker () { }); } -async function selectFileFromPicker () { +/** + * Opens the File System API to select a file + * @returns {Promise>} The selected file from picker + */ +async function selectFileFromPickerViaFileSystemApi () { const fileHandles = await window.showOpenFilePicker({ multiple: false }) const [selectedFile] = fileHandles const file = await selectedFile.getFile(); @@ -55,10 +65,14 @@ async function selectFileFromPicker () { return [file]; } +/** + * Gets the selected zim file from the IndexedDB + * @param {string} selectedFilename The name of the file to get back from DB + * @returns {Promise>} The selected File Object from cache + */ function getSelectedZimFromCache (selectedFilename) { - return new Promise((resolve, reject) => { + return new Promise((resolve, _reject) => { cache.idxDB('zimFiles', async function (FSHandler) { - // const selectedFile = FSHandler.fileOrDirHandle if (await FSHandler.fileOrDirHandle.queryPermission() !== 'granted') await FSHandler.fileOrDirHandle.requestPermission() if (FSHandler.fileOrDirHandle.kind === 'directory') { @@ -70,8 +84,6 @@ function getSelectedZimFromCache (selectedFilename) { files.push(await entry.getFile()) } } - // files = await (await FSHandler.fileOrDirHandle.getFileHandle(selectedFilename)).getFile() - console.log(files); resolve(files) } else { const file = await FSHandler.fileOrDirHandle.getFile(); @@ -81,6 +93,16 @@ function getSelectedZimFromCache (selectedFilename) { }) } +/** + * @typedef {Object.} WebkitFileList + */ + +/** + * Gets the selected zim file from the WebkitFileList + * @param {WebkitFileList} webKitFileList The WebkitFileList to get the selected file from + * @param {string} filename The name of the file to get back from webkitFileList + * @returns {Array} The selected Files Object from webkitFileList + */ function getSelectedZimFromWebkitList (webKitFileList, filename) { const filenameWithoutExtension = filename.replace(/\.zim\w\w$/i, '') @@ -101,19 +123,22 @@ function loadPreviousZimFile () { if (typeof window.showOpenFilePicker === 'function') { cache.idxDB('zimFiles', async function (FSHandler) { if (!FSHandler) return console.info('There is no previous zim file in DB') - console.log('Loading this handler from old time', FSHandler); updateZimDropdownOptions(FSHandler, '') - // refer to this article for easy explanation https://developer.chrome.com/articles/file-system-access/ }) } } -async function handleFolderDropViaFSAPI (packet) { +/** + * Handles the folder drop event via File System API + * @param {DragEvent} packet The DragEvent packet + * @returns {Promise} Whether the dropped item is a file or directory + */ +async function handleFolderDropViaFileSystemAPI (packet) { const isFSAPIsupported = typeof window.showOpenFilePicker === 'function' if (!isFSAPIsupported) return true // Only runs when browser support File System API - const fileInfo = await packet.dataTransfer.items[0] + const fileInfo = packet.dataTransfer.items[0] const fileOrDirHandle = await fileInfo.getAsFileSystemHandle(); console.log(fileOrDirHandle, fileInfo); if (fileOrDirHandle.kind === 'file') { @@ -128,9 +153,7 @@ async function handleFolderDropViaFSAPI (packet) { }); return true } - // will be later on used if (fileOrDirHandle.kind === 'directory') { - // const dirHandle = fileInfo.getAsFileSystemHandle(); const fileNames = [] for await (const entry of fileOrDirHandle.values()) { fileNames.push(entry.name) @@ -148,19 +171,20 @@ async function handleFolderDropViaFSAPI (packet) { } } +/** + * Handles the folder drop event via WebkitGetAsEntry + * @param {DragEvent} event The DragEvent packet + * @returns {Promise<{loadZim: boolean, files: Array} | void>} Whether the dropped item is a file or directory and FileList + */ async function handleFolderDropViaWebkit (event) { var dt = event.dataTransfer; var entry = dt.items[0].webkitGetAsEntry(); if (entry.isFile) { - // do whatever you want - return { loadZim: true, files: [entry.file] } } else if (entry.isDirectory) { - // do whatever you want var reader = entry.createReader(); const files = await getFilesFromReader(reader); - console.log('[DEBUG] After files', files); const fileNames = [] files.forEach(file => fileNames.push(file.name)); await updateZimDropdownOptions({ files: fileNames }, '') @@ -168,9 +192,14 @@ async function handleFolderDropViaWebkit (event) { } } +/** + * Gets the files from the FileSystemReader + * @param {FileSystemDirectoryReader} reader The FileSystemReader to get files from + * @returns {Promise>} The files from the reader + */ async function getFilesFromReader (reader) { const files = [] - const promise = new Promise(function (resolve, reject) { + const promise = new Promise(function (resolve, _reject) { reader.readEntries(function (entries) { resolve(entries) }) @@ -180,9 +209,8 @@ async function getFilesFromReader (reader) { for (let index = 0; index < entries.length; index++) { const fileOrDir = entries[index]; if (fileOrDir.isFile) { - const filePromise = await new Promise(function (resolve, reject) { + const filePromise = await new Promise(function (resolve, _reject) { fileOrDir.file(function (file) { - // console.log(file); resolve(file) }) }); @@ -194,11 +222,11 @@ async function getFilesFromReader (reader) { export default { updateZimDropdownOptions, - selectDirectoryFromPicker, - selectFileFromPicker, + selectDirectoryFromPickerViaFileSystemApi, + selectFileFromPickerViaFileSystemApi, getSelectedZimFromCache, loadPreviousZimFile, handleFolderDropViaWebkit, - handleFolderDropViaFSAPI, + handleFolderDropViaFileSystemAPI, getSelectedZimFromWebkitList }