UNPKG

devextreme

Version:

JavaScript/TypeScript Component Suite for Responsive Web Development

1,140 lines (1,139 loc) • 65.7 kB
/** * DevExtreme (cjs/__internal/ui/file_uploader/file_uploader.js) * Version: 25.2.5 * Build date: Fri Feb 20 2026 * * Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED * Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/ */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.FILEUPLOADER_CLASS = exports.FILEUPLOADER_CANCEL_BUTTON_POSITION_END_CLASS = exports.FILEUPLOADER_CANCEL_BUTTON_CLASS = void 0; var _events_engine = _interopRequireDefault(require("../../../common/core/events/core/events_engine")); var _index = require("../../../common/core/events/utils/index"); var _message = _interopRequireDefault(require("../../../common/core/localization/message")); var _component_registrator = _interopRequireDefault(require("../../../core/component_registrator")); var _devices = _interopRequireDefault(require("../../../core/devices")); var _dom_adapter = _interopRequireDefault(require("../../../core/dom_adapter")); var _guid = _interopRequireDefault(require("../../../core/guid")); var _renderer = _interopRequireDefault(require("../../../core/renderer")); var _callbacks = _interopRequireDefault(require("../../../core/utils/callbacks")); var _extend = require("../../../core/utils/extend"); var _size = require("../../../core/utils/size"); var _type = require("../../../core/utils/type"); var _window = require("../../../core/utils/window"); var _button = _interopRequireDefault(require("../../../ui/button")); var _progress_bar = _interopRequireDefault(require("../../../ui/progress_bar")); var _themes = require("../../../ui/themes"); var _m_icon = require("../../core/utils/m_icon"); var _editor = _interopRequireDefault(require("../../ui/editor/editor")); var _file_upload_strategyChunks = require("../../ui/file_uploader/file_upload_strategy.chunks.custom"); var _file_upload_strategyChunks2 = require("../../ui/file_uploader/file_upload_strategy.chunks.default"); var _file_upload_strategyWhole = require("../../ui/file_uploader/file_upload_strategy.whole.custom"); var _file_upload_strategyWhole2 = require("../../ui/file_uploader/file_upload_strategy.whole.default"); var _file_uploader = require("../../ui/file_uploader/file_uploader.utils"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e } } const window = (0, _window.getWindow)(); const FILEUPLOADER_CLASS = exports.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_FILE_ICON_CLASS = "dx-fileuploader-file-icon"; const FILEUPLOADER_BUTTON_CLASS = "dx-fileuploader-button"; const FILEUPLOADER_BUTTON_CONTAINER_CLASS = "dx-fileuploader-button-container"; const FILEUPLOADER_CANCEL_BUTTON_CLASS = exports.FILEUPLOADER_CANCEL_BUTTON_CLASS = "dx-fileuploader-cancel-button"; const FILEUPLOADER_CANCEL_BUTTON_POSITION_END_CLASS = exports.FILEUPLOADER_CANCEL_BUTTON_POSITION_END_CLASS = "dx-fileuploader-cancel-button-position-end"; const FILEUPLOADER_UPLOAD_BUTTON_CLASS = "dx-fileuploader-upload-button"; const FILEUPLOADER_INVALID_CLASS = "dx-fileuploader-invalid"; const FILEUPLOADER_AFTER_LOAD_DELAY = 400; const DRAG_EVENT_DELTA = 1; const DIALOG_TRIGGER_EVENT_NAMESPACE = "dxFileUploaderDialogTrigger"; const keyUpEventName = "keyup"; const nativeClickEvent = "click"; const ENTER_KEY = "enter"; const SPACE_KEY = "space"; let renderFileUploaderInput = () => (0, _renderer.default)("<input>").attr("type", "file"); const isFormDataSupported = () => !!window.FormData; class FileUploader extends _editor.default { _supportedKeys() { const click = e => { e.preventDefault(); const $selectButton = this._selectButton.$element(); _events_engine.default.triggerHandler($selectButton, { type: "dxclick" }) }; return Object.assign({}, super._supportedKeys(), { space: click, enter: click }) } _setOptionsByReference() { super._setOptionsByReference(); (0, _extend.extend)(this._optionsByReference, { value: true }) } _getDefaultOptions() { return Object.assign({}, super._getDefaultOptions(), { 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, onFileValidationError: null, onProgress: null, onUploadError: null, onUploadAborted: null, onDropZoneEnter: null, onDropZoneLeave: null, onCancelButtonClick: null, onFileLimitReached: void 0, 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", _hideCancelButtonOnUpload: true, _showFileIcon: false, _cancelButtonPosition: "start", _maxFileCount: void 0 }) } _defaultOptionsRules() { return super._defaultOptionsRules().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, nativeDropSupported: false, labelText: "" } }, { device: () => !isFormDataSupported(), options: { uploadMode: "useForm" } }, { device: () => (0, _themes.isMaterial)((0, _themes.current)()), options: { _uploadButtonType: "default" } }, { device: () => (0, _themes.isFluent)((0, _themes.current)()), options: { _buttonStylingMode: "text" } }]) } _initOptions(options) { const isLabelTextDefined = "labelText" in options; super._initOptions(options); if (!isLabelTextDefined && !this._shouldDragOverBeRendered()) { this.option({ labelText: "" }) } } _init() { super._init(); this._initFileInput(); this._initLabel(); this._setUploadStrategy(); this._createFileLimitReachedAction(); this._createFiles(); this._createBeforeSendAction(); this._createUploadStartedAction(); this._createUploadedAction(); this._createFilesUploadedAction(); this._createFileValidationErrorAction(); this._createProgressAction(); this._createUploadErrorAction(); this._createUploadAbortedAction(); this._createDropZoneEnterAction(); this._createDropZoneLeaveAction(); this._createCancelButtonClickAction() } _setUploadStrategy() { const { chunkSize: chunkSize = 0 } = this.option(); if (chunkSize > 0) { const { uploadChunk: uploadChunk } = this.option(); this._uploadStrategy = uploadChunk && (0, _type.isFunction)(uploadChunk) ? new _file_upload_strategyChunks.CustomChunksFileUploadStrategy(this) : new _file_upload_strategyChunks2.DefaultChunksFileUploadStrategy(this) } else { const { uploadFile: uploadFile } = this.option(); this._uploadStrategy = uploadFile && (0, _type.isFunction)(uploadFile) ? new _file_upload_strategyWhole.CustomWholeFileUploadStrategy(this) : new _file_upload_strategyWhole2.DefaultWholeFileUploadStrategy(this) } } _initFileInput() { 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() })); _events_engine.default.on(this._$fileInput, "click", (e => { e.stopPropagation(); this._resetInputValue(); const { useNativeInputClick: useNativeInputClick } = this.option(); return useNativeInputClick || this._isCustomClickEvent })) } const inputProps = { multiple: multiple, accept: accept, tabIndex: -1 }; if ((0, _type.isDefined)(hint)) { inputProps.title = hint } this._$fileInput.prop(inputProps) } _inputChangeHandler() { if (this._doPreventInputChange) { return } const fileName = this._$fileInput.val().replace(/^.*\\/, ""); const files = this._$fileInput.prop("files"); const { uploadMode: uploadMode } = this.option(); if (files && !files.length && "useForm" !== uploadMode) { return } if (this._isFileLimitReached(files)) { var _this$_fileLimitReach; null === (_this$_fileLimitReach = this._fileLimitReachedAction) || void 0 === _this$_fileLimitReach || _this$_fileLimitReach.call(this); return } const value = files ? this._getFiles(files) : [{ name: fileName }]; this._changeValue(value); if ("instantly" === uploadMode) { this._uploadFiles() } } _isFileLimitReached() { let files = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : []; const { _maxFileCount: _maxFileCount, value: value } = this.option(); if (void 0 === _maxFileCount) { return false } const totalCount = files.length + ((null === value || void 0 === value ? void 0 : value.length) ?? 0); const isFileLimitReached = totalCount > _maxFileCount; return isFileLimitReached } _shouldFileListBeExtended() { const { uploadMode: uploadMode, extendSelection: extendSelection, multiple: multiple } = this.option(); return Boolean("useForm" !== uploadMode && extendSelection && multiple) } _changeValue(value) { const { value: currentValue } = this.option(); const files = this._shouldFileListBeExtended() ? null === currentValue || void 0 === currentValue ? void 0 : currentValue.slice() : []; this.option({ value: null === files || void 0 === files ? void 0 : files.concat(value) }) } _getFiles(fileList) { return [...fileList] } _getFile(fileData) { var _this$_files; const { value: value } = this.option(); const targetFileValue = (0, _type.isNumeric)(fileData) ? null === value || void 0 === value ? void 0 : value[fileData] : fileData; return null === (_this$_files = this._files) || void 0 === _this$_files ? void 0 : _this$_files.filter((file => file.value === targetFileValue))[0] } _initLabel() { if (!this._$inputLabel) { this._$inputLabel = (0, _renderer.default)("<div>") } this._updateInputLabelText() } _updateInputLabelText() { const { labelText: labelText } = this.option(); const correctedValue = this._isInteractionDisabled() ? "" : labelText; this._$inputLabel.text(correctedValue ?? "") } _focusTarget() { return this.$element().find(".dx-fileuploader-button") } _getSubmitElement() { return this._$fileInput } _initMarkup() { super._initMarkup(); this.$element().addClass(FILEUPLOADER_CLASS); this._renderWrapper(); this._renderInputWrapper(); this._renderSelectButton(); this._renderInputContainer(); this._renderUploadButton(); this._preventRecreatingFiles = true; this._activeDropZone = null } _render() { const { dropZone: dropZone } = this.option(); this._preventRecreatingFiles = false; this._attachDragEventHandlers(this._$inputWrapper); this._attachDragEventHandlers(dropZone); this._renderFiles(); super._render() } _createFileProgressBar(file) { file.progressBar = this._createProgressBar(file.value.size); if (file.$file) { file.progressBar.$element().appendTo(file.$file) } this._initStatusMessage(file); this._ensureCancelButtonInitialized(file) } _setStatusMessage(file) { let message = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : ""; setTimeout((() => { const { showFileList: showFileList } = this.option(); if (showFileList) { if (file.$statusMessage) { var _file$progressBar; file.$statusMessage.text(message); file.$statusMessage.css("display", ""); null === (_file$progressBar = file.progressBar) || void 0 === _file$progressBar || _file$progressBar.$element().remove() } } }), 400) } _getUploadAbortedStatusMessage() { const { uploadMode: uploadMode, uploadAbortedMessage: uploadAbortedMessage, readyToUploadMessage: readyToUploadMessage } = this.option(); return "instantly" === uploadMode ? uploadAbortedMessage : readyToUploadMessage } _createFiles() { const { value: files } = this.option(); if (this._isFileLimitReached()) { var _this$_fileLimitReach2; null === (_this$_fileLimitReach2 = this._fileLimitReachedAction) || void 0 === _this$_fileLimitReach2 || _this$_fileLimitReach2.call(this) } if (this._files && (0 === (null === files || void 0 === files ? void 0 : files.length) || !this._shouldFileListBeExtended())) { this._preventFilesUploading(this._files); this._files = null } if (!this._files) { this._files = [] } null === files || void 0 === files || files.slice(this._files.length).forEach((value => { var _this$_files2; const file = this._createFile(value); this._validateFile(file); null === (_this$_files2 = this._files) || void 0 === _this$_files2 || _this$_files2.push(file) })) } _preventFilesUploading(files) { null === files || void 0 === files || files.forEach((file => this._uploadStrategy.abortUpload(file))) } _validateFile(file) { file.isValidFileExtension = this._validateFileExtension(file); file.isValidMinSize = this._validateMinFileSize(file); file.isValidMaxSize = this._validateMaxFileSize(file) } _validateFileExtension(file) { const { allowedFileExtensions: allowedFileExtensions } = this.option(); if (!(null !== allowedFileExtensions && void 0 !== allowedFileExtensions && allowedFileExtensions.length)) { return true } return this._isFileExtensionAllowed(file.value, allowedFileExtensions) } _validateMaxFileSize(file) { const fileSize = file.value.size; const { maxFileSize: maxFileSize = 0 } = this.option(); return maxFileSize > 0 ? fileSize <= maxFileSize : true } _validateMinFileSize(file) { const fileSize = file.value.size; const { minFileSize: minFileSize = 0 } = this.option(); return minFileSize > 0 ? fileSize >= minFileSize : true } _isFileExtensionAllowed(file, allowedExtensions) { for (let i = 0, n = allowedExtensions.length; i < n; i += 1) { let allowedExtension = allowedExtensions[i]; if (allowedExtension.startsWith(".")) { allowedExtension = allowedExtension.replace(".", "\\."); if (new RegExp(`${allowedExtension}$`, "i").exec(file.name)) { return true } } else { allowedExtension = allowedExtension.replace(new RegExp("\\*", "g"), ""); if (new RegExp(allowedExtension, "i").exec(file.type)) { return true } } } return false } _createBeforeSendAction() { this._beforeSendAction = this._createActionByOption("onBeforeSend", { excludeValidators: ["readOnly"] }) } _createUploadStartedAction() { this._uploadStartedAction = this._createActionByOption("onUploadStarted", { excludeValidators: ["readOnly"] }) } _createUploadedAction() { this._uploadedAction = this._createActionByOption("onUploaded", { excludeValidators: ["readOnly"] }) } _createFilesUploadedAction() { this._filesUploadedAction = this._createActionByOption("onFilesUploaded", { excludeValidators: ["readOnly"] }) } _createFileValidationErrorAction() { this._fileValidationErrorAction = this._createActionByOption("onFileValidationError", { excludeValidators: ["readOnly"] }) } _createProgressAction() { this._progressAction = this._createActionByOption("onProgress", { excludeValidators: ["readOnly"] }) } _createUploadAbortedAction() { this._uploadAbortedAction = this._createActionByOption("onUploadAborted", { excludeValidators: ["readOnly"] }) } _createUploadErrorAction() { this._uploadErrorAction = this._createActionByOption("onUploadError", { excludeValidators: ["readOnly"] }) } _createDropZoneEnterAction() { this._dropZoneEnterAction = this._createActionByOption("onDropZoneEnter") } _createDropZoneLeaveAction() { this._dropZoneLeaveAction = this._createActionByOption("onDropZoneLeave") } _createCancelButtonClickAction() { this._cancelButtonClickAction = this._createActionByOption("onCancelButtonClick", { excludeValidators: ["readOnly"] }) } _createFileLimitReachedAction() { this._fileLimitReachedAction = this._createActionByOption("onFileLimitReached", { excludeValidators: ["readOnly"] }) } _createFile(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 Boolean(this.isValidFileExtension) && Boolean(this.isValidMaxSize) && Boolean(this.isValidMinSize) }, isInitialized: false } } _resetFileState(file) { file.isAborted = false; file.uploadStarted = false; file.isStartLoad = false; file.loadedSize = 0; file.chunksData = void 0; file.request = void 0 } _renderFiles() { var _this$_files4, _this$_validationMess; const { value: value, showFileList: showFileList } = this.option(); if (!this._$filesContainer) { this._$filesContainer = (0, _renderer.default)("<div>").addClass("dx-fileuploader-files-container").appendTo(this._$content) } else if (!this._shouldFileListBeExtended() || 0 === (null === value || void 0 === value ? void 0 : value.length)) { this._$filesContainer.empty() } if (showFileList) { var _this$_files3; null === (_this$_files3 = this._files) || void 0 === _this$_files3 || _this$_files3.forEach((file => { if (!file.$file) { this._renderFile(file) } })) } this.$element().toggleClass("dx-fileuploader-show-file-list", showFileList); this._toggleFileContainerAria(Boolean(showFileList && (null === (_this$_files4 = this._files) || void 0 === _this$_files4 ? void 0 : _this$_files4.length))); this._toggleFileUploaderEmptyClassName(); this._updateFileNameMaxWidth(); null === (_this$_validationMess = this._validationMessage) || void 0 === _this$_validationMess || _this$_validationMess.repaint() } _toggleFileContainerAria(applyAria) { var _this$_$filesContaine; const aria = { role: applyAria ? "list" : null, "aria-label": applyAria ? _message.default.format("dxFileUploader-fileListLabel") : null }; null === (_this$_$filesContaine = this._$filesContainer) || void 0 === _this$_$filesContaine || _this$_$filesContaine.attr(aria) } _renderFile(file) { const { value: value } = file; if (!this._$filesContainer) { return } const $fileContainer = (0, _renderer.default)("<div>").addClass("dx-fileuploader-file-container").appendTo(this._$filesContainer).attr("role", "listitem"); this._renderFileIcon(value.name, $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).attr("title", value.name).appendTo($fileInfo); if ((0, _type.isDefined)(value.size)) { (0, _renderer.default)("<div>").addClass("dx-fileuploader-file-size").text((0, _file_uploader.getFileSize)(value.size)).appendTo($fileInfo) } this._renderFileButtons(file, $fileContainer); if (file.isValid()) { const { readyToUploadMessage: readyToUploadMessage } = this.option(); file.$statusMessage.text(readyToUploadMessage ?? "") } else { var _this$_fileValidation; 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")) } null === (_this$_fileValidation = this._fileValidationErrorAction) || void 0 === _this$_fileValidation || _this$_fileValidation.call(this, { file: file.value }); $fileContainer.addClass("dx-fileuploader-invalid") } } _createValidationElement(key) { return (0, _renderer.default)("<span>").text(this.option()[key]) } _updateFileNameMaxWidth() { var _this$_$filesContaine2, _this$_$filesContaine3, _this$_$filesContaine4, _this$_$filesContaine5, _this$_$filesContaine6; const { allowCanceling: allowCanceling, uploadMode: uploadMode, _showFileIcon: _showFileIcon } = this.option(); const cancelButtonsCount = allowCanceling && "useForm" !== uploadMode ? 1 : 0; const uploadButtonsCount = "useButtons" === uploadMode ? 1 : 0; const filesContainerWidth = (0, _size.getWidth)(null === (_this$_$filesContaine2 = this._$filesContainer) || void 0 === _this$_$filesContaine2 ? void 0 : _this$_$filesContaine2.find(".dx-fileuploader-file-container").first()) || (0, _size.getWidth)(this._$filesContainer); const $buttonContainer = null === (_this$_$filesContaine3 = this._$filesContainer) || void 0 === _this$_$filesContaine3 ? void 0 : _this$_$filesContaine3.find(".dx-fileuploader-button-container").eq(0); const buttonsWidth = (0, _size.getWidth)($buttonContainer) * (cancelButtonsCount + uploadButtonsCount); const $fileSize = null === (_this$_$filesContaine4 = this._$filesContainer) || void 0 === _this$_$filesContaine4 ? void 0 : _this$_$filesContaine4.find(".dx-fileuploader-file-size").eq(0); const $icon = null === (_this$_$filesContaine5 = this._$filesContainer) || void 0 === _this$_$filesContaine5 ? void 0 : _this$_$filesContaine5.find(".dx-fileuploader-file-icon").eq(0); const iconWidth = _showFileIcon ? (0, _size.getOuterWidth)($icon) : 0; const prevFileSize = null === $fileSize || void 0 === $fileSize ? void 0 : $fileSize.text(); null === $fileSize || void 0 === $fileSize || $fileSize.text("1000 Mb"); const fileSizeWidth = (0, _size.getWidth)($fileSize); null === $fileSize || void 0 === $fileSize || $fileSize.text(prevFileSize ?? ""); const maxWidth = filesContainerWidth - buttonsWidth - fileSizeWidth - iconWidth; null === (_this$_$filesContaine6 = this._$filesContainer) || void 0 === _this$_$filesContaine6 || _this$_$filesContaine6.find(".dx-fileuploader-file-name").css("maxWidth", maxWidth) } _renderFileButtons(file, $container) { const { _cancelButtonPosition: _cancelButtonPosition } = this.option(); const $uploadButton = this._getUploadButton(file); if ($uploadButton) { $container.prepend($uploadButton) } const $cancelButton = this._getCancelButton(file); if ($cancelButton) { if ("end" === _cancelButtonPosition) { $container.append($cancelButton); return } $container.prepend($cancelButton) } } _renderFileIcon(fileName, $container) { const { _showFileIcon: _showFileIcon } = this.option(); if (!_showFileIcon) { return }(0, _renderer.default)("<div>").addClass(`dx-fileuploader-file-icon ${_m_icon.ICON_CLASS} ${_m_icon.ICON_CLASS}-${(0,_file_uploader.getFileIconName)(fileName)}`).appendTo($container) } _getCancelButton(file) { var _file$value; const { uploadMode: uploadMode, _cancelButtonPosition: _cancelButtonPosition } = this.option(); if ("useForm" === 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 ${FILEUPLOADER_CANCEL_BUTTON_CLASS}`), _button.default, { onClick: () => { var _this$_cancelButtonCl; this._removeFile(file); null === (_this$_cancelButtonCl = this._cancelButtonClickAction) || void 0 === _this$_cancelButtonCl || _this$_cancelButtonCl.call(this, { file: file.value }) }, icon: "close", visible: allowCanceling, disabled: readOnly, integrationOptions: {}, hoverStateEnabled: hoverStateEnabled, stylingMode: _buttonStylingMode, elementAttr: { "aria-label": _message.default.format("dxFileUploader-removeFileButtonLabel", (null === file || void 0 === file || null === (_file$value = file.value) || void 0 === _file$value ? void 0 : _file$value.name) ?? "") } }); if ("end" === _cancelButtonPosition) { file.cancelButton.$element().addClass(FILEUPLOADER_CANCEL_BUTTON_POSITION_END_CLASS) } return (0, _renderer.default)("<div>").addClass("dx-fileuploader-button-container").append(file.cancelButton.$element()) } _getUploadButton(file) { var _file$value2; const { uploadMode: uploadMode } = this.option(); if (!file.isValid() || "useButtons" !== 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, elementAttr: { "aria-label": _message.default.format("dxFileUploader-uploadFileButtonLabel", (null === file || void 0 === file || null === (_file$value2 = file.value) || void 0 === _file$value2 ? void 0 : _file$value2.name) ?? "") } }); file.onLoadStart.add((() => { var _file$uploadButton; null === (_file$uploadButton = file.uploadButton) || void 0 === _file$uploadButton || _file$uploadButton.option({ visible: false, disabled: true }) })); file.onAbort.add((() => { var _file$uploadButton2; null === (_file$uploadButton2 = file.uploadButton) || void 0 === _file$uploadButton2 || _file$uploadButton2.option({ visible: true, disabled: false }) })); return (0, _renderer.default)("<div>").addClass("dx-fileuploader-button-container").append(file.uploadButton.$element()) } _removeFile(file) { var _file$$file, _this$_files5, _this$_files6; null === (_file$$file = file.$file) || void 0 === _file$$file || _file$$file.parent().remove(); null === (_this$_files5 = this._files) || void 0 === _this$_files5 || _this$_files5.splice(this._files.indexOf(file), 1); const { value: value } = this.option(); const valueCopy = null === value || void 0 === value ? void 0 : value.slice(); null === valueCopy || void 0 === valueCopy || valueCopy.splice(valueCopy.indexOf(file.value), 1); this._preventRecreatingFiles = true; this.option({ value: valueCopy }); this._preventRecreatingFiles = false; if (0 === (null === (_this$_files6 = this._files) || void 0 === _this$_files6 ? void 0 : _this$_files6.length)) { this._toggleFileContainerAria(false) } this._toggleFileUploaderEmptyClassName(); this._resetInputValue(true) } removeFile(fileData) { const { uploadMode: uploadMode } = this.option(); if ("useForm" === uploadMode || !(0, _type.isDefined)(fileData)) { return } const file = this._getFile(fileData); if (file) { if (file.uploadStarted) { this._preventFilesUploading([file]) } this._removeFile(file) } } _toggleFileUploaderEmptyClassName() { var _this$_files7; this.$element().toggleClass("dx-fileuploader-empty", !(null !== (_this$_files7 = this._files) && void 0 !== _this$_files7 && _this$_files7.length) || this._hasInvalidFile(this._files)) } _hasInvalidFile(files) { return files.some((file => !file.isValid())) } _renderSelectButton() { const $button = (0, _renderer.default)("<div>").addClass("dx-fileuploader-button").appendTo(this._$inputWrapper); const { selectButtonText: selectButtonText, readOnly: readOnly, hoverStateEnabled: hoverStateEnabled } = this.option(); this._selectButton = this._createComponent($button, _button.default, { text: selectButtonText, focusStateEnabled: false, integrationOptions: {}, disabled: readOnly, hoverStateEnabled: hoverStateEnabled }); if ("desktop" === _devices.default.real().deviceType) { this._selectButton.option({ onClick: () => this._selectFileDialogClickHandler() }) } else { this._attachSelectFileDialogHandlers(this._selectButton.$element()) } const { dialogTrigger: dialogTrigger } = this.option(); this._attachSelectFileDialogHandlers(dialogTrigger) } _selectFileDialogClickHandler() { const { useNativeInputClick: useNativeInputClick } = this.option(); if (useNativeInputClick || this._isInteractionDisabled()) { return } this._isCustomClickEvent = true; _events_engine.default.trigger(this._$fileInput, "click"); this._isCustomClickEvent = false } _attachSelectFileDialogHandlers(target) { if (!(0, _type.isDefined)(target)) { return } this._detachSelectFileDialogHandlers(target); const $target = (0, _renderer.default)(target); _events_engine.default.on($target, (0, _index.addNamespace)("click", "dxFileUploaderDialogTrigger"), (() => { this._selectFileDialogClickHandler() })); _events_engine.default.on($target, (0, _index.addNamespace)("keyup", "dxFileUploaderDialogTrigger"), (e => { const normalizedKeyName = (0, _index.normalizeKeyName)(e); if ("enter" === normalizedKeyName || "space" === normalizedKeyName) { this._selectFileDialogClickHandler() } })) } _detachSelectFileDialogHandlers(target) { if (!(0, _type.isDefined)(target)) { return } const $target = (0, _renderer.default)(target); _events_engine.default.off($target, ".dxFileUploaderDialogTrigger") } _renderUploadButton() { const { uploadButtonText: uploadButtonText, _uploadButtonType: _uploadButtonType, hoverStateEnabled: hoverStateEnabled, uploadMode: uploadMode } = this.option(); if ("useButtons" !== 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: uploadButtonText, onClick: this._uploadButtonClickHandler.bind(this), type: _uploadButtonType, integrationOptions: {}, hoverStateEnabled: hoverStateEnabled }) } _uploadButtonClickHandler() { this._uploadFiles() } _shouldDragOverBeRendered() { const { readOnly: readOnly, uploadMode: uploadMode, nativeDropSupported: nativeDropSupported } = this.option(); return !readOnly && ("useForm" !== uploadMode || nativeDropSupported) } _isInteractionDisabled() { const { readOnly: readOnly, disabled: disabled } = this.option(); return Boolean(readOnly) || Boolean(disabled) } _renderInputContainer() { this._$inputContainer = (0, _renderer.default)("<div>").addClass("dx-fileuploader-input-container").appendTo(this._$inputWrapper); this._renderInput(); this._$fileInput.addClass("dx-fileuploader-input"); const labelId = `dx-fileuploader-input-label-${new _guid.default}`; this._$inputLabel.attr("id", labelId).addClass("dx-fileuploader-input-label").appendTo(this._$inputContainer); this.setAria("labelledby", labelId, this._$fileInput) } _renderInput() { const { useNativeInputClick: useNativeInputClick, inputAttr: inputAttr } = this.option(); if (useNativeInputClick) { this._selectButton.option({ template: this._selectButtonInputTemplate.bind(this) }) } else { this._$fileInput.appendTo(this._$inputContainer); this._selectButton.option({ template: "content" }) } this._applyInputAttributes(inputAttr) } _selectButtonInputTemplate(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 } _renderInputWrapper() { if (!this._$content) { return } this._$inputWrapper = (0, _renderer.default)("<div>").addClass("dx-fileuploader-input-wrapper").appendTo(this._$content) } _detachDragEventHandlers(target) { if (!target) { return } _events_engine.default.off((0, _renderer.default)(target), (0, _index.addNamespace)("", this.NAME)) } _attachDragEventHandlers(target) { const isCustomTarget = target !== this._$inputWrapper; if (!(0, _type.isDefined)(target) || !this._shouldDragOverBeRendered()) { return } this._detachDragEventHandlers(target); _events_engine.default.on((0, _renderer.default)(target), (0, _index.addNamespace)("dragenter", this.NAME), this._dragEnterHandler.bind(this, isCustomTarget)); _events_engine.default.on((0, _renderer.default)(target), (0, _index.addNamespace)("dragover", this.NAME), this._dragOverHandler.bind(this, isCustomTarget)); _events_engine.default.on((0, _renderer.default)(target), (0, _index.addNamespace)("dragleave", this.NAME), this._dragLeaveHandler.bind(this, isCustomTarget)); _events_engine.default.on((0, _renderer.default)(target), (0, _index.addNamespace)("drop", this.NAME), this._dropHandler.bind(this, isCustomTarget)) } _applyInputAttributes(customAttributes) { this._$fileInput.attr(customAttributes) } _useInputForDrop() { const { uploadMode: uploadMode, nativeDropSupported: nativeDropSupported } = this.option(); return Boolean(nativeDropSupported) && "useForm" === uploadMode } _getDropZoneElement(isCustomTarget, e) { if (!e.currentTarget) { return } const { dropZone: dropZone } = this.option(); const targetList = isCustomTarget ? (0, _renderer.default)(dropZone).toArray() : [this._$inputWrapper]; const targetListElements = targetList.map((element => (0, _renderer.default)(element).get(0))); const currentTargetIndex = targetListElements.indexOf(e.currentTarget); return targetListElements[currentTargetIndex] } _dragEnterHandler(isCustomTarget, e) { const { disabled: disabled } = this.option(); if (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) } } _shouldRaiseDragOver(e, dropZoneElement) { return null === this._activeDropZone && this.isMouseOverElement(e, dropZoneElement, false) && e.originalEvent.dataTransfer.types.find((item => "Files" === item)) } _dragOverHandler(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) } } } _dragLeaveHandler(isCustomTarget, e) { if (!this._useInputForDrop()) { e.preventDefault() } if (this._shouldRaiseDragLeave(e, isCustomTarget)) { this._tryToggleDropZoneActive(false, isCustomTarget, e); this._activeDropZone = null } } _shouldRaiseDragLeave(e, isCustomTarget) { return null !== this._activeDropZone && !this.isMouseOverElement(e, this._activeDropZone, !isCustomTarget, -1) } _tryToggleDropZoneActive(active, isCustom, event) { var _this$mouseAction; const classAction = active ? "addClass" : "removeClass"; const mouseAction = active ? "_dropZoneEnterAction" : "_dropZoneLeaveAction"; null === (_this$mouseAction = this[mouseAction]) || void 0 === _this$mouseAction || _this$mouseAction.call(this, { event: event, dropZoneElement: this._activeDropZone }); if (!isCustom) { this.$element()[classAction]("dx-fileuploader-dragover") } } _dropHandler(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); const { multiple: multiple, uploadMode: uploadMode } = this.option(); if (!multiple && files.length > 1 || 0 === files.length) { return } if (this._isFileLimitReached(files)) { var _this$_fileLimitReach3; null === (_this$_fileLimitReach3 = this._fileLimitReachedAction) || void 0 === _this$_fileLimitReach3 || _this$_fileLimitReach3.call(this); return } this._changeValue(files); if ("instantly" === uploadMode) { this._uploadFiles() } } _areAllFilesLoaded() { var _this$_files8; return null === (_this$_files8 = this._files) || void 0 === _this$_files8 ? void 0 : _this$_files8.every((file => !file.isValid() || file._isError || file._isLoaded || file.isAborted)) } _handleAllFilesUploaded() { this._recalculateProgress(); if (this._areAllFilesLoaded()) { var _this$_filesUploadedA; null === (_this$_filesUploadedA = this._filesUploadedAction) || void 0 === _this$_filesUploadedA || _this$_filesUploadedA.call(this) } } _renderWrapper() { 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) } _clean() { this._$fileInput.detach(); this._$filesContainer = null; const { dialogTrigger: dialogTrigger, dropZone: dropZone } = this.option(); this._detachSelectFileDialogHandlers(dialogTrigger); this._detachDragEventHandlers(dropZone); if (this._files) { this._files.forEach((file => { file.$file = null; file.$statusMessage = null })) } super._clean() } abortUpload(fileData) { const { uploadMode: uploadMode } = this.option(); if ("useForm" === uploadMode) { return } if ((0, _type.isDefined)(fileData)) { const file = this._getFile(fileData); if (file) { this._preventFilesUploading([file]) } } else { this._preventFilesUploading(this._files) } } upload(fileData) { const { uploadMode: uploadMode } = this.option(); if ("useForm" === uploadMode) { return } if ((0, _type.isDefined)(fileData)) { const file = this._getFile(fileData); if (file && isFormDataSupported()) { this._uploadFile(file) } } else { this._uploadFiles() } } _uploadFiles() { if (isFormDataSupported()) { var _this$_files9; null === (_this$_files9 = this._files) || void 0 === _this$_files9 || _this$_files9.forEach((file => this._uploadFile(file))) } } _uploadFile(file) { this._uploadStrategy.upload(file) } _updateProgressBar(file, loadedFileData) { var _file$progressBar2, _this$_progressAction; null ===