mirror of
https://github.com/leporello-js/leporello-js
synced 2026-01-14 05:14:28 -08:00
136 lines
3.6 KiB
JavaScript
136 lines
3.6 KiB
JavaScript
|
|
// code is borrowed from
|
||
|
|
// https://googlechrome.github.io/samples/service-worker/post-message/
|
||
|
|
const send_message = (message) => {
|
||
|
|
return new Promise(function(resolve) {
|
||
|
|
const messageChannel = new MessageChannel();
|
||
|
|
messageChannel.port1.onmessage = function(event) {
|
||
|
|
resolve(event.data)
|
||
|
|
};
|
||
|
|
if(navigator.serviceWorker.controller == null) {
|
||
|
|
// Service worker will be available after reload
|
||
|
|
window.location.reload()
|
||
|
|
}
|
||
|
|
navigator.serviceWorker.controller.postMessage(message,
|
||
|
|
[messageChannel.port2]);
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
globalThis.clear_directory_handle = () => {
|
||
|
|
send_message({type: 'SET', data: null})
|
||
|
|
window.location.reload()
|
||
|
|
}
|
||
|
|
|
||
|
|
let dir_handle
|
||
|
|
|
||
|
|
const request_directory_handle = async () => {
|
||
|
|
dir_handle = await showDirectoryPicker()
|
||
|
|
await send_message({type: 'SET', data: dir_handle})
|
||
|
|
return dir_handle
|
||
|
|
}
|
||
|
|
|
||
|
|
export const load_persisted_directory_handle = () => {
|
||
|
|
return navigator.serviceWorker.register('service_worker.js')
|
||
|
|
.then(() => navigator.serviceWorker.ready)
|
||
|
|
.then(() => send_message({type: 'GET'}))
|
||
|
|
.then(async h => {
|
||
|
|
if(h == null || (await h.queryPermission()) != 'granted') {
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
// test if directory handle is valid
|
||
|
|
try {
|
||
|
|
await h.entries().next()
|
||
|
|
} catch(e) {
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
dir_handle = h
|
||
|
|
return dir_handle
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
const file_handle = async (dir_handle, filename, is_directory = false, options) => {
|
||
|
|
if(typeof(filename) == 'string') {
|
||
|
|
filename = filename.split('/')
|
||
|
|
}
|
||
|
|
const [first, ...rest] = filename
|
||
|
|
if(rest.length == 0) {
|
||
|
|
return is_directory
|
||
|
|
? await dir_handle.getDirectoryHandle(first, options)
|
||
|
|
: await dir_handle.getFileHandle(first, options)
|
||
|
|
} else {
|
||
|
|
const nested_dir_handle = await dir_handle.getDirectoryHandle(first)
|
||
|
|
return file_handle(nested_dir_handle, rest, is_directory, options)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export const write_file = async (name, contents) => {
|
||
|
|
const f_hanlde = await file_handle(dir_handle, name)
|
||
|
|
// Create a FileSystemWritableFileStream to write to.
|
||
|
|
const writable = await f_hanlde.createWritable()
|
||
|
|
// Write the contents of the file to the stream.
|
||
|
|
await writable.write(contents)
|
||
|
|
// Close the file and write the contents to disk.
|
||
|
|
await writable.close()
|
||
|
|
}
|
||
|
|
|
||
|
|
// Blacklist hidden dirs and node_modules
|
||
|
|
const is_blacklisted = h => h.name == 'node_modules' || h.name.startsWith('.')
|
||
|
|
|
||
|
|
const read_file = async handle => {
|
||
|
|
const file_data = await handle.getFile()
|
||
|
|
return await file_data.text()
|
||
|
|
}
|
||
|
|
|
||
|
|
const do_load_dir = async (handle, path) => {
|
||
|
|
if(handle.kind == 'directory') {
|
||
|
|
const children = []
|
||
|
|
for await (let [name, h] of handle) {
|
||
|
|
if(!is_blacklisted(h)) {
|
||
|
|
children.push(h)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return {
|
||
|
|
name: handle.name,
|
||
|
|
path,
|
||
|
|
kind: 'directory',
|
||
|
|
children: await Promise.all(
|
||
|
|
children
|
||
|
|
.map(c =>
|
||
|
|
do_load_dir(c, path == null ? c.name : path + '/' + c.name)
|
||
|
|
)
|
||
|
|
.sort((a,b) => a.name > b.name)
|
||
|
|
)
|
||
|
|
}
|
||
|
|
} else if(handle.kind == 'file') {
|
||
|
|
return {
|
||
|
|
name: handle.name,
|
||
|
|
path,
|
||
|
|
kind: 'file',
|
||
|
|
contents: await read_file(handle)
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
throw new Error('unknown kind')
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
export const create_file = (path, is_dir) => {
|
||
|
|
return file_handle(
|
||
|
|
dir_handle,
|
||
|
|
path,
|
||
|
|
is_dir,
|
||
|
|
{create: true}
|
||
|
|
)
|
||
|
|
}
|
||
|
|
|
||
|
|
export const load_dir = async (should_request_access) => {
|
||
|
|
let handle
|
||
|
|
if(should_request_access) {
|
||
|
|
handle = await request_directory_handle()
|
||
|
|
} else {
|
||
|
|
handle = await load_persisted_directory_handle()
|
||
|
|
if(handle == null) {
|
||
|
|
return null
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return do_load_dir(handle, null)
|
||
|
|
}
|