diff --git a/src/filehandle/FileLinkedList.ts b/src/filehandle/FileLinkedList.ts index 75318bf..b6066e3 100644 --- a/src/filehandle/FileLinkedList.ts +++ b/src/filehandle/FileLinkedList.ts @@ -50,13 +50,22 @@ class FileLinkedList { } } - unlink(handle: DH) { + async unlink(handle: DH) { const { next } = this.current; - if (next && next.value === handle) { - this.current.next = null; + if (!next) return false; - this.event.emit(UPDATE_KEY, this.current.value); + try { + const isSame = await next.value.isSameEntry(handle); + + if (isSame) { + this.current.next = null; + this.event.emit(UPDATE_KEY, this.current.value); + } + + return isSame; + } catch (err) { + return false; } } diff --git a/src/filehandle/WebdavFile.ts b/src/filehandle/WebdavFile.ts index 7fa819d..31c69b5 100644 --- a/src/filehandle/WebdavFile.ts +++ b/src/filehandle/WebdavFile.ts @@ -1,5 +1,6 @@ import { createElement } from 'react'; +import { isEqual } from 'lodash-es'; import type { FileStat, WebDAVClient } from 'webdav'; import { AuthType, createClient } from 'webdav'; @@ -13,16 +14,23 @@ import { FileType } from './utils/fileManager'; function createWebdavFileSystemHandle( file: FileStat, webdav: WebDAVClient, - parentPath: string + parentPath: string, + webdavInfo: WebdavInfo ) { if (file.type == 'directory') { return new WebdavFileSystemDirectoryHandle( webdav, parentPath + '/', - file.basename + file.basename, + webdavInfo ); } else { - return new WebdavFileSystemFileHandle(webdav, parentPath, file.basename); + return new WebdavFileSystemFileHandle( + webdav, + parentPath, + file.basename, + webdavInfo + ); } } @@ -77,37 +85,60 @@ class WebdavFileSystemWritableFileStream } } -class WebdavFileSystemFileHandle implements FileSystemFileHandle { - readonly kind = 'file'; +class WebdavFileSystemHandle implements FileSystemHandle { + kind: FileSystemHandleKind; + name: string; - private webdav: WebDAVClient; + private _fullPath: string; - private fullPath: string; + private _webdav: WebDAVClient; - private _name: string; + private _webdavInfo: WebdavInfo; - private file: File | null = null; + constructor( + kind: FileSystemHandleKind, + name: string, + fullPath: string, + webdavClient: WebDAVClient, + webdavInfo: WebdavInfo + ) { + this.kind = kind; + this.name = name; - constructor(webdav: WebDAVClient, fullPath: string, name: string) { - this.webdav = webdav; + this._fullPath = fullPath; + this._webdav = webdavClient; - this._name = name; + this._webdavInfo = webdavInfo; + } - this.fullPath = fullPath; + get fullPath() { + return this._fullPath; } - get name() { - return this._name; + get webdav() { + return this._webdav; } - createSyncAccessHandle(): Promise { - throw new Error('Method not implemented.'); + get webdavInfo() { + return this._webdavInfo; } - isSameEntry(other: FileSystemHandle): Promise; - isSameEntry(arg: FileSystemHandle): boolean; - isSameEntry(): boolean | Promise { - throw new Error('Method not implemented.'); + isSameEntry(other: WebdavFileSystemHandle): Promise; + isSameEntry(arg: WebdavFileSystemHandle): boolean; + isSameEntry(handle: WebdavFileSystemHandle): boolean | Promise { + try { + if ( + handle instanceof WebdavFileSystemHandle && + isEqual(this.webdavInfo, handle.webdavInfo) && + this._fullPath === handle._fullPath + ) { + return Promise.resolve(true); + } + } catch (err) { + return Promise.resolve(false); + } + + return Promise.resolve(false); } queryPermission(): Promise { @@ -121,6 +152,28 @@ class WebdavFileSystemFileHandle implements FileSystemFileHandle { remove(): Promise { throw new Error('Method not implemented.'); } +} + +class WebdavFileSystemFileHandle + extends WebdavFileSystemHandle + implements FileSystemFileHandle +{ + readonly kind = 'file'; + + private file: File | null = null; + + constructor( + webdav: WebDAVClient, + fullPath: string, + name: string, + webdavInfo: WebdavInfo + ) { + super('file', name, fullPath, webdav, webdavInfo); + } + + createSyncAccessHandle(): Promise { + throw new Error('Method not implemented.'); + } async getFile() { if (this.file) { @@ -131,7 +184,7 @@ class WebdavFileSystemFileHandle implements FileSystemFileHandle { format: 'binary' })) as ArrayBuffer; - this.file = new File([data], this._name); + this.file = new File([data], this.name); return this.file; } @@ -146,29 +199,24 @@ class WebdavFileSystemFileHandle implements FileSystemFileHandle { return new WebdavFileSystemWritableFileStream( webdav, fullPath, - (buffer) => (this.file = new File([buffer], this._name)) + (buffer) => (this.file = new File([buffer], this.name)) ); } } -class WebdavFileSystemDirectoryHandle implements FileSystemDirectoryHandle { +class WebdavFileSystemDirectoryHandle + extends WebdavFileSystemHandle + implements FileSystemDirectoryHandle +{ readonly kind = 'directory'; - private webdav: WebDAVClient; - - private fullPath: string; - - private _name: string; - - constructor(webdav: WebDAVClient, fullPath: string, name: string) { - this.webdav = webdav; - - this._name = name; - this.fullPath = fullPath; - } - - get name() { - return this._name; + constructor( + webdav: WebDAVClient, + fullPath: string, + name: string, + webdavInfo: WebdavInfo + ) { + super('directory', name, fullPath, webdav, webdavInfo); } resolve(possibleDescendant: FileSystemHandle): Promise; @@ -187,30 +235,12 @@ class WebdavFileSystemDirectoryHandle implements FileSystemDirectoryHandle { throw new Error('Method not implemented.'); } - isSameEntry(other: FileSystemHandle): Promise; - isSameEntry(arg: FileSystemHandle): boolean; - isSameEntry(): boolean | Promise { - throw new Error('Method not implemented.'); - } - - queryPermission(): Promise { - throw new Error('Method not implemented.'); - } - - requestPermission(): Promise { - throw new Error('Method not implemented.'); - } - - remove(): Promise { - throw new Error('Method not implemented.'); - } - entries(): AsyncIterableIterator< [string, WebdavFileSystemDirectoryHandle | WebdavFileSystemFileHandle] > { let i = 0; - const { webdav, fullPath } = this; + const { webdav, fullPath, webdavInfo } = this; const p = webdav.getDirectoryContents(fullPath, { includeSelf: false @@ -232,7 +262,12 @@ class WebdavFileSystemDirectoryHandle implements FileSystemDirectoryHandle { return { value: [ curr.basename, - createWebdavFileSystemHandle(curr, webdav, fullPath + curr.basename) + createWebdavFileSystemHandle( + curr, + webdav, + fullPath + curr.basename, + webdavInfo + ) ], done: false }; @@ -267,7 +302,8 @@ class WebdavFileSystemDirectoryHandle implements FileSystemDirectoryHandle { return new WebdavFileSystemDirectoryHandle( this.webdav, subFullPath + '/', - name + name, + this.webdavInfo ); } @@ -293,7 +329,12 @@ class WebdavFileSystemDirectoryHandle implements FileSystemDirectoryHandle { } } - return new WebdavFileSystemFileHandle(this.webdav, subFullPath, name); + return new WebdavFileSystemFileHandle( + this.webdav, + subFullPath, + name, + this.webdavInfo + ); } async removeEntry(name: string): Promise { @@ -321,19 +362,20 @@ class WebdavFile { remote = true; - constructor(webdav: WebdavInfo) { - this.name = webdav.name; + constructor(webdavInfo: WebdavInfo) { + this.name = webdavInfo.name; - this.webdav = createClient(webdav.url, { + this.webdav = createClient(webdavInfo.url, { authType: AuthType.Auto, - username: webdav.username, - password: webdav.password + username: webdavInfo.username, + password: webdavInfo.password }); this.handle = new WebdavFileSystemDirectoryHandle( this.webdav, '/', - this.name + this.name, + webdavInfo ); } } diff --git a/src/filehandle/components/FileContent.tsx b/src/filehandle/components/FileContent.tsx index 2d27552..72483fe 100644 --- a/src/filehandle/components/FileContent.tsx +++ b/src/filehandle/components/FileContent.tsx @@ -97,7 +97,7 @@ function MountWebdavModal(props: { open: boolean; close(): void }) { name="username" rules={[{ required: true, message: 'Please input your username!' }]} > - + @@ -105,7 +105,7 @@ function MountWebdavModal(props: { open: boolean; close(): void }) { name="password" rules={[{ required: true, message: 'Please input your password!' }]} > - + @@ -249,19 +249,25 @@ const FileContent: React.FC = (props) => { async onOk() { try { let _webdavs = webdavs.slice(0); + _selection.map((file) => { if (file.remote) { - _webdavs = _webdavs.filter((webdav) => webdav.name !== file.name); + _webdavs = _webdavs.filter((webdav) => { + if ( + webdav.name === file.name && + file.handle.kind === 'directory' + ) { + fileLinked.unlink(file.handle); + } + + return webdav.name !== file.name; + }); } }); + setWebdavs(_webdavs); await Promise.all(names.map((name) => remove(name))); - - _selection.map( - (file) => - file.handle.kind === 'directory' && fileLinked.unlink(file.handle) - ); } catch (err) { error((err as Error).message); } diff --git a/src/filehandle/hooks/useFileSystem.ts b/src/filehandle/hooks/useFileSystem.ts index caec05d..ee1bacd 100644 --- a/src/filehandle/hooks/useFileSystem.ts +++ b/src/filehandle/hooks/useFileSystem.ts @@ -102,7 +102,7 @@ export function useFileSystem(): FileSystem { useMemo(() => update(), [webdavs]); - useMemo( + useEffect( () => fileLinked.current?.listener((directory) => update(directory)), [fileLinked.current, webdavs] ); @@ -145,7 +145,15 @@ export function useFileSystem(): FileSystem { try { await removeFile(current, name); - setChildren(children.filter((c) => c.name !== name)); + setChildren( + children.filter((c) => { + if (c.name === name && c.handle.kind === 'directory') { + fileLinked.current.unlink(c.handle); + } + + return c.name !== name; + }) + ); } catch (err) { error((err as Error).message); } diff --git a/src/filehandle/md_editor/component/MDSidebar.tsx b/src/filehandle/md_editor/component/MDSidebar.tsx index 36ebac2..f1ca7b3 100644 --- a/src/filehandle/md_editor/component/MDSidebar.tsx +++ b/src/filehandle/md_editor/component/MDSidebar.tsx @@ -28,11 +28,11 @@ interface ISidebarProps { onSelect(handle: FH): void; } -type ExtendFileInfo = FileInfo & { +interface ExtendFileInfo extends FileInfo { id: string; parent?: ExtendFileInfo; children?: ExtendFileInfo[]; -}; +} const ADD_KEY = '.$<>/\\.#$%' + uuid(); diff --git a/src/filehandle/md_editor/component/styles/MDEditor.module.less b/src/filehandle/md_editor/component/styles/MDEditor.module.less index d486f16..ebb9e5d 100644 --- a/src/filehandle/md_editor/component/styles/MDEditor.module.less +++ b/src/filehandle/md_editor/component/styles/MDEditor.module.less @@ -16,6 +16,10 @@ border: none; outline: none; + & > :first-child { + margin-top: 0px !important; + } + h1, h2, h3, @@ -28,10 +32,10 @@ pre, blockquote, hr { - margin-top: 0.6em; - margin-bottom: 0.3em; + margin-top: 1em; + margin-bottom: 0.5em; font-size: 15px; - line-height: 1.57; + line-height: 1.8; color: var(--text-color); word-break: break-word; } @@ -42,7 +46,7 @@ h4, h5, h6 { - margin-bottom: 0.5em; + margin-bottom: 1em; font-weight: 600; }