Source: gdfs-ui.js

"use strict";
const debug = require("debug")("gdfs-ui");
debug("loading");
const Gdfs = require("./gdfs.js");
const GdfsEvent = require("./gdfs-event.js");

/**
 * class GdfsUi
 * @constructor
 * @param {HTMLElement} The root element that UI widget will be built.
 * @param {Gdfs} The gapi client.
 */
function GdfsUi(element, opt) {
    debug("Start of GdfsUi ctor");
    this._element = element;
    this._gdfs = new Gdfs();
    this._pageSize = 10;
    this._trashed = false;
    this._pageToken = null;
    this._files = [];
    this._opt = {
        onFileListChange: () => {},
        onCurrentDirChange: () => {},
    };

    opt = opt || {};
    for(const key of Object.keys(this._opt)) {
        if(key in opt) {
            this._opt[key] = opt[key];
        }
    }

    // events
    this._fileListChangeEvent = new GdfsEvent(
        this._element, "gdfsui-filelist-change");
    this._currentDirChangeEvent = new GdfsEvent(
        this._element, "gdfsui-current-dir-change");

    this._currentDirChangeEvent.listen(
        this._opt.onCurrentDirChange);
    this._fileListChangeEvent.listen(
        this._opt.onFileListChange);

    this._gdfs.onCwdUpdate(async () => {
        debug("Start of _gdfs.onCwdUpdate");
        await this.reload();
        this._currentDirChangeEvent.fire();
        debug("End of _gdfs.onCwdUpdate");
    });

    const onSignedInStatusChange = async status => {
        debug("Start of signInStatusChange");
        if(status) {
            await this._gdfs.chdir("/");
        }
        debug("End of signInStatusChange");
    };

    // Listen events
    Gdfs.signInStatusChangeEvent.listen(
        () => onSignedInStatusChange(Gdfs.isSignedIn()));

    onSignedInStatusChange(Gdfs.isSignedIn());
    debug("End of GdfsUi ctor");
}

/**
 * Returns the listing files in current directory is completed.
 * @returns {boolean} true if the listing files is completed.
 */
GdfsUi.prototype.isPageCompleted = function() {
    const status = this._pageToken == null;
    return status;
};

/**
 * Get current path as full path.
 * @returns {Array<string>} The array of file ids.
 */
GdfsUi.prototype.getCurrentPath = function() {
    return this._gdfs._currentPath;
};

/**
 * Get files list on current page.
 * @param {number} begin a file index
 * @param {number} end a file index
 * @returns {Array<File>} the files in current page.
 */
GdfsUi.prototype.getFiles = async function(begin, end) {
    debug(`GdfsUi#getFiles param:{begin:${begin}, end:${end})}`);
    debug(`_pageToken: ${this._pageToken}`);
    if(this._pageToken == null) {
        this._files = [];
    }
    while(end > this._files.length) {
        await this.readDir();
        this._fileListChangeEvent.fire();
        if(this._pageToken == null) {
            break;
        }
    }
    return this._files.slice(begin, end);
};

/**
 * Read the files on current directory.
 * @async
 * @returns {Promise<undefined>}
 */
GdfsUi.prototype.readDir = async function() {

    const andConditionsOfQuerySearchClauses = [
        `parents in '${this._gdfs.getCurrentFolderId()}'`,
        `trashed = ${this._trashed?"true":"false"}`,
    ];

    const queryParameters = {
        "pageSize": this._pageSize,
        "pageToken": this._pageToken,
        "q": andConditionsOfQuerySearchClauses.join(" and "),
        "fields": "nextPageToken, files(id, name, mimeType, webContentLink, webViewLink)",
    };

    const result = await Gdfs.getFileList(queryParameters);
    this._pageToken = result.nextPageToken;
    for(const file of result.files) {
        this._files.push(file);
    }
};

/**
 * Reload the file list.
 * @async
 * @returns {Promise} to sync
 */
GdfsUi.prototype.reload = async function() {
    this._pageToken = null;
    this._files = [];
    await this.readDir();
    this._fileListChangeEvent.fire();
};

/**
 * Move current directory to root, parent or one of children.
 * @param {string} folderId A destination file id to move.
 * To move to parent, ".." is available.
 * @returns {Promise<undefined>}
 */
GdfsUi.prototype.chdirById = async function(folderId) {
    await this._gdfs.chdirById(folderId);
};

/**
 * Get file resource.
 * @async
 * @param {string} fileId The file id of the target file.
 * @returns {Promise<object>} The resource object.
 */
GdfsUi.prototype.getFileResource = async function(fileId) {
    return await Gdfs.getFileResource({
        "fileId": fileId,
    });
};

/**
 * Upload a file.
 * @param {File} file the file to be uploaded.
 * @return {Promise<File>} an uploaded File.
 */
GdfsUi.prototype.uploadFile = function (file) {
    return new Promise( (resolve, reject) => {
        const reader = new FileReader();
        reader.onload = async () => {
            resolve(await this.writeFile(
                file.name, file.type, reader.result));
        };
        reader.onerror = event => {
            reject(new Error([
                "Fail to upload. Could not read the file ",
                `${file.name}(${event.type}).`,
            ].join("")));
        };
        reader.readAsArrayBuffer(file);
    });
};

/**
 * Create or overwrite a file to current directory.
 * @param {string} filename The file name.
 * @param {string} mimeType The content type.
 * @param {any} data The file content.
 * @returns {Promise<object>} The response of update.
 */
GdfsUi.prototype.writeFile = async function (
    filename, mimeType, data)
{
    // Find same file in current directory
    const fileIds = this._files
        .filter(file => (file.name === filename))
        .map( file => file.id );

    if(fileIds.length == 0) {
        //Create new file
        const response = await Gdfs.createFile(
            this._gdfs.getCurrentFolderId(), filename, mimeType);
        const file = JSON.parse(response);
        return await Gdfs.updateFile(
            file.id, mimeType, data);
    }

    // Overwrite the file
    return await Gdfs.updateFile(
        fileIds[0], mimeType, data);
};

module.exports = GdfsUi;