/**
* @file <b>esperecyan-webdav-client</b> is the WebDAV client library
* which is designed like [File and Directory Entries API]{@link https://wicg.github.io/entries-api/}.
* @version 1.0.1
* @see [File and Directory Entries API — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/File_and_Directory_Entries_API}
* @license MPL-2.0
* @author 100の人
* @see {@link https://github.com/esperecyan/webdav-client}
*/
'use strict';
/**
* The DOMException interface represents an abnormal event (called an exception)
* which occurs as a result of calling a method or accessing a property of a web API.
* @external DOMException
* @see [DOMException — Web APIs | MDN]{@link https://developer.mozilla.org/ja/docs/Web/API/DOMException}
* @see [4.3. DOMException | Web IDL]{@link https://heycam.github.io/webidl/#idl-DOMException}
*/
/**
* An ErrorCallback function is used for operations that may return an error asynchronously.
* @external ErrorCallback
* @see [ErrorCallback | File and Directory Entries API]{@link
* https://wicg.github.io/entries-api/#callbackdef-errorcallback}
*/
/**
* This interface is the generic callback used to indicate success of an asynchronous method.
* @external VoidCallback
* @see [6.6.7 The VoidCallback interface | File and Directory Entries API]{@link
* https://www.w3.org/TR/2012/WD-file-system-api-20120417/#the-voidcallback-interface}
*/
/**
* This interface is the generic callback used to indicate success of an asynchronous method.
* @external FileSystemFlags
* @see [FileSystemFlags — Web APIs | MDN]{@link https://developer.mozilla.org/docs/Web/API/FileSystemFlags}
* @see [FileSystemFlags | 7.2. The FileSystemDirectoryEntry Interface | File and Directory Entries API]{@link
* https://wicg.github.io/entries-api/#dictdef-filesystemflags}
*/
/**
* @external FileCallback
* @see [FileCallback | 7.4. The FileSystemFileEntry Interface | File and Directory Entries API]{@link
* https://wicg.github.io/entries-api/#callbackdef-filecallback}
*/
/**
* The File interface provides information about files and allows JavaScript in a web page to access their content.
* @external File
* @see [File — Web APIs | MDN]{@link https://developer.mozilla.org/docs/Web/API/File}
* @see [4. The File Interface | File API]{@link https://www.w3.org/TR/FileAPI/#file-section}
*/
/** @namespace */
const webdav = {};
/**
* The Metadata interface is used by the File and Directory Entries API
* to contain information about a file system entry.
*
* @typedef {Object} webdav.Metadata
* @see [Metadata — Web APIs | MDN]{@link https://developer.mozilla.org/docs/Web/API/Metadata}
* @see [5.1 The Metadata interface | File API: Directories and System]{@link
* https://www.w3.org/TR/2012/WD-file-system-api-20120417/#the-metadata-interface}
* @property {Date} modificationTime
* @property {number} size
* @property {string} eTag
*/
/**
* This interface is the callback used to look up file and directory metadata.
* @callback webdav.MetadataCallback
* @see [6.6.4 The MetadataCallback interface | File API: Directories and System]{@link
* https://www.w3.org/TR/2012/WD-file-system-api-20120417/#the-metadatacallback-interface}
* @param {webdav.Metadata} metadata
* @returns {void}
* @property {Function} [handleEvent]
*/
/**
* @callback webdav.FileSystemEntryCallback
* @see [FileSystemEntryCallback | 7.2. The FileSystemDirectoryEntry Interface | File and Directory Entries API]{@link
* https://wicg.github.io/entries-api/#callbackdef-filesystementrycallback}
* @param {webdav.FileSystemEntry} entry
* @returns {void}
* @property {Function} [handleEvent]
*/
/**
* @callback webdav.FileSystemEntriesCallback
* @see [FileSystemEntriesCallback | 7.3. The FileSystemDirectoryReader Interface | File and Directory Entries API]{@link https://wicg.github.io/entries-api/#callbackdef-filesystementriescallback}
* @param {webdav.FileSystemEntry[]} entries
* @returns {void}
* @property {Function} [handleEvent]
*/
/**
* This interface is the callback used to create a {@link webdav.FileWriter}.
* @callback webdav.FileWriterCallback
* @see [6.6.5 The FileWriterCallback interface | File API: Directories and System]{@link
* https://www.w3.org/TR/2012/WD-file-system-api-20120417/#the-filewritercallback-interface}
* @param {webdav.FileWriter} fileWriter
* @returns {void}
* @property {Function} [handleEvent]
*/
/**
* The basic interface representing a single entry in a file system.
* This is implemented by other interfaces which represent files or directories.
* @see [FileSystemEntry — Web APIs | MDN]{@link https://developer.mozilla.org/docs/Web/API/FileSystemEntry}
*/
webdav.FileSystemEntry = class {
/**
* @hideconstructor
* @param {Object} params
* @param {string} params.fullPath
* @param {?webdav.Metadata} [params.metadata]
*/
constructor({fullPath, metadata = null})
{
/**
* A Boolean which is `true` if the entry represents a file. If it’s not a file, this value is `false`.
* @see [FileSystemEntry.isFile — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemEntry/isFile}
* @readonly
* @type {boolean}
*/
this.isFile = false;
/**
* A Boolean which is `true` if the entry represents a directory; otherwise, it’s `false`.
* @see [FileSystemEntry.isDirectory — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemEntry/isDirectory}
* @readonly
* @type {boolean}
*/
this.isDirectory = false;
/**
* A USVString containing the name of the entry (the final part of the path, after the last “/” character).
* @see [FileSystemEntry.name — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemEntry/name}
* @readonly
* @type {string}
*/
this.name = decodeURIComponent(/([^/]*)\/?$/.exec(fullPath)[1]);
/**
* An absolute-URL string.
* @see [FileSystemEntry.fullPath — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemEntry/fullPath}
* @readonly
* @type {string}
*/
this.fullPath = fullPath;
/**
* @access private
* @type {?webdav.Metadata}
*/
this.metadata = metadata;
}
/**
* Returns a {@link webdav.FileSystemDirectoryEntry} representing the entry’s parent directory.
* @see [FileSystemEntry.getParent() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemEntry/getParent}
* @param {webdav.FileSystemEntryCallback} [successCallback]
* A function which is called when the parent directory entry has been retrieved.
* The callback receives a single input parameter:
* a {@link webdav.FileSystemDirectoryEntry} object representing the parent directory.
* The parent of the root directory is considered to be the root directory, itself,
* so be sure to watch for that.
* @param {external:ErrorCallback} [errorCallback] - An optional callback which is executed if an error occurs.
* There’s a single parameter: a {@link external:DOMException} describing what went wrong.
* @returns {void}
*/
getParent(successCallback = () => {}, errorCallback = () => {})
{
if (this.fullPath === '') {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(
new DOMException('The directory is associated with the root of the file system.', 'NotSupportedError')
);
} else {
const url = new URL('.', this.fullPath.replace(/\/$/, ''));
const client = new XMLHttpRequest();
client.open('PROPFIND', url);
client.setRequestHeader('content-type', 'application/xml; charset=UTF-8');
client.setRequestHeader('depth', '0');
client.responseType = 'document';
client.addEventListener('error', function () {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(
new DOMException(`NetworkError when attempting to fetch an entry <${url}>.`, 'NotFoundError')
);
});
client.addEventListener('load', function (event) {
let entry, err;
if (event.target.status === 207) {
if (event.target.response.getElementsByTagNameNS('DAV:', 'collection')[0]) {
entry = new webdav.FileSystemDirectoryEntry({fullPath: event.target.responseURL, metadata: {
modificationTime: new Date(
event.target.response.getElementsByTagNameNS('DAV:', 'getlastmodified')[0].textContent
),
size: 0,
eTag: event.target.response.getElementsByTagNameNS('DAV:', 'getetag')[0].textContent,
}});
} else {
err = new DOMException(`<${url}> is a file, not a directory.`, 'TypeMismatchError');
}
} else {
err = new DOMException(`${event.target.status} ${event.target.statusText}`, 'NotFoundError');
}
if (entry) {
(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent)(entry);
} else {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(err);
}
});
client.send(`<?xml version="1.0" encoding="UTF-8"?>
<propfind xmlns="DAV:">
<prop>
<resourcetype />
<getlastmodified />
<getcontentlength />
<getetag />
</prop>
</propfind>`);
}
}
/**
* Obtains metadata about the file, such as its modification date and size.
* @see [FileSystemEntry.getMetadata() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemEntry/getMetadata}
* @see [File API: Directories and System]{@link
* https://www.w3.org/TR/2012/WD-file-system-api-20120417/#the-entry-interface}
* @param {webdav.MetadataCallback} successCallback
* A function which is called when looking up the metadata is succesfully completed.
* Receives a single input parameter: a {@link webdav.Metadata} object with information about the file.
* **This is information at the time of the instance of {@link wevdav.FileSystemEntry} created.**
* @param {external:ErrorCallback} [errorCallback]
* An optional callback which is executed if an error occurs while looking up the metadata.
* There’s a single parameter: a {@link external:DOMException} describing what went wrong.
* @returns {void}
*/
getMetadata(successCallback, errorCallback = () => {})
{
if (this.metadata) {
(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent)(
Object.assign({}, this.metadata)
);
} else {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(
new DOMException(`This entry <${this.fullPath}> does not have metadata.`, 'NotSupportedError')
);
}
}
/**
* Removes the specified file or directory. You can only remove directories which are empty.
* @see [FileSystemEntry.remove() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemEntry/remove}
* @see [File API: Directories and System]{}@link
* https://www.w3.org/TR/2012/WD-file-system-api-20120417/#the-entry-interface}
* @param {external:VoidCallback} successCallback
* A function which is called once the file has been successfully removed.
* @param {external:ErrorCallback} [errorCallback]
* An optional callback which is called if the attempt to remove the file fails.
* @returns {void}
*/
remove(successCallback, errorCallback = () => {})
{
(async () => {
if (this.fullPath === '') {
return Promise.reject(new DOMException(
'The directory associated with the root of the file system can not be removed.',
'NotSupportedError'
));
}
if (this.isDirectory) {
const entries = await new Promise((resolve, reject) => {
this.createReader().readEntries(resolve, reject);
});
if (entries.length > 0) {
return Promise.reject(
new DOMException(`This directory <${this.fullPath}> is not empty.`, 'InvalidModificationError')
);
}
}
const response = await fetch(this.fullPath, {method: 'DELETE'});
if (response.ok) {
(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent)();
} else {
return Promise.reject(new DOMException(
`${response.status} ${response.statusText}`,
response.status === 404 ? 'NotFoundError' : 'TypeMismatchError'
));
}
})().catch(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent);
}
};
/**
* Represents a single directory in a file system.
* @see [FileSystemDirectoryEntry — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemDirectoryEntry}
*/
webdav.FileSystemDirectoryEntry = class extends webdav.FileSystemEntry {
/** @inheritdoc */
constructor(...args)
{
super(...args);
this.isDirectory = true;
}
/**
* Creates
* a {@link webdav.FileSystemDirectoryReader} object which can be used to read the entries in this directory.
* @see [FileSystemDirectoryEntry.createReader() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemDirectoryEntry/createReader}
* @returns {webdav.FileSystemDirectoryReader}
* A {@link webdav.FileSystemDirectoryReader} object which can be used to read the directory’s entries.
*/
createReader()
{
return new webdav.FileSystemDirectoryReader({directoryEntry: this});
}
/**
* Returns a {@link webdav.FileSystemFileEntry} object representinga file located
* within the directory’s hierarchy, given a path relative to the directory on which the method is called.
* @see [FileSystemDirectoryEntry.getFile() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemDirectoryEntry/getFile}
* @param {?string} [path] - A `USVString` specifying the path,
* relative to the directory on which the method is called, describing which file’s entry to return.
* @param {external:FileSystemFlags} [options]
* An object based on the {@link external:FileSystemFlags} dictionary, which allows you to specify
* whether or not to create the entry if it’s missing and if it’s an error if the file already exists.
* **This method returns dummy instance instead of creating an empty file.**
* @param {webdav.FileSystemEntryCallback} [successCallback]
* A method to be called once the {@link webdav.FileSystemFileEntry} has been created.
* The method receives a single parameter:
* the {@link webdav.FileSystemFileEntry} object representing the file in question.
* @param {external:ErrorCallback} [errorCallback] - A method to be called if an error occurs. Receives
* as its sole input parameter a {@link external:DOMException} object describing the error which occurred.
* @returns {void}
*/
getFile(path = '', {create = false, exclusive = false} = {}, successCallback = () => {}, errorCallback = () => {})
{
let url;
let typeError;
try {
url = this.fullPath ? new URL(path, this.fullPath) : new URL(path);
} catch (exception) {
if (exception instanceof TypeError) {
typeError = exception;
} else {
throw exception;
}
}
if (typeError || !/^https?:\/\/[^?#]+[^/?#]$/.test(url)) {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(new DOMException(
typeError || `<${url}> does not match supported URL patterns that the scheme is “https” or “http”,`
+ ' the path does not end with “/”, and neither a query nor a fragment exist.',
'TypeMismatchError'
));
return;
}
const client = new XMLHttpRequest();
client.open('PROPFIND', url);
client.setRequestHeader('content-type', 'application/xml; charset=UTF-8');
client.setRequestHeader('depth', '0');
client.responseType = 'document';
client.addEventListener('error', function () {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(
new DOMException(`NetworkError when attempting to fetch an entry <${url}>.`, 'NotFoundError')
);
});
client.addEventListener('load', function (event) {
let entry, err;
if (event.target.status === 207) {
if (create && exclusive) {
err = new DOMException(`<${url}> already exists.`, 'PathExistsError');
} else if (!event.target.response.getElementsByTagNameNS('DAV:', 'collection')[0]) {
entry = new webdav.FileSystemFileEntry({fullPath: event.target.responseURL, metadata: {
modificationTime: new Date(
event.target.response.getElementsByTagNameNS('DAV:', 'getlastmodified')[0].textContent
),
size: Number.parseInt(
event.target.response.getElementsByTagNameNS('DAV:', 'getcontentlength')[0].textContent
),
eTag: event.target.response.getElementsByTagNameNS('DAV:', 'getetag')[0].textContent,
}});
} else {
err = new DOMException(`<${url}> is a directory, not a file.`, 'TypeMismatchError');
}
} else if (event.target.status === 404 && create) {
entry = new webdav.FileSystemFileEntry({fullPath: event.target.responseURL});
} else {
err = new DOMException(`${event.target.status} ${event.target.statusText}`, 'NotFoundError');
}
if (entry) {
(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent)(entry);
} else {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(err);
}
});
client.send(`<?xml version="1.0" encoding="UTF-8"?>
<propfind xmlns="DAV:">
<prop>
<resourcetype />
<getlastmodified />
<getcontentlength />
<getetag />
</prop>
</propfind>`);
}
/**
* Returns a {@link webdav.FileSystemDirectoryEntry} object
* representing a directory located at a given path, relative to the directory on which the method is called.
* @see [FileSystemDirectoryEntry.getDirectory() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemDirectoryEntry/getDirectory}
* @param {?string} [path] - A USVString representing an absolute path or a path relative to the directory
* on which the method is called, describing which directory entry to return.
* @param {external:FileSystemFlags} [options]
* An object based on the {external:FileSystemFlags} dictionary, which allows you to specify
* whether or not to create the entry if it's missing and if it's an error if the file already exists.
* @param {webdav.FileSystemEntryCallback} [successCallback]
* A method to be called once the {@link webdav.FileSystemEntryCallback} has been created.
* The method receives a single parameter:
* the {@link webdav.FileSystemEntryCallback} object representing the directory in question.
* @param {external:ErrorCallback} [errorCallback] - A method to be called if an error occurs. Receives
* as its sole input parameter a {@link external:DOMException} object describing the error which occurred.
* @returns {void}
*/
getDirectory(
path = '',
{create = false, exclusive = false} = {},
successCallback = () => {},
errorCallback = () => {}
) {
if (path && !path.endsWith('/')) {
path += '/';
}
let url;
let typeError;
try {
url = this.fullPath ? new URL(path, this.fullPath) : new URL(path);
} catch (exception) {
if (exception instanceof TypeError) {
typeError = exception;
} else {
throw exception;
}
}
if (typeError || !/^https?:\/\/[^?#]+$/.test(url)) {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(new DOMException(
typeError || `<${url}> does not match supported URL patterns that the scheme is “https” or “http”,`
+ ' and neither a query nor a fragment exist.',
'TypeMismatchError'
));
return;
}
const client = new XMLHttpRequest();
client.open('PROPFIND', url);
client.setRequestHeader('content-type', 'application/xml; charset=UTF-8');
client.setRequestHeader('depth', '0');
client.responseType = 'document';
client.addEventListener('error', function () {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(
new DOMException(`NetworkError when attempting to fetch an entry <${url}>.`, 'NotFoundError')
);
});
client.addEventListener('load', function (event) {
(async function () {
if (event.target.status === 207) {
if (create && exclusive) {
return Promise.reject(new DOMException(`<${url}> already exists.`, 'PathExistsError'));
}
if (event.target.response.getElementsByTagNameNS('DAV:', 'collection')[0]) {
return new webdav.FileSystemDirectoryEntry({fullPath: event.target.responseURL, metadata: {
modificationTime: new Date(
event.target.response.getElementsByTagNameNS('DAV:', 'getlastmodified')[0].textContent
),
size: 0,
eTag: event.target.response.getElementsByTagNameNS('DAV:', 'getetag')[0].textContent,
}});
} else {
return Promise.reject(
new DOMException(`<${url}> is a file, not a directory.`, 'TypeMismatchError')
);
}
} else if (event.target.status === 404 && create) {
try {
const response = await fetch(url, {method: 'MKCOL'});
return response.ok
? new webdav.FileSystemDirectoryEntry({fullPath: response.url})
: Promise.reject(new DOMException(
`${response.status} ${response.statusText}`,
'NoModificationAllowedError'
));
} catch (exception) {
if (exception instanceof TypeError) {
return Promise.reject(new DOMException(exception.message, 'NetworkError'));
} else {
throw exception;
}
}
} else {
return Promise.reject(
new DOMException(`${event.target.status} ${event.target.statusText}`, 'NotFoundError')
);
}
})()
.then(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent)
.catch(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent);
});
client.send(`<?xml version="1.0" encoding="UTF-8"?>
<propfind xmlns="DAV:">
<prop>
<resourcetype />
<getlastmodified />
<getcontentlength />
<getetag />
</prop>
</propfind>`);
}
/**
* Deletes a directory and all of its contents, including the contents of subdirectories.
* @see [FileSystemDirectoryEntry.removeRecursively() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemDirectoryEntry/removeRecursively}
* @see [File API: Directories and System]{@link
* https://www.w3.org/TR/2012/WD-file-system-api-20120417/#the-directoryentry-interface}
* @param {external:VoidCallback} successCallback
* A function to call once the directory removal process has completed. The callback has no parameters.
* @param {external:ErrorCallback} [errorCallback]
* A function to be called if an error occurs while attempting to remove the directory subtree.
* Receives a {@link external:DOMException} describing the error which occurred as input.
* @returns {void}
*/
removeRecursively(successCallback, errorCallback = () => {})
{
(async () => {
if (this.fullPath === '') {
return Promise.reject(new DOMException(
'The directory associated with the root of the file system can not be removed.',
'NotSupportedError'
));
}
const response = await fetch(this.fullPath, {method: 'DELETE'});
if (response.ok) {
(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent)();
} else {
return Promise.reject(new DOMException(
`${response.status} ${response.statusText}`,
response.status === 404 ? 'NotFoundError' : 'TypeMismatchError'
));
}
})().catch(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent);
}
};
/**
* Created by calling {@link webdav.FileSystemDirectoryEntry.createReader},
* this interface provides the functionality which lets you read the contents of a directory.
* @see [FileSystemDirectoryReader — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemDirectoryReader}
*/
webdav.FileSystemDirectoryReader = class {
/**
* @hideconstructor
* @param {Object} params
* @param {webdav.FileSystemDirectoryEntry} params.directoryEntry
*/
constructor({directoryEntry})
{
/**
* @access private
* @type {webdav.FileSystemDirectoryEntry}
*/
this.directoryEntry = directoryEntry;
/**
* @access private
* @type {boolean}
*/
this.readingFlag = false;
/**
* @access private
* @type {boolean}
*/
this.doneFlag = false;
/**
* @access private
* @type {?DOMException}
*/
this.readerError = null;
}
/**
* Returns a an array containing some number of the directory’s entries.
* Each item in the array is an object based on FileSystemEntry
* —typically either {@link webdav.FileSystemFileEntry} or {@link webdav.FileSystemDirectoryEntry}.
* @see [FileSystemDirectoryReader.readEntries() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemDirectoryReader/readEntries}
* @param {webdav.FileSystemEntriesCallback} successCallback
* A function which is called when the directory’s contents have been retrieved.
* The function receives a single input parameter:
* an array of file system entry objects, each based on {@link webdav.FileSystemEntry}.
* Generally, they are either {@link webdav.FileSystemFileEntry} objects, which represent standard files,
* or {@link webdav.FileSystemDirectoryEntry} objects, which represent directories.
* If there are no files left, or you’ve already called readEntries() on this FileSystemDirectoryReader,
* the array is empty.
* @param {external:ErrorCallback} [errorCallback]
* A callback function which is called if an error occurs while reading from the directory.
* It receives one input parameter: a {@link external:DOMException} object describing the error which occurred.
* @returns {void}
*/
readEntries(successCallback, errorCallback = () => {})
{
if (this.readingFlag) {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(
new DOMException('The reader is during operation.', 'InvalidStateError')
);
} else if (this.readerError) {
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(this.readerError);
} else if (this.doneFlag) {
(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent)([]);
} else {
this.readingFlag = true;
const client = new XMLHttpRequest();
client.open('PROPFIND', this.directoryEntry.fullPath);
client.setRequestHeader('content-type', 'application/xml; charset=UTF-8');
client.setRequestHeader('depth', '1');
client.responseType = 'document';
client.addEventListener('error', function () {
this.readerError = new DOMException(
`NetworkError when attempting to fetch child entries of <${this.directoryEntry.fullPath}>.`,
'NetworkError'
);
this.readingFlag = false;
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(this.readerError);
});
client.addEventListener('load', event => {
if (event.target.status === 207) {
const responses = event.target.response.getElementsByTagNameNS('DAV:', 'response');
const entries = [];
for (let i = 1, l = responses.length; i < l; i++) {
const url = responses[i].getElementsByTagNameNS('DAV:', 'href')[0].textContent;
const isDirectory = responses[i].getElementsByTagNameNS('DAV:', 'collection')[0];
entries.push(new webdav[isDirectory ? 'FileSystemDirectoryEntry' : 'FileSystemFileEntry']({
fullPath: new URL(url, this.directoryEntry.fullPath).href,
metadata: {
modificationTime: new Date(
responses[i].getElementsByTagNameNS('DAV:', 'getlastmodified')[0].textContent
),
size: isDirectory ? 0 : Number.parseInt(
responses[i].getElementsByTagNameNS('DAV:', 'getcontentlength')[0].textContent
),
eTag: responses[i].getElementsByTagNameNS('DAV:', 'getetag')[0].textContent,
},
}));
}
this.doneFlag = true;
this.readingFlag = false;
(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent)(entries);
} else {
this.readingFlag = false;
this.readerError = new DOMException(`${event.target.status} ${event.target.statusText}`);
(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent)(this.readerError);
}
});
client.send(`<?xml version="1.0" encoding="UTF-8"?>
<propfind xmlns="DAV:">
<prop>
<resourcetype />
<getlastmodified />
<getcontentlength />
<getetag />
</prop>
</propfind>`);
}
}
};
/**
* Represents a single file in a file system.
* @see [FileSystemFileEntry — Web APIs | MDN]{@link https://developer.mozilla.org/docs/Web/API/FileSystemFileEntry}
*/
webdav.FileSystemFileEntry = class extends webdav.FileSystemEntry {
/** @inheritdoc */
constructor(...args)
{
super(...args);
this.isFile = true;
}
/**
* Creates a new FileWriter object which allows writing to the file represented by the file system entry.
* @see [FileSystemFileEntry.createWriter() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemFileEntry/createWriter}
* @see [File API: Directories and System]{@link
* https://www.w3.org/TR/2012/WD-file-system-api-20120417/#widl-FileEntry-createWriter-void-FileWriterCallback-successCallback-ErrorCallback-errorCallback}
* @param {webdav.FileWriterCallback} successCallback
* A callback function which is called when the {@link webdav.FileWriter} has been created successfully;
* the {@link webdav.FileWriter} is passed into the callback as the only parameter.
* @param {external:ErrorCallback} [errorCallback] - If provided, this must be a method
* which is caled when an error occurs while trying to create the {@link webdav.FileWriter}.
* This callback receives as input a {@link external:DOMException} object describing the error.
* @returns {void}
*/
createWriter(successCallback)
{
(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent)(
new webdav.FileWriter({fileEntry: this})
);
}
/**
* Creates a new File object which can be used to read the file.
* @see [FileSystemFileEntry.file() — Web APIs | MDN]{@link
* https://developer.mozilla.org/docs/Web/API/FileSystemFileEntry/file}
* @param {external:FileCallback} successCallback
* A callback function which is called when the {@link external:File} has been created successfully;
* the {@link external:File} is passed into the callback as the only parameter.
* @param {external:ErrorCallback} [errorCallback] - If provided,
* this must be a method which is caled when an error occurs while trying to create the {@link external:File}.
* This callback receives as input a {@link external:DOMException} object describing the error.
* @returns {void}
*/
file(successCallback, errorCallback = () => {})
{
fetch(this.fullPath).then(function (response) {
if (response.ok) {
response.blob()
.then(typeof successCallback === 'function' ? successCallback : successCallback.handleEvent);
} else {
return Promise.reject(
new DOMException(
`${response.status} ${response.statusText}`,
response.status === 404 ? 'NotFoundError' : 'TypeMismatchError'
)
);
}
}).catch(typeof errorCallback === 'function' ? errorCallback : errorCallback.handleEvent);
}
};
/**
* This interface provides methods to monitor the asynchronous writing of blobs to disk using event handler attributes
* and allow saving an Blob.
* @see [File API: Writer]{@link https://www.w3.org/TR/2012/WD-file-writer-api-20120417/#the-filewriter-interface}
*/
webdav.FileWriter = class {
/**
* @hideconstructor
* @param {Object} params
* @param {webdav.FileSystemFileEntry} params.fileEntry
*/
constructor({fileEntry})
{
/**
* @access private
* @type {webdav.FileSystemFileEntry}
*/
this.fileEntry = fileEntry;
}
/**
* Write the supplied data to the file.
* @see [File API: Writer]{@link
* https://www.w3.org/TR/2012/WD-file-writer-api-20120417/#widl-FileWriter-write-void-Blob-data}
* @param {Blob} data The blob to write.
* @returns {void}
*/
write(data)
{
fetch(this.fileEntry.fullPath, {method: 'PUT', body: data}).then(response => {
if (response.ok) {
/**
* Handler for write events.
* @see [onwrite | 5. The FileSaver interface | File API: Writer]{@link
* https://www.w3.org/TR/2012/WD-file-writer-api-20120417/#widl-FileSaver-onwrite}
* @type {?Function}
*/
if (this.onwrite) {
this.onwrite(new ProgressEvent('write'));
}
} else {
return Promise.reject(new DOMException(`${response.status} ${response.statusText}`));
}
}).catch(exception => {
/**
* The last error that occurred on the {@link webdav.FileWriter}.
* @see [error | 5. The FileSaver interface | File API: Writer]{@link
* https://www.w3.org/TR/2012/WD-file-writer-api-20120417/#widl-FileSaver-error}
* @readonly
* @type {external:DOMException}
*/
this.error = exception;
/**
* Handler for error events.
* @see [onerror | 5. The FileSaver interface | File API: Writer]{@link
* https://www.w3.org/TR/2012/WD-file-writer-api-20120417/#widl-FileSaver-onerror}
* @type {?Function}
*/
if (this.onerror) {
this.onerror(new ProgressEvent('error'));
}
});
}
};
/**
* A dummy {@link webdav.FileSystemDirectoryEntry} object which be used as the file system’s root directory.
* Through this object, you can gain access to all files and directories in the file system.
* @type {webdav.FileSystemDirectoryEntry}
*/
webdav.root = new webdav.FileSystemDirectoryEntry({fullPath: ''});