devextreme
Version:
JavaScript/TypeScript Component Suite for Responsive Web Development
386 lines (385 loc) • 16.9 kB
JavaScript
/**
* DevExtreme (esm/__internal/ui/file_manager/ui.file_manager.file_uploader.js)
* Version: 25.2.7
* Build date: Tue May 05 2026
*
* Copyright (c) 2012 - 2026 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
import Guid from "../../../core/guid";
import $ from "../../../core/renderer";
import {
Deferred
} from "../../../core/utils/deferred";
import {
getInnerHeight,
setHeight,
setWidth
} from "../../../core/utils/size";
import {
hasWindow
} from "../../../core/utils/window";
import FileUploader from "../../../ui/file_uploader";
import Widget from "../../core/widget/widget";
import {
whenSome
} from "../../ui/file_manager/ui.file_manager.common";
const FILE_MANAGER_FILE_UPLOADER_CLASS = "dx-filemanager-fileuploader";
const FILE_MANAGER_FILE_UPLOADER_DROPZONE_PLACEHOLDER_CLASS = "dx-filemanager-fileuploader-dropzone-placeholder";
class FileManagerFileUploader extends Widget {
_initMarkup() {
this._initActions();
this.$element().addClass("dx-filemanager-fileuploader");
this._uploaderInfos = [];
this._createInternalFileUploader();
this._createDropZonePlaceholder();
this._setDropZonePlaceholderVisible(false);
super._initMarkup()
}
_createInternalFileUploader() {
const {
chunkSize: chunkSize
} = this._getController();
const $fileUploader = $("<div>").appendTo(this.$element());
const fileUploader = this._createComponent($fileUploader, FileUploader, {
name: "file",
multiple: true,
showFileList: false,
activeStateEnabled: false,
focusStateEnabled: false,
hoverStateEnabled: false,
labelText: "",
readyToUploadMessage: "",
accept: "*",
chunkSize: chunkSize,
dropZone: this.option("dropZone"),
onValueChanged: e => this._onFileUploaderValueChanged(e),
onProgress: e => this._onFileUploaderProgress(e),
onUploaded: e => this._onFileUploaderUploaded(e),
onFilesUploaded: e => this._onFileUploaderAllFilesUploaded(e),
onUploadAborted: e => this._onFileUploaderUploadAborted(e),
onUploadError: e => this._onFileUploaderUploadError(e),
onDropZoneEnter: () => this._setDropZonePlaceholderVisible(true),
onDropZoneLeave: () => this._setDropZonePlaceholderVisible(false)
});
fileUploader.option({
uploadChunk: (file, chunksData) => this._fileUploaderUploadChunk(fileUploader, file, chunksData),
abortUpload: (file, chunksData) => this._fileUploaderAbortUpload(fileUploader, file, chunksData)
});
fileUploader._shouldRaiseDragLeaveBase = fileUploader._shouldRaiseDragLeave;
fileUploader._shouldRaiseDragLeave = e => this._shouldRaiseDragLeave(e, fileUploader);
const uploaderInfo = {
fileUploader: fileUploader
};
this._uploaderInfos.push(uploaderInfo)
}
tryUpload() {
const info = this._findAndUpdateAvailableUploaderInfo();
if (info) {
info.fileUploader._selectFileDialogClickHandler()
}
}
cancelUpload(sessionId) {
this._cancelUpload(sessionId)
}
cancelFileUpload(sessionId, fileIndex) {
this._cancelUpload(sessionId, fileIndex)
}
_cancelUpload(sessionId, fileIndex) {
const {
fileUploader: fileUploader
} = this._findUploaderInfoBySessionId(sessionId);
fileUploader.abortUpload(fileIndex)
}
_fileUploaderUploadChunk(fileUploader, file, chunksInfo) {
const {
session: session,
fileIndex: fileIndex
} = this._findSessionByFile(fileUploader, file);
const {
controller: controller
} = session;
chunksInfo.fileIndex = fileIndex;
return controller.uploadFileChunk(file, chunksInfo)
}
_fileUploaderAbortUpload(fileUploader, file, chunksInfo) {
const {
session: session,
fileIndex: fileIndex
} = this._findSessionByFile(fileUploader, file);
const {
controller: controller
} = session;
chunksInfo.fileIndex = fileIndex;
return controller.abortFileUpload(file, chunksInfo)
}
_onFileUploaderValueChanged(_ref) {
let {
component: component,
value: value
} = _ref;
if (0 === value.length) {
return
}
const files = value.slice();
const uploaderInfo = this._findUploaderInfo(component);
this._uploadFiles(uploaderInfo, files);
setTimeout(() => {
if (!this._findAndUpdateAvailableUploaderInfo()) {
this._createInternalFileUploader()
}
})
}
_onFileUploaderProgress(_ref2) {
let {
component: component,
file: file,
bytesLoaded: bytesLoaded,
bytesTotal: bytesTotal
} = _ref2;
const {
session: session,
fileIndex: fileIndex
} = this._findSessionByFile(component, file);
const fileValue = 0 !== bytesTotal ? bytesLoaded / bytesTotal : 1;
const commonValue = component.option("progress") / 100;
const args = {
sessionId: session.id,
fileIndex: fileIndex,
commonValue: commonValue,
fileValue: fileValue
};
this._raiseUploadProgress(args)
}
_onFileUploaderAllFilesUploaded(_ref3) {
let {
component: component
} = _ref3;
const {
session: session
} = this._findSessionByFile(component, component._files[0].value);
this._raiseUploadFinished({
sessionId: session.id,
commonValue: component.option("progress") / 100
})
}
_onFileUploaderUploaded(_ref4) {
let {
component: component,
file: file
} = _ref4;
const deferred = this._getDeferredForFile(component, file);
deferred.resolve()
}
_onFileUploaderUploadAborted(_ref5) {
let {
component: component,
file: file
} = _ref5;
const deferred = this._getDeferredForFile(component, file);
deferred.resolve({
canceled: true
})
}
_onFileUploaderUploadError(_ref6) {
let {
component: component,
file: file,
error: error
} = _ref6;
const deferred = this._getDeferredForFile(component, file);
deferred.reject(error)
}
_createDropZonePlaceholder() {
const {
dropZonePlaceholderContainer: dropZonePlaceholderContainer
} = this.option();
this._$dropZonePlaceholder = $("<div>").addClass("dx-filemanager-fileuploader-dropzone-placeholder").appendTo($(dropZonePlaceholderContainer))
}
_adjustDropZonePlaceholder() {
var _this$_$dropZonePlace, _this$_$dropZonePlace2, _this$_$dropZonePlace3;
const {
dropZone: dropZone
} = this.option();
const $dropZoneTarget = dropZone;
if (!hasWindow() || 0 === (null === $dropZoneTarget || void 0 === $dropZoneTarget ? void 0 : $dropZoneTarget.length)) {
return
}
const placeholderBorderTopWidth = parseFloat((null === (_this$_$dropZonePlace = this._$dropZonePlaceholder) || void 0 === _this$_$dropZonePlace ? void 0 : _this$_$dropZonePlace.css("borderTopWidth")) ?? "");
const placeholderBorderLeftWidth = parseFloat((null === (_this$_$dropZonePlace2 = this._$dropZonePlaceholder) || void 0 === _this$_$dropZonePlace2 ? void 0 : _this$_$dropZonePlace2.css("borderLeftWidth")) ?? "");
const {
dropZonePlaceholderContainer: dropZonePlaceholderContainer
} = this.option();
const $placeholderContainer = dropZonePlaceholderContainer;
const containerBorderBottomWidth = parseFloat((null === $placeholderContainer || void 0 === $placeholderContainer ? void 0 : $placeholderContainer.css("borderBottomWidth")) ?? "");
const containerBorderLeftWidth = parseFloat((null === $placeholderContainer || void 0 === $placeholderContainer ? void 0 : $placeholderContainer.css("borderLeftWidth")) ?? "");
const containerHeight = getInnerHeight($placeholderContainer);
const containerOffset = null === $placeholderContainer || void 0 === $placeholderContainer ? void 0 : $placeholderContainer.offset();
const dropZoneOffset = null === $dropZoneTarget || void 0 === $dropZoneTarget ? void 0 : $dropZoneTarget.offset();
null === (_this$_$dropZonePlace3 = this._$dropZonePlaceholder) || void 0 === _this$_$dropZonePlace3 || _this$_$dropZonePlace3.css({
top: (null === dropZoneOffset || void 0 === dropZoneOffset ? void 0 : dropZoneOffset.top) - (null === containerOffset || void 0 === containerOffset ? void 0 : containerOffset.top) - containerHeight - containerBorderBottomWidth,
left: (null === dropZoneOffset || void 0 === dropZoneOffset ? void 0 : dropZoneOffset.left) - (null === containerOffset || void 0 === containerOffset ? void 0 : containerOffset.left) - containerBorderLeftWidth
});
setHeight(this._$dropZonePlaceholder, (null === $dropZoneTarget || void 0 === $dropZoneTarget ? void 0 : $dropZoneTarget.get(0).offsetHeight) - 2 * placeholderBorderTopWidth);
setWidth(this._$dropZonePlaceholder, (null === $dropZoneTarget || void 0 === $dropZoneTarget ? void 0 : $dropZoneTarget.get(0).offsetWidth) - 2 * placeholderBorderLeftWidth)
}
_setDropZonePlaceholderVisible(visible) {
if (visible) {
var _this$_$dropZonePlace4;
this._adjustDropZonePlaceholder();
null === (_this$_$dropZonePlace4 = this._$dropZonePlaceholder) || void 0 === _this$_$dropZonePlace4 || _this$_$dropZonePlace4.css("display", "")
} else {
var _this$_$dropZonePlace5;
null === (_this$_$dropZonePlace5 = this._$dropZonePlaceholder) || void 0 === _this$_$dropZonePlace5 || _this$_$dropZonePlace5.css("display", "none")
}
}
_shouldRaiseDragLeave(e, uploaderInstance) {
return uploaderInstance.isMouseOverElement(e, this.option("splitterElement")) || uploaderInstance._shouldRaiseDragLeaveBase(e, true)
}
_uploadFiles(uploaderInfo, files) {
this._setDropZonePlaceholderVisible(false);
const sessionId = (new Guid).toString();
const controller = this._getController();
const deferreds = files.map(() => new Deferred);
uploaderInfo.session = {
id: sessionId,
controller: controller,
files: files,
deferreds: deferreds
};
const sessionInfo = {
sessionId: sessionId,
deferreds: deferreds,
files: files
};
this._raiseUploadSessionStarted(sessionInfo);
return whenSome(deferreds).always(() => setTimeout(() => {
uploaderInfo.fileUploader.clear();
uploaderInfo.session = null
}))
}
_getDeferredForFile(fileUploader, file) {
const {
session: session,
fileIndex: fileIndex
} = this._findSessionByFile(fileUploader, file);
return session.deferreds[fileIndex]
}
_findSessionByFile(fileUploader, file) {
const uploaderInfo = this._findUploaderInfo(fileUploader);
const {
session: session
} = uploaderInfo;
const fileIndex = session.files.indexOf(file);
return {
session: session,
fileIndex: fileIndex
}
}
_findUploaderInfoBySessionId(sessionId) {
for (let i = 0; i < (null === (_this$_uploaderInfos = this._uploaderInfos) || void 0 === _this$_uploaderInfos ? void 0 : _this$_uploaderInfos.length); i += 1) {
var _this$_uploaderInfos;
const uploaderInfo = this._uploaderInfos[i];
const {
session: session
} = uploaderInfo;
if (session && session.id === sessionId) {
return uploaderInfo
}
}
return null
}
_findAndUpdateAvailableUploaderInfo() {
var _info;
let info = null;
for (let i = 0; i < (null === (_this$_uploaderInfos2 = this._uploaderInfos) || void 0 === _this$_uploaderInfos2 ? void 0 : _this$_uploaderInfos2.length); i += 1) {
var _this$_uploaderInfos2;
const currentInfo = this._uploaderInfos[i];
currentInfo.fileUploader.option("dropZone", "");
if (!info && !currentInfo.session) {
info = currentInfo
}
}
const {
dropZone: dropZone
} = this.option();
null === (_info = info) || void 0 === _info || _info.fileUploader.option("dropZone", dropZone);
return info
}
_findUploaderInfo(fileUploader) {
for (let i = 0; i < (null === (_this$_uploaderInfos3 = this._uploaderInfos) || void 0 === _this$_uploaderInfos3 ? void 0 : _this$_uploaderInfos3.length); i += 1) {
var _this$_uploaderInfos3;
const info = this._uploaderInfos[i];
if (info.fileUploader === fileUploader) {
return info
}
}
return null
}
_getController() {
const {
getController: controllerGetter
} = this.option();
return null === controllerGetter || void 0 === controllerGetter ? void 0 : controllerGetter()
}
_raiseUploadSessionStarted(sessionInfo) {
var _this$_actions$onUplo, _this$_actions;
null === (_this$_actions$onUplo = (_this$_actions = this._actions).onUploadSessionStarted) || void 0 === _this$_actions$onUplo || _this$_actions$onUplo.call(_this$_actions, {
sessionInfo: sessionInfo
})
}
_raiseUploadProgress(args) {
var _this$_actions$onUplo2, _this$_actions2;
null === (_this$_actions$onUplo2 = (_this$_actions2 = this._actions).onUploadProgress) || void 0 === _this$_actions$onUplo2 || _this$_actions$onUplo2.call(_this$_actions2, args)
}
_raiseUploadFinished(args) {
var _this$_actions$onUplo3, _this$_actions3;
null === (_this$_actions$onUplo3 = (_this$_actions3 = this._actions).onUploadFinished) || void 0 === _this$_actions$onUplo3 || _this$_actions$onUplo3.call(_this$_actions3, args)
}
_initActions() {
this._actions = {
onUploadSessionStarted: this._createActionByOption("onUploadSessionStarted"),
onUploadProgress: this._createActionByOption("onUploadProgress"),
onUploadFinished: this._createActionByOption("onUploadFinished")
}
}
_getDefaultOptions() {
return Object.assign({}, super._getDefaultOptions(), {
getController: void 0,
onUploadSessionStarted: void 0,
onUploadProgress: void 0,
onUploadFinished: void 0,
splitterElement: void 0
})
}
_optionChanged(args) {
var _this$_$dropZonePlace6, _this$_$dropZonePlace7;
const {
name: name,
value: value
} = args;
switch (name) {
case "getController":
this.repaint();
break;
case "onUploadSessionStarted":
case "onUploadProgress":
case "onUploadFinished":
this._actions[name] = this._createActionByOption(name);
break;
case "dropZone":
this._findAndUpdateAvailableUploaderInfo();
this._adjustDropZonePlaceholder();
break;
case "dropZonePlaceholderContainer":
null === (_this$_$dropZonePlace6 = this._$dropZonePlaceholder) || void 0 === _this$_$dropZonePlace6 || _this$_$dropZonePlace6.detach();
null === (_this$_$dropZonePlace7 = this._$dropZonePlaceholder) || void 0 === _this$_$dropZonePlace7 || _this$_$dropZonePlace7.appendTo(value);
break;
case "splitterElement":
break;
default:
super._optionChanged(args)
}
}
}
export default FileManagerFileUploader;