فهرست منبع

WIP - XHR upload progress proposal

dom111 2 سال پیش
والد
کامیت
9cacabe28f
9فایلهای تغییر یافته به همراه55 افزوده شده و 52 حذف شده
  1. 4 25
      src/lib/DAV.ts
  2. 6 2
      src/lib/Entry.ts
  3. 21 17
      src/lib/HTTP.ts
  4. 2 1
      src/lib/Response.ts
  5. 4 3
      src/lib/handleFileUpload.ts
  6. 18 1
      src/lib/joinPath.ts
  7. 0 0
      src/webdav-min.js
  8. 0 0
      src/webdav.js.map
  9. 0 3
      src/webdav.ts

+ 4 - 25
src/lib/DAV.ts

@@ -305,32 +305,11 @@ export class DAV {
     path: string,
     file: File,
     onProgress: (uploadedBytes: number) => void = () => {}
-  ): Promise<{ ok: boolean }> {
-    const targetFile = joinPath(path, file.name);
-
-    const xhr = await this.#http.PUT(
-      joinPath(location.pathname, file.name),
-      file,
-      onProgress
+  ): Promise<Response> {
+    return this.#toastOnFailure(
+      (): Promise<Response> =>
+        this.#http.PUT(joinPath(path, file.name), file, onProgress)
     );
-
-    const ok = xhr.status >= 200 && xhr.status < 300;
-
-    if (!ok) {
-      error(
-        t('failure', {
-          interpolation: {
-            escapeValue: false,
-          },
-          method: 'PUT',
-          url: xhr.responseURL,
-          statusText: xhr.statusText,
-          status: xhr.status,
-        })
-      );
-    }
-
-    return { ok: ok };
   }
 }
 

+ 6 - 2
src/lib/Entry.ts

@@ -1,4 +1,8 @@
-import joinPath, { pathAndName, trailingSlash } from './joinPath';
+import joinPath, {
+  normalisePath,
+  pathAndName,
+  trailingSlash,
+} from './joinPath';
 import Collection from './Collection';
 import EventEmitter from '@dom111/typed-event-emitter/EventEmitter';
 import { t } from 'i18next';
@@ -87,7 +91,7 @@ export default class Entry extends EventEmitter<EntryEvents> {
     this.#name = name;
     this.#copy = copy;
     this.#directory = directory;
-    this.#fullPath = fullPath;
+    this.#fullPath = normalisePath(fullPath);
     this.#title = title;
     this.#modified = modifiedDate;
     this.#move = move;

+ 21 - 17
src/lib/HTTP.ts

@@ -54,32 +54,36 @@ const method = async (
 const methodXHR = async (
   method: string,
   url: RequestInfo,
-  body: Document | XMLHttpRequestBodyInit | null = null,
+  body: XMLHttpRequestBodyInit | null = null,
   parameters: RequestInit = {},
   onProgress: (loaded: number) => void = () => {}
 ): Promise<Response> => {
   return new Promise<Response>(async (resolve, reject) => {
     const request = new Request(url, {
-      ...(defaultParams[method] || {}),
-      ...parameters,
-      method,
-    });
-
-    const xhr = new XMLHttpRequest();
+        ...(defaultParams[method] || {}),
+        ...parameters,
+        method,
+        body,
+      }),
+      xhr = new XMLHttpRequest();
 
     xhr.open(request.method, request.url, true);
     request.headers.forEach((value, key) => xhr.setRequestHeader(key, value));
     xhr.upload.addEventListener('progress', (e) => onProgress(e.loaded), false);
     xhr.addEventListener('loadend', () => {
-      const response = new Response(xhr.response, {
-        headers: xhr
-          .getAllResponseHeaders()
-          .trim()
-          .split('\r\n')
-          .map((line) => line.split(': ', 2) as [string, string]),
-        status: xhr.status,
-        statusText: xhr.statusText,
-      });
+      // https://fetch.spec.whatwg.org/#statuses
+      const body = [101, 204, 205, 304].includes(xhr.status)
+          ? null
+          : xhr.response,
+        response = new Response(body, {
+          headers: xhr
+            .getAllResponseHeaders()
+            .trim()
+            .split('\r\n')
+            .map((line) => line.split(': ', 2) as [string, string]),
+          status: xhr.status,
+          statusText: xhr.statusText,
+        });
 
       if (!response.ok) {
         reject(new RequestFailure(request, response));
@@ -105,7 +109,7 @@ export class HTTP {
     url: string,
     file: File,
     onProgress: (uploadedBytes: number) => void,
-    parameters: RequestInit
+    parameters?: RequestInit
   ): Promise<Response> {
     return methodXHR(
       'PUT',

+ 2 - 1
src/lib/Response.ts

@@ -1,4 +1,5 @@
 import Collection from './Collection';
+import { normalisePath } from './joinPath';
 
 export type EntryObject = {
   directory: boolean;
@@ -49,7 +50,7 @@ export class Response {
     return Array.from(responses).map(
       (response): EntryObject => ({
         directory: !!getTag(response, 'D:collection'),
-        fullPath: getTagContent(response, 'D:href'),
+        fullPath: normalisePath(getTagContent(response, 'D:href')),
         modified: Date.parse(
           getTagContent(response, 'lp1:getlastmodified') ||
             getTagContent(response, 'D:getlastmodified')

+ 4 - 3
src/lib/handleFileUpload.ts

@@ -1,7 +1,7 @@
 import DAV from './DAV';
 import Entry from './Entry';
 import State from './State';
-import joinPath from './joinPath';
+import joinPath, { normalisePath } from './joinPath';
 import { success } from 'melba-toast';
 import { t } from 'i18next';
 
@@ -10,7 +10,8 @@ export const handleFileUpload = async (
   state: State,
   file: File
 ): Promise<void> => {
-  const collection = await dav.list(state.getPath(), true);
+  const collection = await dav.list(state.getPath(), true),
+    normalisedFileName = normalisePath(file.name);
 
   if (!collection) {
     return;
@@ -19,7 +20,7 @@ export const handleFileUpload = async (
   state.setCollection(collection);
 
   const [existingFile] = collection.filter(
-    (entry: Entry): boolean => entry.name === file.name
+    (entry: Entry): boolean => entry.name === normalisedFileName
   );
 
   if (existingFile) {

+ 18 - 1
src/lib/joinPath.ts

@@ -12,8 +12,25 @@ export const leadingAndTrailingSlash = (text: string): string =>
 export const leadingSlash = (text: string): string =>
   text.startsWith('/') ? text : `/${text}`;
 
+export const normalisePath = (path: string) =>
+  path
+    .split(/\//)
+    .map((pathPart: string) => {
+      let unescaped;
+
+      // Yuck! This is needed to decode 'badly' encoded paths (%df for ß for example)
+      try {
+        unescaped = decodeURIComponent(pathPart);
+      } catch (e) {
+        unescaped = unescape(pathPart);
+      }
+
+      return encodeURIComponent(unescaped);
+    })
+    .join('/');
+
 export const pathAndName = (path: string): [string, string] => {
-  const pathParts = joinPath(path).split(/\//),
+  const pathParts = joinPath(normalisePath(path)).split(/\//),
     file = pathParts.pop();
 
   return [joinPath(...pathParts), file];

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
src/webdav-min.js


تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 0 - 0
src/webdav.js.map


+ 0 - 3
src/webdav.ts

@@ -12,9 +12,6 @@ import de from '../translations/de.json';
 import en from '../translations/en.json';
 import pt from '../translations/pt.json';
 import { use } from 'i18next';
-import Tree from './components/Tree/Tree';
-import WebDAV from './components/Tree/WebDAV';
-import PlainObject from './components/Tree/PlainObject';
 
 use(LanguageDetector)
   .init({

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است