UNPKG

@adobe/coral-spectrum

Version:

Coral Spectrum is a JavaScript library of Web Components following Spectrum design patterns.

290 lines (245 loc) 7.42 kB
/** * Copyright 2019 Adobe. All rights reserved. * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ import MIME_TYPES from '../data/mimetypes'; import {transform, validate} from '../../../coral-utils'; /** Enumeration for {@link FileUploadItem} response types. @typedef {Object} FileUploadItemResponseTypeEnum @property {String} TEXT String type. @property {String} ARRAY_BUFFER Array buffer type. @property {String} BLOB Blob type. @property {String} DOCUMENT Document type. @property {String} JSON JavaScript object, parsed from a JSON string returned by the server. */ const responseType = { TEXT: 'text', ARRAY_BUFFER: 'arraybuffer', BLOB: 'blob', DOCUMENT: 'document', JSON: 'json' }; // eg text/plain const MIME_TYPE_REGEXP = /(.+)\/(.+)$/; // eg .txt const FILE_EXTENSION_REGEXP = /\.(.+)$/; // eg text const SHORTCUT_REGEXP = /.*/; const MIME_TYPE_AUDIO = 'audio/*'; const MIME_TYPE_IMAGE = 'image/*'; const MIME_TYPE_VIDEO = 'video/*'; /** @class Coral.FileUpload.Item @classdesc A FileUpload item encapsulating file meta-data @param {File|HTMLElement} file The file element. */ class FileUploadItem { /** Takes a {File} as argument. @param {File} file */ constructor(file) { this._originalFile = file; this._xhr = null; } /** The File. @name file @readonly @type {File} */ get file() { return this._originalFile; } /** Array of additional parameters as key:value to be uploaded with the file. A parameter must contain a <code>name</code> key:value and optionally a <code>value</code> key:value. @name parameters @type {Array.<Object>} @default [] */ get parameters() { return this._parameters || []; } set parameters(value) { const isValid = Array.isArray(value) && value.every((el) => el && el.name); if (isValid) { this._parameters = value; } } /** The item xhr <code>withCredentials</code> property. @name withCredentials @type {Boolean} @default false */ get withCredentials() { return this._withCredentials || false; } set withCredentials(value) { this._withCredentials = transform.boolean(value); } /** The item xhr <code>timeout</code> property. @name timeout @type {Number} @default 0 */ get timeout() { return this._timeout || 0; } set timeout(value) { const timeout = transform.number(value); if (timeout !== null) { this._timeout = timeout; if (this._xhr) { this._xhr.timeout = timeout; } } } /** The item xhr <code>responseType</code> property. See {@link FileUploadItemResponseTypeEnum}. @name responseType @default {FileUploadItemResponseTypeEnum.TEXT} @type {String} */ get responseType() { return this._responseType || responseType.TEXT; } set responseType(value) { value = transform.string(value).toLowerCase(); this._responseType = validate.enumeration(responseType)(value) && value || responseType.TEXT; if (this._xhr) { this._xhr.responseType = value; } } /** The item xhr <code>readyState</code> property. @name readyState @readonly @default 0 @type {Number} */ get readyState() { return this._xhr ? this._xhr.readyState : this._readyState || 0; } /** The item xhr <code>responseType</code> property. Depends on {@link Coral.FileUpload.Item#responseType}. @name response @readonly @default "" @type {String|ArrayBuffer|Blob|Document} */ get response() { return this._xhr ? this._xhr.response : this._response || ''; } /** The item xhr <code>responseText</code> property. @name responseText @readonly @default "" @type {String} */ get responseText() { return this._xhr ? this._xhr.responseText : this._responseText || ''; } /** The item xhr <code>responseXML</code> property. @name responseXML @readonly @default null @type {HTMLElement} */ get responseXML() { return this._xhr ? this._xhr.responseXML : this._responseXML || null; } /** The item xhr <code>status</code> property. @name status @readonly @default 0 @type {Number} */ get status() { return this._xhr ? this._xhr.status : this._status || 0; } /** The item xhr <code>statusText</code> property. @name statusText @readonly @default "" @type {String} */ get statusText() { return this._xhr ? this._xhr.statusText : this._statusText || ''; } /** @private */ _isMimeTypeAllowed(acceptedMimeTypes) { let isAllowed = false; // Unrecognized browser mime types have a file type of ''. const fileType = this.file.type || 'application/unknown'; if (!fileType.match(MIME_TYPE_REGEXP)) { // File mime type is erroneous return false; } return acceptedMimeTypes.split(',').some((allowedMimeType) => { allowedMimeType = allowedMimeType.trim(); if (allowedMimeType === '*' || allowedMimeType === '.*' || allowedMimeType === '*/*' || fileType === 'application/unknown') { // Explicit wildcard case: allow any file // Allow unknown mime types isAllowed = true; } else if (allowedMimeType.match(MIME_TYPE_REGEXP)) { if (allowedMimeType === MIME_TYPE_AUDIO) { isAllowed = fileType.indexOf(MIME_TYPE_AUDIO.slice(0, -1)) === 0; } else if (allowedMimeType === MIME_TYPE_IMAGE) { isAllowed = fileType.indexOf(MIME_TYPE_IMAGE.slice(0, -1)) === 0; } else if (allowedMimeType === MIME_TYPE_VIDEO) { isAllowed = fileType.indexOf(MIME_TYPE_VIDEO.slice(0, -1)) === 0; } else { // Proper mime type case: directly compare with file mime type isAllowed = fileType === allowedMimeType; } } else if (allowedMimeType.match(FILE_EXTENSION_REGEXP)) { // File extension case const allowedMimeTypes = MIME_TYPES[allowedMimeType]; // Depending on OS and browser, a file extension can map to different mime types // e.g .csv maps to "text/csv" on Mac OS and to "application/vnd.ms-excel" on Windows if (Array.isArray(allowedMimeTypes)) { isAllowed = allowedMimeTypes.some((mimeType) => fileType === mimeType); } else { isAllowed = fileType === MIME_TYPES[allowedMimeType]; } } else if (allowedMimeType.match(SHORTCUT_REGEXP)) { // "Shortcut" case: only compare first part of the file mime type with the shortcut isAllowed = fileType.split('/')[0] === allowedMimeType; } // Break the loop if file mime type is allowed return isAllowed; }); } /** Returns {@link FileUploadItem} response types. @return {FileUploadItemResponseTypeEnum} */ static get responseType() { return responseType; } } export default FileUploadItem;