devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
1,119 lines (1,115 loc) • 70.9 kB
JavaScript
/**
* DevExtreme (cjs/ui/file_uploader.js)
* Version: 23.2.6
* Build date: Wed May 01 2024
*
* Copyright (c) 2012 - 2024 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
exports.default = void 0;
var _size = require("../core/utils/size");
var _renderer = _interopRequireDefault(require("../core/renderer"));
var _guid = _interopRequireDefault(require("../core/guid"));
var _window = require("../core/utils/window");
var _events_engine = _interopRequireDefault(require("../events/core/events_engine"));
var _component_registrator = _interopRequireDefault(require("../core/component_registrator"));
var _callbacks = _interopRequireDefault(require("../core/utils/callbacks"));
var _type = require("../core/utils/type");
var _iterator = require("../core/utils/iterator");
var _extend = require("../core/utils/extend");
var _deferred = require("../core/utils/deferred");
var _ajax = _interopRequireDefault(require("../core/utils/ajax"));
var _editor = _interopRequireDefault(require("./editor/editor"));
var _button = _interopRequireDefault(require("./button"));
var _progress_bar = _interopRequireDefault(require("./progress_bar"));
var _devices = _interopRequireDefault(require("../core/devices"));
var _index = require("../events/utils/index");
var _click = require("../events/click");
var _message = _interopRequireDefault(require("../localization/message"));
var _themes = require("./themes");
var _dom_adapter = _interopRequireDefault(require("../core/dom_adapter"));
function _interopRequireDefault(obj) {
return obj && obj.__esModule ? obj : {
default: obj
}
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass)
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function(o, p) {
o.__proto__ = p;
return o
};
return _setPrototypeOf(o, p)
}
const window = (0, _window.getWindow)();
const FILEUPLOADER_CLASS = "dx-fileuploader";
const FILEUPLOADER_EMPTY_CLASS = "dx-fileuploader-empty";
const FILEUPLOADER_SHOW_FILE_LIST_CLASS = "dx-fileuploader-show-file-list";
const FILEUPLOADER_DRAGOVER_CLASS = "dx-fileuploader-dragover";
const FILEUPLOADER_WRAPPER_CLASS = "dx-fileuploader-wrapper";
const FILEUPLOADER_CONTAINER_CLASS = "dx-fileuploader-container";
const FILEUPLOADER_CONTENT_CLASS = "dx-fileuploader-content";
const FILEUPLOADER_INPUT_WRAPPER_CLASS = "dx-fileuploader-input-wrapper";
const FILEUPLOADER_INPUT_CONTAINER_CLASS = "dx-fileuploader-input-container";
const FILEUPLOADER_INPUT_LABEL_CLASS = "dx-fileuploader-input-label";
const FILEUPLOADER_INPUT_CLASS = "dx-fileuploader-input";
const FILEUPLOADER_FILES_CONTAINER_CLASS = "dx-fileuploader-files-container";
const FILEUPLOADER_FILE_CONTAINER_CLASS = "dx-fileuploader-file-container";
const FILEUPLOADER_FILE_INFO_CLASS = "dx-fileuploader-file-info";
const FILEUPLOADER_FILE_STATUS_MESSAGE_CLASS = "dx-fileuploader-file-status-message";
const FILEUPLOADER_FILE_CLASS = "dx-fileuploader-file";
const FILEUPLOADER_FILE_NAME_CLASS = "dx-fileuploader-file-name";
const FILEUPLOADER_FILE_SIZE_CLASS = "dx-fileuploader-file-size";
const FILEUPLOADER_BUTTON_CLASS = "dx-fileuploader-button";
const FILEUPLOADER_BUTTON_CONTAINER_CLASS = "dx-fileuploader-button-container";
const FILEUPLOADER_CANCEL_BUTTON_CLASS = "dx-fileuploader-cancel-button";
const FILEUPLOADER_UPLOAD_BUTTON_CLASS = "dx-fileuploader-upload-button";
const FILEUPLOADER_INVALID_CLASS = "dx-fileuploader-invalid";
const FILEUPLOADER_AFTER_LOAD_DELAY = 400;
const FILEUPLOADER_CHUNK_META_DATA_NAME = "chunkMetadata";
const DRAG_EVENT_DELTA = 1;
let renderFileUploaderInput = () => (0, _renderer.default)("<input>").attr("type", "file");
const isFormDataSupported = () => !!window.FormData;
let FileUploader = function(_Editor) {
_inheritsLoose(FileUploader, _Editor);
function FileUploader() {
return _Editor.apply(this, arguments) || this
}
var _proto = FileUploader.prototype;
_proto._supportedKeys = function() {
const click = e => {
e.preventDefault();
const $selectButton = this._selectButton.$element();
_events_engine.default.trigger($selectButton, _click.name)
};
return (0, _extend.extend)(_Editor.prototype._supportedKeys.call(this), {
space: click,
enter: click
})
};
_proto._setOptionsByReference = function() {
_Editor.prototype._setOptionsByReference.call(this);
(0, _extend.extend)(this._optionsByReference, {
value: true
})
};
_proto._getDefaultOptions = function() {
return (0, _extend.extend)(_Editor.prototype._getDefaultOptions.call(this), {
chunkSize: 0,
value: [],
selectButtonText: _message.default.format("dxFileUploader-selectFile"),
uploadButtonText: _message.default.format("dxFileUploader-upload"),
labelText: _message.default.format("dxFileUploader-dropFile"),
name: "files[]",
multiple: false,
accept: "",
uploadUrl: "/",
allowCanceling: true,
showFileList: true,
progress: 0,
dialogTrigger: void 0,
dropZone: void 0,
readyToUploadMessage: _message.default.format("dxFileUploader-readyToUpload"),
uploadedMessage: _message.default.format("dxFileUploader-uploaded"),
uploadFailedMessage: _message.default.format("dxFileUploader-uploadFailedMessage"),
uploadAbortedMessage: _message.default.format("dxFileUploader-uploadAbortedMessage"),
uploadMode: "instantly",
uploadMethod: "POST",
uploadHeaders: {},
uploadCustomData: {},
onBeforeSend: null,
onUploadStarted: null,
onUploaded: null,
onFilesUploaded: null,
onProgress: null,
onUploadError: null,
onUploadAborted: null,
onDropZoneEnter: null,
onDropZoneLeave: null,
allowedFileExtensions: [],
maxFileSize: 0,
minFileSize: 0,
inputAttr: {},
invalidFileExtensionMessage: _message.default.format("dxFileUploader-invalidFileExtension"),
invalidMaxFileSizeMessage: _message.default.format("dxFileUploader-invalidMaxFileSize"),
invalidMinFileSizeMessage: _message.default.format("dxFileUploader-invalidMinFileSize"),
extendSelection: true,
validationMessageMode: "always",
uploadFile: null,
uploadChunk: null,
abortUpload: null,
validationMessageOffset: {
h: 0,
v: 0
},
hoverStateEnabled: true,
useNativeInputClick: false,
useDragOver: true,
nativeDropSupported: true,
_uploadButtonType: "normal",
_buttonStylingMode: "contained"
})
};
_proto._defaultOptionsRules = function() {
return _Editor.prototype._defaultOptionsRules.call(this).concat([{
device: () => "desktop" === _devices.default.real().deviceType && !_devices.default.isSimulator(),
options: {
focusStateEnabled: true
}
}, {
device: [{
platform: "android"
}],
options: {
validationMessageOffset: {
v: 0
}
}
}, {
device: () => "desktop" !== _devices.default.real().deviceType,
options: {
useDragOver: false
}
}, {
device: () => !isFormDataSupported(),
options: {
uploadMode: "useForm"
}
}, {
device: () => "desktop" !== _devices.default.real().deviceType,
options: {
nativeDropSupported: false
}
}, {
device: () => (0, _themes.isMaterial)(),
options: {
_uploadButtonType: "default"
}
}, {
device: () => (0, _themes.isFluent)(),
options: {
_buttonStylingMode: "text"
}
}])
};
_proto._initOptions = function(options) {
const isLabelTextDefined = "labelText" in options;
_Editor.prototype._initOptions.call(this, options);
if (!isLabelTextDefined && !this._shouldDragOverBeRendered()) {
this.option("labelText", "")
}
};
_proto._init = function() {
_Editor.prototype._init.call(this);
this._initFileInput();
this._initLabel();
this._setUploadStrategy();
this._createFiles();
this._createBeforeSendAction();
this._createUploadStartedAction();
this._createUploadedAction();
this._createFilesUploadedAction();
this._createProgressAction();
this._createUploadErrorAction();
this._createUploadAbortedAction();
this._createDropZoneEnterAction();
this._createDropZoneLeaveAction()
};
_proto._setUploadStrategy = function() {
let strategy = null;
if (this.option("chunkSize") > 0) {
const uploadChunk = this.option("uploadChunk");
strategy = uploadChunk && (0, _type.isFunction)(uploadChunk) ? new CustomChunksFileUploadStrategy(this) : new DefaultChunksFileUploadStrategy(this)
} else {
const uploadFile = this.option("uploadFile");
strategy = uploadFile && (0, _type.isFunction)(uploadFile) ? new CustomWholeFileUploadStrategy(this) : new DefaultWholeFileUploadStrategy(this)
}
this._uploadStrategy = strategy
};
_proto._initFileInput = function() {
this._isCustomClickEvent = false;
const {
multiple: multiple,
accept: accept,
hint: hint
} = this.option();
if (!this._$fileInput) {
this._$fileInput = renderFileUploaderInput();
_events_engine.default.on(this._$fileInput, "change", this._inputChangeHandler.bind(this));
_events_engine.default.on(this._$fileInput, "click", e => {
e.stopPropagation();
this._resetInputValue();
return this.option("useNativeInputClick") || this._isCustomClickEvent
})
}
const inputProps = {
multiple: multiple,
accept: accept,
tabIndex: -1
};
if ((0, _type.isDefined)(hint)) {
inputProps.title = hint
}
this._$fileInput.prop(inputProps)
};
_proto._inputChangeHandler = function() {
if (this._doPreventInputChange) {
return
}
const fileName = this._$fileInput.val().replace(/^.*\\/, "");
const files = this._$fileInput.prop("files");
if (files && !files.length && "useForm" !== this.option("uploadMode")) {
return
}
const value = files ? this._getFiles(files) : [{
name: fileName
}];
this._changeValue(value);
if ("instantly" === this.option("uploadMode")) {
this._uploadFiles()
}
};
_proto._shouldFileListBeExtended = function() {
return "useForm" !== this.option("uploadMode") && this.option("extendSelection") && this.option("multiple")
};
_proto._changeValue = function(value) {
const files = this._shouldFileListBeExtended() ? this.option("value").slice() : [];
this.option("value", files.concat(value))
};
_proto._getFiles = function(fileList) {
const values = [];
(0, _iterator.each)(fileList, (_, value) => values.push(value));
return values
};
_proto._getFile = function(fileData) {
const targetFileValue = (0, _type.isNumeric)(fileData) ? this.option("value")[fileData] : fileData;
return this._files.filter(file => file.value === targetFileValue)[0]
};
_proto._initLabel = function() {
if (!this._$inputLabel) {
this._$inputLabel = (0, _renderer.default)("<div>")
}
this._updateInputLabelText()
};
_proto._updateInputLabelText = function() {
const correctedValue = this._isInteractionDisabled() ? "" : this.option("labelText");
this._$inputLabel.text(correctedValue)
};
_proto._focusTarget = function() {
return this.$element().find(".dx-fileuploader-button")
};
_proto._getSubmitElement = function() {
return this._$fileInput
};
_proto._initMarkup = function() {
_Editor.prototype._initMarkup.call(this);
this.$element().addClass("dx-fileuploader");
this._renderWrapper();
this._renderInputWrapper();
this._renderSelectButton();
this._renderInputContainer();
this._renderUploadButton();
this._preventRecreatingFiles = true;
this._activeDropZone = null
};
_proto._render = function() {
this._preventRecreatingFiles = false;
this._attachDragEventHandlers(this._$inputWrapper);
this._attachDragEventHandlers(this.option("dropZone"));
this._renderFiles();
_Editor.prototype._render.call(this)
};
_proto._createFileProgressBar = function(file) {
file.progressBar = this._createProgressBar(file.value.size);
file.progressBar.$element().appendTo(file.$file);
this._initStatusMessage(file);
this._ensureCancelButtonInitialized(file)
};
_proto._setStatusMessage = function(file, message) {
setTimeout(() => {
if (this.option("showFileList")) {
if (file.$statusMessage) {
file.$statusMessage.text(message);
file.$statusMessage.css("display", "");
file.progressBar.$element().remove()
}
}
}, 400)
};
_proto._getUploadAbortedStatusMessage = function() {
return "instantly" === this.option("uploadMode") ? this.option("uploadAbortedMessage") : this.option("readyToUploadMessage")
};
_proto._createFiles = function() {
const value = this.option("value");
if (this._files && (0 === value.length || !this._shouldFileListBeExtended())) {
this._preventFilesUploading(this._files);
this._files = null
}
if (!this._files) {
this._files = []
}(0, _iterator.each)(value.slice(this._files.length), (_, value) => {
const file = this._createFile(value);
this._validateFile(file);
this._files.push(file)
})
};
_proto._preventFilesUploading = function(files) {
files.forEach(file => this._uploadStrategy.abortUpload(file))
};
_proto._validateFile = function(file) {
file.isValidFileExtension = this._validateFileExtension(file);
file.isValidMinSize = this._validateMinFileSize(file);
file.isValidMaxSize = this._validateMaxFileSize(file)
};
_proto._validateFileExtension = function(file) {
const allowedExtensions = this.option("allowedFileExtensions");
const accept = this.option("accept");
const allowedTypes = this._getAllowedFileTypes(accept);
const fileExtension = file.value.name.substring(file.value.name.lastIndexOf(".")).toLowerCase();
if (0 !== accept.length && !this._isFileTypeAllowed(file.value, allowedTypes)) {
return false
}
if (0 === allowedExtensions.length) {
return true
}
for (let i = 0; i < allowedExtensions.length; i++) {
if (fileExtension === allowedExtensions[i].toLowerCase()) {
return true
}
}
return false
};
_proto._validateMaxFileSize = function(file) {
const fileSize = file.value.size;
const maxFileSize = this.option("maxFileSize");
return maxFileSize > 0 ? fileSize <= maxFileSize : true
};
_proto._validateMinFileSize = function(file) {
const fileSize = file.value.size;
const minFileSize = this.option("minFileSize");
return minFileSize > 0 ? fileSize >= minFileSize : true
};
_proto._createBeforeSendAction = function() {
this._beforeSendAction = this._createActionByOption("onBeforeSend", {
excludeValidators: ["readOnly"]
})
};
_proto._createUploadStartedAction = function() {
this._uploadStartedAction = this._createActionByOption("onUploadStarted", {
excludeValidators: ["readOnly"]
})
};
_proto._createUploadedAction = function() {
this._uploadedAction = this._createActionByOption("onUploaded", {
excludeValidators: ["readOnly"]
})
};
_proto._createFilesUploadedAction = function() {
this._filesUploadedAction = this._createActionByOption("onFilesUploaded", {
excludeValidators: ["readOnly"]
})
};
_proto._createProgressAction = function() {
this._progressAction = this._createActionByOption("onProgress", {
excludeValidators: ["readOnly"]
})
};
_proto._createUploadAbortedAction = function() {
this._uploadAbortedAction = this._createActionByOption("onUploadAborted", {
excludeValidators: ["readOnly"]
})
};
_proto._createUploadErrorAction = function() {
this._uploadErrorAction = this._createActionByOption("onUploadError", {
excludeValidators: ["readOnly"]
})
};
_proto._createDropZoneEnterAction = function() {
this._dropZoneEnterAction = this._createActionByOption("onDropZoneEnter")
};
_proto._createDropZoneLeaveAction = function() {
this._dropZoneLeaveAction = this._createActionByOption("onDropZoneLeave")
};
_proto._createFile = function(value) {
return {
value: value,
loadedSize: 0,
onProgress: (0, _callbacks.default)(),
onAbort: (0, _callbacks.default)(),
onLoad: (0, _callbacks.default)(),
onError: (0, _callbacks.default)(),
onLoadStart: (0, _callbacks.default)(),
isValidFileExtension: true,
isValidMaxSize: true,
isValidMinSize: true,
isValid() {
return this.isValidFileExtension && this.isValidMaxSize && this.isValidMinSize
},
isInitialized: false
}
};
_proto._resetFileState = function(file) {
file.isAborted = false;
file.uploadStarted = false;
file.isStartLoad = false;
file.loadedSize = 0;
file.chunksData = void 0;
file.request = void 0
};
_proto._renderFiles = function() {
var _this$_validationMess;
const value = this.option("value");
if (!this._$filesContainer) {
this._$filesContainer = (0, _renderer.default)("<div>").addClass("dx-fileuploader-files-container").appendTo(this._$content)
} else if (!this._shouldFileListBeExtended() || 0 === value.length) {
this._$filesContainer.empty()
}
const showFileList = this.option("showFileList");
if (showFileList) {
(0, _iterator.each)(this._files, (_, file) => {
if (!file.$file) {
this._renderFile(file)
}
})
}
this.$element().toggleClass("dx-fileuploader-show-file-list", showFileList);
this._toggleFileUploaderEmptyClassName();
this._updateFileNameMaxWidth();
null === (_this$_validationMess = this._validationMessage) || void 0 === _this$_validationMess ? void 0 : _this$_validationMess.repaint()
};
_proto._renderFile = function(file) {
const value = file.value;
const $fileContainer = (0, _renderer.default)("<div>").addClass("dx-fileuploader-file-container").appendTo(this._$filesContainer);
this._renderFileButtons(file, $fileContainer);
file.$file = (0, _renderer.default)("<div>").addClass("dx-fileuploader-file").appendTo($fileContainer);
const $fileInfo = (0, _renderer.default)("<div>").addClass("dx-fileuploader-file-info").appendTo(file.$file);
file.$statusMessage = (0, _renderer.default)("<div>").addClass("dx-fileuploader-file-status-message").appendTo(file.$file);
(0, _renderer.default)("<div>").addClass("dx-fileuploader-file-name").text(value.name).appendTo($fileInfo);
if ((0, _type.isDefined)(value.size)) {
(0, _renderer.default)("<div>").addClass("dx-fileuploader-file-size").text(this._getFileSize(value.size)).appendTo($fileInfo)
}
if (file.isValid()) {
file.$statusMessage.text(this.option("readyToUploadMessage"))
} else {
if (!file.isValidFileExtension) {
file.$statusMessage.append(this._createValidationElement("invalidFileExtensionMessage"))
}
if (!file.isValidMaxSize) {
file.$statusMessage.append(this._createValidationElement("invalidMaxFileSizeMessage"))
}
if (!file.isValidMinSize) {
file.$statusMessage.append(this._createValidationElement("invalidMinFileSizeMessage"))
}
$fileContainer.addClass("dx-fileuploader-invalid")
}
};
_proto._createValidationElement = function(key) {
return (0, _renderer.default)("<span>").text(this.option(key))
};
_proto._updateFileNameMaxWidth = function() {
const cancelButtonsCount = this.option("allowCanceling") && "useForm" !== this.option("uploadMode") ? 1 : 0;
const uploadButtonsCount = "useButtons" === this.option("uploadMode") ? 1 : 0;
const filesContainerWidth = (0, _size.getWidth)(this._$filesContainer.find(".dx-fileuploader-file-container").first()) || (0, _size.getWidth)(this._$filesContainer);
const $buttonContainer = this._$filesContainer.find(".dx-fileuploader-button-container").eq(0);
const buttonsWidth = (0, _size.getWidth)($buttonContainer) * (cancelButtonsCount + uploadButtonsCount);
const $fileSize = this._$filesContainer.find(".dx-fileuploader-file-size").eq(0);
const prevFileSize = $fileSize.text();
$fileSize.text("1000 Mb");
const fileSizeWidth = (0, _size.getWidth)($fileSize);
$fileSize.text(prevFileSize);
this._$filesContainer.find(".dx-fileuploader-file-name").css("maxWidth", filesContainerWidth - buttonsWidth - fileSizeWidth)
};
_proto._renderFileButtons = function(file, $container) {
const $cancelButton = this._getCancelButton(file);
$cancelButton && $container.append($cancelButton);
const $uploadButton = this._getUploadButton(file);
$uploadButton && $container.append($uploadButton)
};
_proto._getCancelButton = function(file) {
if ("useForm" === this.option("uploadMode")) {
return null
}
const {
allowCanceling: allowCanceling,
readOnly: readOnly,
hoverStateEnabled: hoverStateEnabled,
_buttonStylingMode: _buttonStylingMode
} = this.option();
file.cancelButton = this._createComponent((0, _renderer.default)("<div>").addClass("dx-fileuploader-button dx-fileuploader-cancel-button"), _button.default, {
onClick: () => this._removeFile(file),
icon: "close",
visible: allowCanceling,
disabled: readOnly,
integrationOptions: {},
hoverStateEnabled: hoverStateEnabled,
stylingMode: _buttonStylingMode
});
return (0, _renderer.default)("<div>").addClass("dx-fileuploader-button-container").append(file.cancelButton.$element())
};
_proto._getUploadButton = function(file) {
if (!file.isValid() || "useButtons" !== this.option("uploadMode")) {
return null
}
const {
hoverStateEnabled: hoverStateEnabled,
_buttonStylingMode: _buttonStylingMode
} = this.option();
file.uploadButton = this._createComponent((0, _renderer.default)("<div>").addClass("dx-fileuploader-button dx-fileuploader-upload-button"), _button.default, {
onClick: () => this._uploadFile(file),
icon: "upload",
hoverStateEnabled: hoverStateEnabled,
stylingMode: _buttonStylingMode
});
file.onLoadStart.add(() => file.uploadButton.option({
visible: false,
disabled: true
}));
file.onAbort.add(() => file.uploadButton.option({
visible: true,
disabled: false
}));
return (0, _renderer.default)("<div>").addClass("dx-fileuploader-button-container").append(file.uploadButton.$element())
};
_proto._removeFile = function(file) {
var _file$$file;
null === (_file$$file = file.$file) || void 0 === _file$$file ? void 0 : _file$$file.parent().remove();
this._files.splice(this._files.indexOf(file), 1);
const value = this.option("value").slice();
value.splice(value.indexOf(file.value), 1);
this._preventRecreatingFiles = true;
this.option("value", value);
this._preventRecreatingFiles = false;
this._toggleFileUploaderEmptyClassName();
this._resetInputValue(true)
};
_proto.removeFile = function(fileData) {
if ("useForm" === this.option("uploadMode") || !(0, _type.isDefined)(fileData)) {
return
}
const file = this._getFile(fileData);
if (file) {
if (file.uploadStarted) {
this._preventFilesUploading([file])
}
this._removeFile(file)
}
};
_proto._toggleFileUploaderEmptyClassName = function() {
this.$element().toggleClass("dx-fileuploader-empty", !this._files.length || this._hasInvalidFile(this._files))
};
_proto._hasInvalidFile = function(files) {
for (let i = 0; i < files.length; i++) {
if (!files[i].isValid()) {
return true
}
}
return false
};
_proto._getFileSize = function(size) {
let i = 0;
const labels = [_message.default.format("dxFileUploader-bytes"), _message.default.format("dxFileUploader-kb"), _message.default.format("dxFileUploader-Mb"), _message.default.format("dxFileUploader-Gb")];
const count = labels.length - 1;
while (i < count && size >= 1024) {
size /= 1024;
i++
}
return Math.round(size) + " " + labels[i]
};
_proto._renderSelectButton = function() {
const $button = (0, _renderer.default)("<div>").addClass("dx-fileuploader-button").appendTo(this._$inputWrapper);
this._selectButton = this._createComponent($button, _button.default, {
text: this.option("selectButtonText"),
focusStateEnabled: false,
integrationOptions: {},
disabled: this.option("readOnly"),
hoverStateEnabled: this.option("hoverStateEnabled")
});
this._selectFileDialogHandler = this._selectButtonClickHandler.bind(this);
if ("desktop" === _devices.default.real().deviceType) {
this._selectButton.option("onClick", this._selectFileDialogHandler)
} else {
this._attachSelectFileDialogHandler(this._selectButton.$element())
}
this._attachSelectFileDialogHandler(this.option("dialogTrigger"))
};
_proto._selectButtonClickHandler = function() {
if (this.option("useNativeInputClick")) {
return
}
if (this._isInteractionDisabled()) {
return false
}
this._isCustomClickEvent = true;
_events_engine.default.trigger(this._$fileInput, "click");
this._isCustomClickEvent = false
};
_proto._attachSelectFileDialogHandler = function(target) {
if (!(0, _type.isDefined)(target)) {
return
}
this._detachSelectFileDialogHandler(target);
_events_engine.default.on((0, _renderer.default)(target), "click", this._selectFileDialogHandler)
};
_proto._detachSelectFileDialogHandler = function(target) {
if (!(0, _type.isDefined)(target)) {
return
}
_events_engine.default.off((0, _renderer.default)(target), "click", this._selectFileDialogHandler)
};
_proto._renderUploadButton = function() {
if ("useButtons" !== this.option("uploadMode")) {
return
}
const $uploadButton = (0, _renderer.default)("<div>").addClass("dx-fileuploader-button").addClass("dx-fileuploader-upload-button").appendTo(this._$content);
this._uploadButton = this._createComponent($uploadButton, _button.default, {
text: this.option("uploadButtonText"),
onClick: this._uploadButtonClickHandler.bind(this),
type: this.option("_uploadButtonType"),
integrationOptions: {},
hoverStateEnabled: this.option("hoverStateEnabled")
})
};
_proto._uploadButtonClickHandler = function() {
this._uploadFiles()
};
_proto._shouldDragOverBeRendered = function() {
return !this.option("readOnly") && ("useForm" !== this.option("uploadMode") || this.option("nativeDropSupported"))
};
_proto._isInteractionDisabled = function() {
return this.option("readOnly") || this.option("disabled")
};
_proto._renderInputContainer = function() {
this._$inputContainer = (0, _renderer.default)("<div>").addClass("dx-fileuploader-input-container").appendTo(this._$inputWrapper);
this._$fileInput.addClass("dx-fileuploader-input");
this._renderInput();
const labelId = "dx-fileuploader-input-label-".concat(new _guid.default);
this._$inputLabel.attr("id", labelId).addClass("dx-fileuploader-input-label").appendTo(this._$inputContainer);
this.setAria("labelledby", labelId, this._$fileInput)
};
_proto._renderInput = function() {
if (this.option("useNativeInputClick")) {
this._selectButton.option("template", this._selectButtonInputTemplate.bind(this))
} else {
this._$fileInput.appendTo(this._$inputContainer);
this._selectButton.option("template", "content")
}
this._applyInputAttributes(this.option("inputAttr"))
};
_proto._selectButtonInputTemplate = function(data, content) {
const $content = (0, _renderer.default)(content);
const $text = (0, _renderer.default)("<span>").addClass("dx-button-text").text(data.text);
$content.append($text).append(this._$fileInput);
return $content
};
_proto._renderInputWrapper = function() {
this._$inputWrapper = (0, _renderer.default)("<div>").addClass("dx-fileuploader-input-wrapper").appendTo(this._$content)
};
_proto._detachDragEventHandlers = function(target) {
if (!(0, _type.isDefined)(target)) {
return
}
_events_engine.default.off((0, _renderer.default)(target), (0, _index.addNamespace)("", this.NAME))
};
_proto._attachDragEventHandlers = function(target) {
const isCustomTarget = target !== this._$inputWrapper;
if (!(0, _type.isDefined)(target) || !this._shouldDragOverBeRendered()) {
return
}
this._detachDragEventHandlers(target);
target = (0, _renderer.default)(target);
_events_engine.default.on(target, (0, _index.addNamespace)("dragenter", this.NAME), this._dragEnterHandler.bind(this, isCustomTarget));
_events_engine.default.on(target, (0, _index.addNamespace)("dragover", this.NAME), this._dragOverHandler.bind(this, isCustomTarget));
_events_engine.default.on(target, (0, _index.addNamespace)("dragleave", this.NAME), this._dragLeaveHandler.bind(this, isCustomTarget));
_events_engine.default.on(target, (0, _index.addNamespace)("drop", this.NAME), this._dropHandler.bind(this, isCustomTarget))
};
_proto._applyInputAttributes = function(customAttributes) {
this._$fileInput.attr(customAttributes)
};
_proto._useInputForDrop = function() {
return this.option("nativeDropSupported") && "useForm" === this.option("uploadMode")
};
_proto._getDropZoneElement = function(isCustomTarget, e) {
let targetList = isCustomTarget ? Array.from((0, _renderer.default)(this.option("dropZone"))) : [this._$inputWrapper];
targetList = targetList.map(element => (0, _renderer.default)(element).get(0));
return targetList[targetList.indexOf(e.currentTarget)]
};
_proto._dragEnterHandler = function(isCustomTarget, e) {
if (this.option("disabled")) {
return false
}
if (!this._useInputForDrop()) {
e.preventDefault()
}
const dropZoneElement = this._getDropZoneElement(isCustomTarget, e);
if ((0, _type.isDefined)(dropZoneElement) && this._shouldRaiseDragOver(e, dropZoneElement)) {
this._activeDropZone = dropZoneElement;
this._tryToggleDropZoneActive(true, isCustomTarget, e)
}
};
_proto._shouldRaiseDragOver = function(e, dropZoneElement) {
return null === this._activeDropZone && this.isMouseOverElement(e, dropZoneElement, false) && e.originalEvent.dataTransfer.types.find(item => "Files" === item)
};
_proto._dragOverHandler = function(isCustomTarget, e) {
if (!this._useInputForDrop()) {
e.preventDefault()
}
e.originalEvent.dataTransfer.dropEffect = "copy";
if (!isCustomTarget) {
const dropZoneElement = this._getDropZoneElement(false, e);
if (this._shouldRaiseDragOver(e, dropZoneElement)) {
this._dragEnterHandler(false, e)
}
if (this._shouldRaiseDragLeave(e, false)) {
this._dragLeaveHandler(false, e)
}
}
};
_proto._dragLeaveHandler = function(isCustomTarget, e) {
if (!this._useInputForDrop()) {
e.preventDefault()
}
if (this._shouldRaiseDragLeave(e, isCustomTarget)) {
this._tryToggleDropZoneActive(false, isCustomTarget, e);
this._activeDropZone = null
}
};
_proto._shouldRaiseDragLeave = function(e, isCustomTarget) {
return null !== this._activeDropZone && !this.isMouseOverElement(e, this._activeDropZone, !isCustomTarget, -1)
};
_proto._tryToggleDropZoneActive = function(active, isCustom, event) {
const classAction = active ? "addClass" : "removeClass";
const mouseAction = active ? "_dropZoneEnterAction" : "_dropZoneLeaveAction";
this[mouseAction]({
event: event,
dropZoneElement: this._activeDropZone
});
if (!isCustom) {
this.$element()[classAction]("dx-fileuploader-dragover")
}
};
_proto._dropHandler = function(isCustomTarget, e) {
this._activeDropZone = null;
if (!isCustomTarget) {
this.$element().removeClass("dx-fileuploader-dragover")
}
if (this._useInputForDrop() || isCustomTarget && this._isInteractionDisabled()) {
return
}
e.preventDefault();
const fileList = e.originalEvent.dataTransfer.files;
const files = this._getFiles(fileList);
if (!this.option("multiple") && files.length > 1 || 0 === files.length) {
return
}
this._changeValue(files);
if ("instantly" === this.option("uploadMode")) {
this._uploadFiles()
}
};
_proto._areAllFilesLoaded = function() {
return this._files.every(file => !file.isValid() || file._isError || file._isLoaded || file.isAborted)
};
_proto._handleAllFilesUploaded = function() {
this._recalculateProgress();
if (this._areAllFilesLoaded()) {
this._filesUploadedAction()
}
};
_proto._getAllowedFileTypes = function(acceptSting) {
if (!acceptSting.length) {
return []
}
return acceptSting.split(",").map(item => item.trim())
};
_proto._isFileTypeAllowed = function(file, allowedTypes) {
for (let i = 0, n = allowedTypes.length; i < n; i++) {
let allowedType = allowedTypes[i];
if ("." === allowedType[0]) {
allowedType = allowedType.replace(".", "\\.");
if (file.name.match(new RegExp(allowedType + "$", "i"))) {
return true
}
} else {
allowedType = allowedType.replace(new RegExp("\\*", "g"), "");
if (file.type.match(new RegExp(allowedType, "i"))) {
return true
}
}
}
return false
};
_proto._renderWrapper = function() {
const $wrapper = (0, _renderer.default)("<div>").addClass("dx-fileuploader-wrapper").appendTo(this.$element());
const $container = (0, _renderer.default)("<div>").addClass("dx-fileuploader-container").appendTo($wrapper);
this._$content = (0, _renderer.default)("<div>").addClass("dx-fileuploader-content").appendTo($container)
};
_proto._clean = function() {
this._$fileInput.detach();
delete this._$filesContainer;
this._detachSelectFileDialogHandler(this.option("dialogTrigger"));
this._detachDragEventHandlers(this.option("dropZone"));
if (this._files) {
this._files.forEach(file => {
file.$file = null;
file.$statusMessage = null
})
}
_Editor.prototype._clean.call(this)
};
_proto.abortUpload = function(fileData) {
if ("useForm" === this.option("uploadMode")) {
return
}
if ((0, _type.isDefined)(fileData)) {
const file = this._getFile(fileData);
if (file) {
this._preventFilesUploading([file])
}
} else {
this._preventFilesUploading(this._files)
}
};
_proto.upload = function(fileData) {
if ("useForm" === this.option("uploadMode")) {
return
}
if ((0, _type.isDefined)(fileData)) {
const file = this._getFile(fileData);
if (file && isFormDataSupported()) {
this._uploadFile(file)
}
} else {
this._uploadFiles()
}
};
_proto._uploadFiles = function() {
if (isFormDataSupported()) {
(0, _iterator.each)(this._files, (_, file) => this._uploadFile(file))
}
};
_proto._uploadFile = function(file) {
this._uploadStrategy.upload(file)
};
_proto._updateProgressBar = function(file, loadedFileData) {
file.progressBar && file.progressBar.option({
value: loadedFileData.loaded,
showStatus: true
});
this._progressAction({
file: file.value,
segmentSize: loadedFileData.currentSegmentSize,
bytesLoaded: loadedFileData.loaded,
bytesTotal: loadedFileData.total,
event: loadedFileData.event,
request: file.request
})
};
_proto._updateTotalProgress = function(totalFilesSize, totalLoadedFilesSize) {
let progress = 0;
if ((0, _type.isDefined)(totalFilesSize)) {
if (this._files.length > 0 && this._areAllFilesLoaded() && 0 === totalFilesSize && 0 === totalLoadedFilesSize) {
progress = this._getProgressValue(1)
} else if (totalFilesSize) {
progress = this._getProgressValue(totalLoadedFilesSize / totalFilesSize)
}
}
this.option("progress", progress);
this._setLoadedSize(totalLoadedFilesSize)
};
_proto._getProgressValue = function(ratio) {
return Math.floor(100 * ratio)
};
_proto._initStatusMessage = function(file) {
file.$statusMessage.css("display", "none")
};
_proto._ensureCancelButtonInitialized = function(file) {
if (file.isInitialized) {
return
}
file.cancelButton.option("onClick", () => {
this._preventFilesUploading([file]);
this._removeFile(file)
});
const hideCancelButton = () => {
setTimeout(() => {
file.cancelButton.option({
visible: false
})
}, 400)
};
file.onLoad.add(hideCancelButton);
file.onError.add(hideCancelButton)
};
_proto._createProgressBar = function(fileSize) {
return this._createComponent((0, _renderer.default)("<div>"), _progress_bar.default, {
value: void 0,
min: 0,
max: fileSize,
statusFormat: ratio => this._getProgressValue(ratio) + "%",
showStatus: false,
statusPosition: "right"
})
};
_proto._getTotalFilesSize = function() {
if (!this._totalFilesSize) {
this._totalFilesSize = 0;
(0, _iterator.each)(this._files, (_, file) => {
this._totalFilesSize += file.value.size
})
}
return this._totalFilesSize
};
_proto._getTotalLoadedFilesSize = function() {
if (!this._totalLoadedFilesSize) {
this._totalLoadedFilesSize = 0;
(0, _iterator.each)(this._files, (_, file) => {
this._totalLoadedFilesSize += file.loadedSize
})
}
return this._totalLoadedFilesSize
};
_proto._setLoadedSize = function(value) {
this._totalLoadedFilesSize = value
};
_proto._recalculateProgress = function() {
this._totalFilesSize = 0;
this._totalLoadedFilesSize = 0;
this._updateTotalProgress(this._getTotalFilesSize(), this._getTotalLoadedFilesSize())
};
_proto.isMouseOverElement = function(mouseEvent, element, correctPseudoElements) {
let dragEventDelta = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : 1;
if (!element) {
return false
}
const beforeHeight = correctPseudoElements ? parseFloat(window.getComputedStyle(element, ":before").height) : 0;
const afterHeight = correctPseudoElements ? parseFloat(window.getComputedStyle(element, ":after").height) : 0;
const x = (0, _size.getOffset)(element).left;
const y = (0, _size.getOffset)(element).top + beforeHeight;
const w = element.offsetWidth;
const h = element.offsetHeight - beforeHeight - afterHeight;
const eventX = this._getEventX(mouseEvent);
const eventY = this._getEventY(mouseEvent);
return eventX + dragEventDelta >= x && eventX - dragEventDelta < x + w && eventY + dragEventDelta >= y && eventY - dragEventDelta < y + h
};
_proto._getEventX = function(e) {
return (0, _index.isTouchEvent)(e) ? this._getTouchEventX(e) : e.clientX + this._getDocumentScrollLeft()
};
_proto._getEventY = function(e) {
return (0, _index.isTouchEvent)(e) ? this._getTouchEventY(e) : e.clientY + this._getDocumentScrollTop()
};
_proto._getTouchEventX = function(e) {
let touchPoint = null;
if (e.changedTouches.length > 0) {
touchPoint = e.changedTouches
} else if (e.targetTouches.length > 0) {
touchPoint = e.targetTouches
}
return touchPoint ? touchPoint[0].pageX : 0
};
_proto._getTouchEventY = function(e) {
let touchPoint = null;
if (e.changedTouches.length > 0) {
touchPoint = e.changedTouches
} else if (e.targetTouches.length > 0) {
touchPoint = e.targetTouches
}
return touchPoint ? touchPoint[0].pageY : 0
};
_proto._getDocumentScrollTop = function() {
const document = _dom_adapter.default.getDocument();
return document.documentElement.scrollTop || document.body.scrollTop
};
_proto._getDocumentScrollLeft = function() {
const document = _dom_adapter.default.getDocument();
return document.documentElement.scrollLeft || document.body.scrollLeft
};
_proto._updateReadOnlyState = function() {
const readOnly = this.option("readOnly");
this._selectButton.option("disabled", readOnly);
this._files.forEach(file => {
var _file$cancelButton;
return null === (_file$cancelButton = file.cancelButton) || void 0 === _file$cancelButton ? void 0 : _file$cancelButton.option("disabled", readOnly)
});
this._updateInputLabelText();
this._attachDragEventHandlers(this._$inputWrapper)
};
_proto._updateHoverState = function() {
var _this$_selectButton, _this$_uploadButton;
const value = this.option("hoverStateEnabled");
null === (_this$_selectButton = this._selectButton) || void 0 === _this$_selectButton ? void 0 : _this$_selectButton.option("hoverStateEnabled", value);
null === (_this$_uploadButton = this._uploadButton) || void 0 === _this$_uploadButton ? void 0 : _this$_uploadButton.option("hoverStateEnabled", value);
this._files.forEach(file => {
var _file$uploadButton, _file$cancelButton2;
null === (_file$uploadButton = file.uploadButton) || void 0 === _file$uploadButton ? void 0 : _file$uploadButton.option("hoverStateEnabled", value);
null === (_file$cancelButton2 = file.cancelButton) || void 0 === _file$cancelButton2 ? void 0 : _file$cancelButton2.option("hoverStateEnabled", value)
})
};
_proto._optionChanged = function(args) {
const {
name: name,
value: value,
previousValue: previousValue
} = args;
switch (name) {
case "height":
case "width":
this._updateFileNameMaxWidth();
_Editor.prototype._optionChanged.call(this, args);
break;
case "value":
!value.length && this._$fileInput.val("");
if (!this._preventRecreatingFiles) {
this._createFiles();
this._renderFiles()
}
this._recalculateProgress();
_Editor.prototype._optionChanged.call(this, args);
break;
case "name":
this._initFileInput();
_Editor.prototype._optionChanged.call(this, args);
break;
case "accept":
this._initFileInput();
break;
case "multiple":
this._initFileInput();
if (!args.value) {
this.clear()
}
break;
case "readOnly":
this._updateReadOnlyState();
_Editor.prototype._optionChanged.call(this, args);
break;
case "disabled":
this._updateInputLabelText();
_Editor.prototype._optionChanged.call(this, args);
break;
case "selectButtonText":
this._selectButton.option("text", value);
break;
case "uploadButtonText":
this._uploadButton && this._uploadButton.option("text", value);
break;
case "_uploadButtonType":
this._uploadButton && this._uploadButton.option("type", value);
break;
case "_buttonStylingMode":
this._files.forEach(file => {
var _file$uploadButton2, _file$cancelButton3;
null === (_file$uploadButton2 = file.uploadButton) || void 0 === _file$uploadButton2 ? void 0 : _file$uploadButton2.option("stylingMode", value);
null === (_file$cancelButton3 = file.cancelButton) || void 0 === _file$cancelButton3 ? void 0 : _file$cancelButton3.option("stylingMode", value)
});
break;
case "dialogTrigger":
this._detachSelectFileDialogHandler(previousValue);
this._attachSelectFileDialogHandler(value);
break;
case "dropZone":
this.