/** * DevExtreme (ui/file_uploader.js) * Version: 19.1.16 * Build date: Tue Oct 18 2022 * * Copyright (c) 2012 - 2022 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; var $ = require("../core/renderer"); var Class = require("../core/class"); var Guid = require("../core/guid"); var window = require("../core/utils/window").getWindow(); var eventsEngine = require("../events/core/events_engine"); var registerComponent = require("../core/component_registrator"); var Callbacks = require("../core/utils/callbacks"); var isDefined = require("../core/utils/type").isDefined; var each = require("../core/utils/iterator").each; var extend = require("../core/utils/extend").extend; var inArray = require("../core/utils/array").inArray; var ajax = require("../core/utils/ajax"); var Editor = require("./editor/editor"); var Button = require("./button"); var ProgressBar = require("./progress_bar"); var browser = require("../core/utils/browser"); var devices = require("../core/devices"); var eventUtils = require("../events/utils"); var clickEvent = require("../events/click"); var messageLocalization = require("../localization/message"); var themes = require("./themes"); var FILEUPLOADER_CLASS = "dx-fileuploader"; var FILEUPLOADER_EMPTY_CLASS = "dx-fileuploader-empty"; var FILEUPLOADER_SHOW_FILE_LIST_CLASS = "dx-fileuploader-show-file-list"; var FILEUPLOADER_DRAGOVER_CLASS = "dx-fileuploader-dragover"; var FILEUPLOADER_WRAPPER_CLASS = "dx-fileuploader-wrapper"; var FILEUPLOADER_CONTAINER_CLASS = "dx-fileuploader-container"; var FILEUPLOADER_CONTENT_CLASS = "dx-fileuploader-content"; var FILEUPLOADER_INPUT_WRAPPER_CLASS = "dx-fileuploader-input-wrapper"; var FILEUPLOADER_INPUT_CONTAINER_CLASS = "dx-fileuploader-input-container"; var FILEUPLOADER_INPUT_LABEL_CLASS = "dx-fileuploader-input-label"; var FILEUPLOADER_INPUT_CLASS = "dx-fileuploader-input"; var FILEUPLOADER_FILES_CONTAINER_CLASS = "dx-fileuploader-files-container"; var FILEUPLOADER_FILE_CONTAINER_CLASS = "dx-fileuploader-file-container"; var FILEUPLOADER_FILE_INFO_CLASS = "dx-fileuploader-file-info"; var FILEUPLOADER_FILE_STATUS_MESSAGE_CLASS = "dx-fileuploader-file-status-message"; var FILEUPLOADER_FILE_CLASS = "dx-fileuploader-file"; var FILEUPLOADER_FILE_NAME_CLASS = "dx-fileuploader-file-name"; var FILEUPLOADER_FILE_SIZE_CLASS = "dx-fileuploader-file-size"; var FILEUPLOADER_BUTTON_CLASS = "dx-fileuploader-button"; var FILEUPLOADER_BUTTON_CONTAINER_CLASS = "dx-fileuploader-button-container"; var FILEUPLOADER_CANCEL_BUTTON_CLASS = "dx-fileuploader-cancel-button"; var FILEUPLOADER_UPLOAD_BUTTON_CLASS = "dx-fileuploader-upload-button"; var FILEUPLOADER_INVALID_CLASS = "dx-fileuploader-invalid"; var FILEUPLOADER_AFTER_LOAD_DELAY = 400; var FILEUPLOADER_CHUNK_META_DATA_NAME = "chunkMetadata"; var renderFileUploaderInput = function() { return $("").attr("type", "file") }; var isFormDataSupported = function() { return !!window.FormData }; var FileUploader = Editor.inherit({ _uploadStrategy: null, _supportedKeys: function() { var click = function(e) { e.preventDefault(); var $selectButton = this._selectButton.$element(); eventsEngine.trigger($selectButton, clickEvent.name) }; return extend(this.callBase(), { space: click, enter: click }) }, _setOptionsByReference: function() { this.callBase(); extend(this._optionsByReference, { value: true }) }, _getDefaultOptions: function() { return extend(this.callBase(), { chunkSize: 0, value: [], selectButtonText: messageLocalization.format("dxFileUploader-selectFile"), uploadButtonText: messageLocalization.format("dxFileUploader-upload"), labelText: messageLocalization.format("dxFileUploader-dropFile"), name: "files[]", multiple: false, accept: "", uploadUrl: "/", allowCanceling: true, showFileList: true, progress: 0, readyToUploadMessage: messageLocalization.format("dxFileUploader-readyToUpload"), uploadedMessage: messageLocalization.format("dxFileUploader-uploaded"), uploadFailedMessage: messageLocalization.format("dxFileUploader-uploadFailedMessage"), uploadMode: "instantly", uploadMethod: "POST", uploadHeaders: {}, onUploadStarted: null, onUploaded: null, onProgress: null, onUploadError: null, onUploadAborted: null, allowedFileExtensions: [], maxFileSize: 0, minFileSize: 0, invalidFileExtensionMessage: messageLocalization.format("dxFileUploader-invalidFileExtension"), invalidMaxFileSizeMessage: messageLocalization.format("dxFileUploader-invalidMaxFileSize"), invalidMinFileSizeMessage: messageLocalization.format("dxFileUploader-invalidMinFileSize"), extendSelection: true, validationMessageMode: "always", validationMessageOffset: { h: 0, v: 0 }, useNativeInputClick: false, useDragOver: true, nativeDropSupported: true, _uploadButtonType: "normal" }) }, _defaultOptionsRules: function() { return this.callBase().concat([{ device: function() { return "desktop" === devices.real().deviceType && !devices.isSimulator() }, options: { focusStateEnabled: true } }, { device: [{ platform: "android" }, { platform: "win" }], options: { validationMessageOffset: { v: 0 } } }, { device: function() { return "generic" !== devices.real().platform }, options: { useDragOver: false } }, { device: function() { return !isFormDataSupported() }, options: { uploadMode: "useForm" } }, { device: function() { return browser.msie || "generic" !== devices.real().platform }, options: { nativeDropSupported: false } }, { device: function() { return themes.isMaterial() }, options: { _uploadButtonType: "default" } }]) }, _init: function() { this.callBase.apply(this, arguments); this._initFileInput(); this._initLabel(); this._createFiles(); this._createUploadStartedAction(); this._createUploadedAction(); this._createProgressAction(); this._createUploadErrorAction(); this._createUploadAbortedAction(); this._setUploadStrategy() }, _setUploadStrategy: function() { this._uploadStrategy = this.option("chunkSize") > 0 ? new ChunksFileUploadStrategy(this) : new WholeFileUploadStrategy(this) }, _initFileInput: function() { this._isCustomClickEvent = false; if (!this._$fileInput) { this._$fileInput = renderFileUploaderInput(); eventsEngine.on(this._$fileInput, "change", this._inputChangeHandler.bind(this)); eventsEngine.on(this._$fileInput, "click", function(e) { e.stopPropagation(); return this.option("useNativeInputClick") || this._isCustomClickEvent }.bind(this)) } this._$fileInput.prop({ multiple: this.option("multiple"), accept: this.option("accept"), tabIndex: -1 }) }, _inputChangeHandler: function() { if (this._doPreventInputChange) { return } var fileName = this._$fileInput.val().replace(/^.*\\/, ""); var files = this._$fileInput.prop("files"); if (files && !files.length) { return } var value = files ? this._getFiles(files) : [{ name: fileName }]; this._changeValue(value); if ("instantly" === this.option("uploadMode")) { this._uploadFiles() } }, _shouldFileListBeExtended: function() { return "useForm" !== this.option("uploadMode") && this.option("extendSelection") && this.option("multiple") }, _removeDuplicates: function(files, value) { var result = []; for (var i = 0; i < value.length; i++) { if (!this._isFileInArray(files, value[i])) { result.push(value[i]) } } return result }, _isFileInArray: function(files, file) { for (var i = 0; i < files.length; i++) { var item = files[i]; if (item.size === file.size && item.name === file.name) { return true } } return false }, _changeValue: function(value) { var files = this._shouldFileListBeExtended() ? this.option("value").slice() : []; if ("instantly" !== this.option("uploadMode")) { value = this._removeDuplicates(files, value) } this.option("value", files.concat(value)) }, _getFiles: function(fileList) { var values = []; each(fileList, function(_, value) { values.push(value) }); return values }, _initLabel: function() { if (!this._$inputLabel) { this._$inputLabel = $("