@openui5/sap.m
Version:
OpenUI5 UI Library sap.m
1,399 lines (1,312 loc) • 81.3 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2026 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
sap.ui.define([
"sap/ui/core/Control",
"sap/ui/core/Element",
"sap/ui/events/KeyCodes",
"sap/base/Log",
"sap/base/util/deepEqual",
"sap/m/library",
"sap/m/Button",
"sap/m/Dialog",
"sap/m/List",
"sap/m/MessageBox",
"sap/m/OverflowToolbar",
"sap/m/StandardListItem",
"sap/m/Text",
"sap/m/ToolbarSpacer",
"sap/ui/unified/FileUploader",
"sap/m/upload/UploadSetItem",
"sap/m/upload/Uploader",
"sap/m/upload/UploadSetRenderer",
"sap/m/upload/UploaderHttpRequestMethod",
"sap/ui/core/dnd/DragDropInfo",
"sap/ui/core/dnd/DropInfo",
"sap/m/upload/UploadSetToolbarPlaceholder",
"sap/m/IllustratedMessage",
"sap/m/IllustratedMessageType",
"sap/m/IllustratedMessageSize",
"sap/ui/core/Core",
"sap/ui/core/InvisibleText",
"sap/m/Menu",
"sap/m/MenuItem",
"sap/m/MenuButton",
"sap/ui/core/Lib"
], function(Control, Element, KeyCodes, Log, deepEqual, MobileLibrary, Button, Dialog, List, MessageBox, OverflowToolbar, StandardListItem, Text, ToolbarSpacer, FileUploader, UploadSetItem, Uploader, Renderer, UploaderHttpRequestMethod, DragDropInfo, DropInfo, UploadSetToolbarPlaceholder, IllustratedMessage, IllustratedMessageType, IllustratedMessageSize, Core, InvisibleText, Menu, MenuItem, MenuButton, CoreLib) {
"use strict";
var UploadType = MobileLibrary.UploadType;
var MenuButtonMode = MobileLibrary.MenuButtonMode;
/**
* Constructor for a new UploadSet.
*
* @param {string} [sId] id for the new control, generated automatically if no id is given.
* @param {object} [mSettings] Initial settings for the new control.
* @class This control allows you to upload one or more files from your devices (desktop, tablet, or phone)
* and attach them to your application.<br>
* This control builds on the {@link sap.m.UploadCollection} control, providing better handling of headers
* and requests, unified behavior of instant and deferred uploads, as well as improved progress indication.<br>
* We now ensure that the control handles item insertion and deletion if the items aggregation is not bound to a model.
* It allows the connected model to not only manage the insertion and deletion updates
* but it also helps to avoid template-related issues and ensures better data handling.
* @extends sap.ui.core.Control
* @author SAP SE
* @version 1.146.0
* @constructor
* @public
* @since 1.63
* @deprecated As of version 1.129, replaced by {@link sap.m.plugins.UploadSetwithTable}
* @alias sap.m.upload.UploadSet
*/
var UploadSet = Control.extend("sap.m.upload.UploadSet", {
metadata: {
library: "sap.m",
properties: {
/**
* Allowed file types for files to be uploaded.
* <br>If this property is not set, any file can be uploaded.
*/
fileTypes: {type: "string[]", defaultValue: null},
/**
* Maximum length of names of files to be uploaded.
* <br>If set to <code>null</code> or <code>0</code>, any files can be uploaded,
* regardless of their names length.
*/
maxFileNameLength: {type: "int", defaultValue: null},
/**
* Size limit in megabytes for files to be uploaded.
* <br>If set to <code>null</code> or <code>0</code>, files of any size can be uploaded.
*/
maxFileSize: {type: "float", defaultValue: null},
/**
* Allowed media types for files to be uploaded.
* <br>If this property is not set, any file can be uploaded.
*/
mediaTypes: {type: "string[]", defaultValue: null},
/**
* Defines custom text for the 'No data' text label.
* @deprecated Since version 1.121. Use illustratedMessage instead.
*/
noDataText: { type: "string", defaultValue: null, deprecated: true },
/**
* Defines custom text for the 'No data' description label.
* @deprecated Since version 1.121. Use illustratedMessage instead.
*/
noDataDescription: { type: "string", defaultValue: null, deprecated: true },
/**
* Determines which illustration type is displayed when the control holds no data.
* @deprecated Since version 1.121. Use illustratedMessage instead.
* @since 1.117
*/
noDataIllustrationType: { type: "sap.m.IllustratedMessageType", group: "Appearance", defaultValue: IllustratedMessageType.NoData, deprecated: true },
/**
* Defines custom text for the drag and drop text label.
*/
dragDropText: {type: "string", defaultValue: null},
/**
* Defines custom text for the drag and drop description label.
*/
dragDropDescription: {type: "string", defaultValue: null},
/**
* Defines whether the upload process should be triggered as soon as the file is added.<br>
* If set to <code>false</code>, no upload is triggered when a file is added.
*/
instantUpload: {type: "boolean", defaultValue: true},
/**
* Defines whether file icons should be displayed.
*/
showIcons: {type: "boolean", defaultValue: true},
/**
* Defines whether it is allowed to terminate the upload process.
*/
terminationEnabled: {type: "boolean", defaultValue: true},
/**
* Defines whether the upload action is allowed.
*/
uploadEnabled: {type: "boolean", defaultValue: true},
/**
* URL where the uploaded files will be stored.
*/
uploadUrl: {type: "string", defaultValue: null},
/**
* If set to true, the button used for uploading files become invisible.
* @since 1.99.0
*/
uploadButtonInvisible: {type: "boolean", group: "Appearance", defaultValue: false},
/**
* Allows the user to use the same name for a file while editing the file name.
*'Same name' refers to an already existing file name in the list.
* @since 1.100.0
*/
sameFilenameAllowed: {type: "boolean", group: "Behavior", defaultValue: false},
/**
* HTTP request method chosen for file upload.
* @since 1.90
*/
httpRequestMethod: {type: "sap.m.upload.UploaderHttpRequestMethod", defaultValue: UploaderHttpRequestMethod.Post},
/**
* Lets the user select multiple files from the same folder and then upload them.
*
* If multiple property is set to false, the control shows an error message if more than one file is chosen for drag & drop.
*/
multiple: {type: "boolean", group: "Behavior", defaultValue: false},
/**
* Defines the selection mode of the control (e.g. None, SingleSelect, MultiSelect, SingleSelectLeft, SingleSelectMaster).
* Since the UploadSet reacts like a list for attachments, the API is close to the ListBase Interface.
* sap.m.ListMode.Delete mode is not supported and will be automatically set to sap.m.ListMode.None.
* In addition, if instant upload is set to false the mode sap.m.ListMode.MultiSelect is not supported and will be automatically set to sap.m.ListMode.None.
* @since 1.100.0
*/
mode: {type: "sap.m.ListMode", group: "Behavior", defaultValue: MobileLibrary.ListMode.MultiSelect},
/**
* Enables CloudFile picker feature to upload files from cloud.
* @experimental Since 1.106.
*/
cloudFilePickerEnabled: {type: "boolean", group: "Behavior", defaultValue: false},
/**
* Url of the FileShare OData V4 service supplied for CloudFile picker control.
* @experimental Since 1.106.
*/
cloudFilePickerServiceUrl: {type: "sap.ui.core.URI", group: "Data", defaultValue: ""},
/**
* The text of the CloudFile picker button. The default text is "Upload from cloud" (translated to the respective language).
* @experimental Since 1.106.
*/
cloudFilePickerButtonText: {type: 'string', defaultValue: ""},
/**
* Lets the user upload entire files from directories and sub directories.
* @since 1.107
*/
directory: {type: "boolean", group: "Behavior", defaultValue: false}
},
defaultAggregation: "items",
aggregations: {
/**
* Items representing files that have already been uploaded.
*/
items: {type: "sap.m.upload.UploadSetItem", defaultClass: UploadSetItem, multiple: true, singularName: "item"},
/**
* Items representing files yet to be uploaded.
*/
incompleteItems: {type: "sap.m.upload.UploadSetItem", defaultClass: UploadSetItem, multiple: true, singularName: "incompleteItem"},
/**
* Header fields to be included in the header section of an XHR request.
*/
headerFields: {type: "sap.ui.core.Item", multiple: true, singularName: "headerField"},
/**
* Main toolbar of the <code>UploadSet</code> control.
*/
toolbar: {type: "sap.m.OverflowToolbar", multiple: false},
/**
* Defines the uploader to be used. If not specified, the default implementation is used.
*/
uploader: {type: "sap.m.upload.Uploader", multiple: false},
/**
* An illustrated message is displayed when no data is loaded or provided
* @since 1.121
*/
illustratedMessage: { type: "sap.m.IllustratedMessage", multiple: false }
},
events: {
/**
* This event is fired when a new file is added to the set of items to be uploaded.
*/
afterItemAdded: {
parameters: {
/**
* The file that has just been added.
*/
item: {type: "sap.m.upload.UploadSetItem"}
}
},
/**
* The event is triggered when the file name is changed.
* @since 1.100.0
*/
fileRenamed: {
parameters: {
/**
* The renamed UI element as an UploadSetItem.
*/
item: {type: "sap.m.upload.UploadSetItem"}
}
},
/**
* This event is fired after the item is removed on click of ok button in confirmation dialog.
* @since 1.83
*/
afterItemRemoved: {
parameters: {
/**
* The item removed from the set of items to be uploaded.
*/
item: {type: "sap.m.upload.UploadSetItem"}
}
},
/**
* This event is fired after item edit is confirmed.
* @since 1.83
*/
afterItemEdited: {
parameters: {
/**
* The item edited.
*/
item: {type: "sap.m.upload.UploadSetItem"}
}
},
/**
* This event is fired just before a new file is added to the set of items to be uploaded.
*/
beforeItemAdded: {
parameters: {
/**
* The file to be added to the set of items to be uploaded.
*/
item: {type: "sap.m.upload.UploadSetItem"}
},
allowPreventDefault: true
},
/**
* This event is fired just before the confirmation dialog for 'Remove' action is displayed.
*/
beforeItemRemoved: {
parameters: {
/**
* The item to be removed from the set of items to be uploaded.
*/
item: {type: "sap.m.upload.UploadSetItem"}
},
allowPreventDefault: true
},
/**
* This event is fired when the edit button is clicked for an item and no other item is being edited
* at the same time.
* <br>If there is another item that has unsaved changes, the editing of the clicked item cannot be started.
*/
beforeItemEdited: {
parameters: {
/**
* The item to be edited.
*/
item: {type: "sap.m.upload.UploadSetItem"}
},
allowPreventDefault: true
},
/**
* This event is fired right before the upload process begins.
*/
beforeUploadStarts: {
parameters: {
/**
* The file whose upload is just about to start.
*/
item: {type: "sap.m.upload.UploadSetItem"}
},
allowPreventDefault: true
},
/**
* This event is fired right after the upload process is finished.
*/
uploadCompleted: {
parameters: {
/**
* The file whose upload has just been completed.
*/
item: {type: "sap.m.upload.UploadSetItem"},
/**
* Response message which comes from the server.
*
* On the server side this response has to be put within the "body" tags of the response
* document of the iFrame. It can consist of a return code and an optional message. This does not
* work in cross-domain scenarios.
*/
response : {type : "string"},
/**
* ReadyState of the XHR request.
*
* Required for receiving a <code>readyState</code> is to set the property <code>sendXHR</code>
* to true. This property is not supported by Internet Explorer 9.
*/
readyState : {type : "int"},
/**
* Status of the XHR request.
*
* Required for receiving a <code>status</code> is to set the property <code>sendXHR</code> to true.
* This property is not supported by Internet Explorer 9.
*/
status : {type : "int"},
/**
* Http-Response which comes from the server.
*
* Required for receiving <code>responseXML</code> is to set the property <code>sendXHR</code> to true.
*
* This property is not supported by Internet Explorer 9.
*/
responseXML : {type : "string"},
/**
* Http-Response-Headers which come from the server.
*
* Provided as a JSON-map, i.e. each header-field is reflected by a property in the <code>headers</code>
* object, with the property value reflecting the header-field's content.
*
* Required for receiving <code>headers</code> is to set the property <code>sendXHR</code> to true.
* This property is not supported by Internet Explorer 9.
*/
headers : {type : "object"}
}
},
/**
* This event is fired right before the upload is terminated.
*/
beforeUploadTermination: {
parameters: {
/**
* The file whose upload is about to be terminated.
*/
item: {type: "sap.m.upload.UploadSetItem"}
},
allowPreventDefault: true
},
/**
* This event is fired right after the upload is terminated.
*/
uploadTerminated: {
parameters: {
/**
* The file whose upload has just been terminated.
*/
item: {type: "sap.m.upload.UploadSetItem"}
}
},
/**
* This event is fired in either of the following cases:
* <ul>
* <li>When a file that is selected to be uploaded fails to meet the file type restriction
* (<code>fileType</code> property).</li>
* <li>When the file type restriction changes, and the file to be uploaded fails to meet the new
* restriction.</li>
* </ul>
*/
fileTypeMismatch: {
parameters: {
/**
* The file that fails to meet the file type restriction specified in the
* <code>fileType</code> property.
*/
item: {type: "sap.m.upload.UploadSetItem"}
}
},
/**
* This event is fired in either of the following cases:
* <ul>
* <li>When a file that is selected to be uploaded fails to meet the file name length restriction specified in the
* <code>maxFileNameLength</code> property.</li>
* <li>When the file name length restriction changes, and the file to be uploaded fails to meet the new
* restriction.</li>
* <li>Listeners can use the item parameter to remove the incomplete item that failed to meet the restriction</li>
* </ul>
*/
fileNameLengthExceeded: {
parameters: {
/**
* The file that fails to meet the file name length restriction specified in the
* <code>maxFileNameLength</code> property.
*/
item: {type: "sap.m.upload.UploadSetItem"}
}
},
/**
* This event is fired in either of the following cases:
* <ul>
* <li>When a file that is selected to be uploaded fails to meet the file size restriction specified in the
* <code>maxFileSize</code> property.</li>
* <li>When the file size restriction changes, and the file to be uploaded fails to meet the new
* restriction.</li>
* <li>Listeners can use the item parameter to remove the incomplete item that failed to meet the restriction</li>
* </ul>
*/
fileSizeExceeded: {
parameters: {
/**
* The file that fails to meet the file size restriction specified in the
* <code>maxFileSize</code> property.
*/
item: {type: "sap.m.upload.UploadSetItem"},
/**
* The size of a file in MB, that fails to meet the file size restriction specified in the <code>maxFileSize</code> property.
* @since 1.128.0
*/
fileSize: {type: "float"}
}
},
/**
* This event is fired in either of the following cases:
* <ul>
* <li>When a file that is selected to be uploaded fails to meet the media type restriction specified in the
* <code>mediaTypes</code> property.</li>
* <li>When the media type restriction changes, and the file to be uploaded fails to meet the new
* restriction.</li>
* </ul>
*/
mediaTypeMismatch: {
parameters: {
/**
* The file that fails to meet the media type restriction specified in the
* <code>mediaTypes</code> property.
*/
item: {type: "sap.m.upload.UploadSetItem"}
}
},
/**
* This event is fired simultaneously with the respective event in the inner {@link sap.m.List} control.
*/
selectionChanged: {
parameters: {
/**
* Items whose selection status has just been changed.
*/
items: {type: "sap.m.upload.UploadSetItem[]"}
}
},
/**
* This event is fired when the user starts dragging an uploaded item.
* @event
* @param {sap.ui.base.Event} oControlEvent
* @param {sap.ui.base.EventProvider} oControlEvent.getSource
* @param {object} oControlEvent.getParameters
* @param {sap.ui.core.Element} oControlEvent.getParameters.target The target element that will be dragged
* @param {sap.ui.core.dnd.DragSession} oControlEvent.getParameters.dragSession The UI5 <code>dragSession</code> object that exists only during drag and drop
* @param {Event} oControlEvent.getParameters.browserEvent The underlying browser event
* @public
* @since 1.99
*/
itemDragStart: {
},
/**
* This event is fired when an uploaded item is dropped on the new list position.
* @event
* @param {sap.ui.base.Event} oControlEvent
* @param {sap.ui.base.EventProvider} oControlEvent.getSource
* @param {object} oControlEvent.getParameters
* @param {sap.ui.core.dnd.DragSession} oControlEvent.getParameters.dragSession The UI5 <code>dragSession</code> object that exists only during drag and drop
* @param {sap.ui.core.Element} oControlEvent.getParameters.draggedControl The element being dragged
* @param {sap.ui.core.Element} oControlEvent.getParameters.droppedControl The element being dropped
* @param {sap.ui.core.dnd.RelativeDropPosition} oControlEvent.getParameters.dropPosition The calculated position of the drop action relative to the <code>droppedControl</code>.
* @param {Event} oControlEvent.getParameters.browserEvent The underlying browser event
* @public
* @since 1.99
*/
itemDrop: {
}
}
},
renderer: Renderer
});
var UploadState = MobileLibrary.UploadState;
/* ================== */
/* Lifecycle handling */
/* ================== */
UploadSet.prototype.init = function () {
this._oRb = CoreLib.getResourceBundleFor("sap.m");
this._oList = null;
this._oEditedItem = null;
this._oItemToBeDeleted = null;
this._mListItemIdToItemMap = {};
this._oUploadButton = null;
this._oDragIndicator = false;
this._initialIllustrationClone = true;
// Drag&drop
this._$Body = null;
this._$DragDropArea = null;
this._oLastEnteredTarget = null;
this._aGroupHeadersAdded = [];
this._iFileUploaderPH = null;
this._oItemToUpdate = null;
//Setting invisible text
this._oInvisibleText = new InvisibleText();
this._oInvisibleText.toStatic();
this._oIllustratedMessage = this.getAggregation("illustratedMessage");
if (!this._oIllustratedMessage) {
this._oIllustratedMessage = new IllustratedMessage({
illustrationType: IllustratedMessageType.NoData,
illustrationSize: IllustratedMessageSize.Auto,
title: this._oRb.getText("UPLOAD_SET_NO_DATA_TEXT"),
description: this.getUploadEnabled() ? this._oRb.getText("UPLOADCOLLECTION_NO_DATA_DESCRIPTION") : " "
});
}
this._oIllustratedMessage.addIllustrationAriaLabelledBy(this._oInvisibleText.getId());
this.setAggregation("illustratedMessage", this._oIllustratedMessage);
this._oInvisibleText.setText(this._oRb.getText("UPLOAD_SET_ILLUSTRATED_MESSAGE"));
this._cloudFilePickerControl = null;
this._oListEventDelegate = null;
this.addDependent(this._oInvisibleText);
};
UploadSet.prototype.exit = function () {
if (this._oList) {
this._oList.destroy();
this._oList = null;
}
if (this._oToolbar) {
this._oToolbar.destroy();
this._oToolbar = null;
}
if (this._oFileUploader) {
this._oFileUploader.destroy();
this._oFileUploader = null;
}
if (this._oUploader) {
this._oUploader.destroy();
this._oUploader = null;
}
if (this._oIllustratedMessage) {
this._oIllustratedMessage.destroy();
this._oIllustratedMessage = null;
}
if (this._oIllustratedMessageClone) {
this._oIllustratedMessageClone.destroy();
this._oIllustratedMessageClone = null;
}
};
/* ===================== */
/* Overriden API methods */
/* ===================== */
UploadSet.prototype.onBeforeRendering = function (oEvent) {
if (this._oListEventDelegate) {
this._oList.removeEventDelegate(this._oListEventDelegate);
this._oListEventDelegate = null;
}
this._aGroupHeadersAdded = [];
this._clearGroupHeaders();
this._fillListWithUploadSetItems(this.getItems());
if (this._initialIllustrationClone) {
this._oIllustratedMessageClone = this.getAggregation("illustratedMessage").clone();
this._initialIllustrationClone = false;
}
};
UploadSet.prototype.onAfterRendering = function () {
var oInput;
if (this._oEditedItem) {
oInput = this._oEditedItem._getFileNameEdit().$("inner");
if (oInput) {
oInput.on("focus", function () {
oInput.selectText(0, oInput.val().length);
});
oInput.trigger("focus");
}
if (this._oEditedItem && this._oEditedItem.getEditState()) {
var oMarkerContainerDomRef = this._oEditedItem.getListItem() ? this._oEditedItem.getListItem().getDomRef() : null;
var oMarkerContainer = oMarkerContainerDomRef ? oMarkerContainerDomRef.querySelector(".sapMUSObjectMarkerContainer") : null;
if (oMarkerContainer) {
oMarkerContainer.setAttribute("style", "display: none");
}
}
}
this._oListEventDelegate = {
onclick: function(event) {
this._handleClick(event, this._oEditedItem);
}.bind(this)
};
this._oList.addDelegate(this._oListEventDelegate);
var aList = this.getList();
if (this._bItemRemoved) {
this._bItemRemoved = false;
var aListItems = aList.getItems();
if (aListItems.length > 0) {
aListItems[0].focus();
} else {
aList.getDomRef().querySelector(".sapMUCNoDataPage").focus();
}
}
var oNoDataDom = aList?.getDomRef()?.querySelector(".sapMUCNoDataPage");
var iCurrentHeight = oNoDataDom?.offsetHeight;
if (iCurrentHeight){
oNoDataDom.style.height = iCurrentHeight + "px";
}
if (this.getCloudFilePickerEnabled()) {
this._oFileUploader.addStyleClass("sapMUSTFileUploaderVisibility");
}
};
/**
* Handling of 'click' of the list (items + header)
* @param {sap.ui.base.Event} oEvent Event of the 'click'
* @param {Object} item List item
* @private
*/
UploadSet.prototype._handleClick = function (oEvent, item) {
var $Button = oEvent.target.closest("button");
var sId = "";
if ($Button) {
sId = $Button.id;
}
if (sId.lastIndexOf("editButton") === -1) {
if (sId.lastIndexOf("cancelButton") !== -1) {
if (item) {
this._handleItemEditCancelation(oEvent, item);
}
} else if (oEvent.target.id.lastIndexOf("thumbnail") < 0 && oEvent.target.id.lastIndexOf("icon") < 0 &&
oEvent.target.id.lastIndexOf("deleteButton") < 0 && oEvent.target.id.lastIndexOf("fileNameEdit-inner") < 0) {
if (item) {
this._handleItemEditConfirmation(oEvent, item);
}
}
}
};
UploadSet.prototype.onkeydown = function (oEvent) {
var oListItem,
oItem;
// Check the case when focus is inside an edited item
if (this._oEditedItem && this._oEditedItem._getFileNameEdit().$("inner")[0] === oEvent.target) {
oItem = this._oEditedItem;
} else if (oEvent.target) {
oListItem = Element.getElementById(oEvent.target.id);
if (oListItem) {
oItem = this._mListItemIdToItemMap[oListItem.getId()];
}
}
// No item no fun
if (!oItem) {
return;
}
switch (oEvent.keyCode) {
case KeyCodes.F2:
if (oItem._bInEditMode) {
this._handleItemEditConfirmation(oEvent, oItem);
} else {
this._handleItemEdit(oEvent, oItem);
}
break;
case KeyCodes.ESCAPE:
this._handleItemEditCancelation(oEvent, oItem);
break;
case KeyCodes.DELETE:
if (!oItem.$("fileNameEdit").hasClass("sapMInputFocused") && oItem.getEnabledRemove() && oItem.getVisibleRemove()) {
this._handleItemDelete(oEvent, oItem);
}
break;
case KeyCodes.ENTER:
if (oItem === this._oEditedItem) {
this._handleItemEditConfirmation(oEvent, oItem);
}
break;
default:
return;
}
};
UploadSet.prototype.getToolbar = function () {
if (!this._oToolbar) {
var oUploader = this.getCloudFilePickerEnabled() ? this._getCloudFilePicker() : this.getDefaultFileUploader();
this._oToolbar = this.getAggregation("toolbar");
if (!this._oToolbar) {
this._oToolbar = new OverflowToolbar(this.getId() + "-toolbar", {
content: [this._oNumberOfAttachmentsTitle, new ToolbarSpacer(), oUploader]
});
this._iFileUploaderPH = 2;
this.addDependent(this._oToolbar);
} else {
this._iFileUploaderPH = this._getFileUploaderPlaceHolderPosition(this._oToolbar);
if (this._oToolbar && this._iFileUploaderPH > -1) {
this._setFileUploaderInToolbar(oUploader);
} else if (this._oToolbar) {
// fallback position to add file uploader control if UploadSetToolbarPlaceHolder instance not found
this._oToolbar.addContent(oUploader);
}
}
if (this.getCloudFilePickerEnabled()) {
this._oToolbar.addContent(this.getDefaultFileUploader());
}
}
return this._oToolbar;
};
UploadSet.prototype._openFileUploaderPicker = function () {
this._oFileUploader.oFileUpload.click();
};
UploadSet.prototype._openCloudFilePicker = function () {
this._invokeCloudFilePicker();
};
UploadSet.prototype._itemSelectedCallback = function (oEvent) {
var oItem = oEvent.getParameter("item");
// eslint-disable-next-line default-case
switch (oItem.getText()) {
case this.getCloudFilePickerButtonText() ? this.getCloudFilePickerButtonText() : this._oRb.getText("UPLOAD_SET_DEFAULT_CFP_BUTTON_TEXT"):
this._oMenuButton
.detachEvent("defaultAction", this._openFileUploaderPicker.bind(this))
.attachEvent("defaultAction", this._openCloudFilePicker.bind(this));
this._openCloudFilePicker();
this._oMenuButton.setText(oItem.getText());
break;
case this._oRb.getText("UPLOAD_SET_DEFAULT_LFP_BUTTON_TEXT"):
this._oMenuButton
.detachEvent("defaultAction", this._openCloudFilePicker.bind(this))
.attachEvent("defaultAction", this._openFileUploaderPicker.bind(this));
this._openFileUploaderPicker();
this._oMenuButton.setText(oItem.getText());
break;
}
};
// Functions returns sNoDataText which is combination of Title and Description from the IllustratedMessage
UploadSet.prototype._setListNoDataText = function (sText, bIsDescription) {
var sNoDataText = "";
var oIllustratedMessage = this.getAggregation("illustratedMessage");
if (!sText) {
sNoDataText = oIllustratedMessage.getTitle() + " " + (this.getUploadEnabled() ? oIllustratedMessage.getDescription() : " ");
} else if (sText) {
if (bIsDescription) {
sNoDataText = oIllustratedMessage.getTitle() + " " + sText;
} else {
sNoDataText = sText + " " + (this.getUploadEnabled() ? oIllustratedMessage.getDescription() : " ");
}
}
return sNoDataText;
};
UploadSet.prototype.getNoDataText = function () {
var sNoDataText = this.getProperty("noDataText");
sNoDataText = sNoDataText || this._oRb.getText("UPLOAD_SET_NO_DATA_TEXT");
if (this._oList) {
this._oList.setNoDataText(this._setListNoDataText(sNoDataText));
}
return sNoDataText;
};
UploadSet.prototype.getNoDataDescription = function () {
var sNoDataDescription = this.getProperty("noDataDescription");
sNoDataDescription = sNoDataDescription || this._oRb.getText("UPLOADCOLLECTION_NO_DATA_DESCRIPTION");
if (this._oList) {
this._oList.setNoDataText(this._setListNoDataText(sNoDataDescription, true));
}
return sNoDataDescription;
};
UploadSet.prototype.getDragDropText = function () {
var sDragDropText = this.getProperty("dragDropText");
sDragDropText = sDragDropText || this._oRb.getText("IllustratedMessage_TITLE_UploadCollection");
return sDragDropText;
};
UploadSet.prototype.getDragDropDescription = function () {
var sDragDropDescription = this.getProperty("dragDropDescription");
sDragDropDescription = sDragDropDescription || this._oRb.getText("IllustratedMessage_DESCRIPTION_UploadCollection");
return sDragDropDescription;
};
UploadSet.prototype.setToolbar = function (oToolbar) {
this.setAggregation("toolbar", oToolbar);
this.getToolbar();
return this;
};
UploadSet.prototype.addAggregation = function (sAggregationName, oObject, bSuppressInvalidate) {
Control.prototype.addAggregation.call(this, sAggregationName, oObject, bSuppressInvalidate);
if (oObject && (sAggregationName === 'items' || sAggregationName === "incompleteItems")) {
this._projectToNewListItem(oObject);
this._refreshInnerListStyle();
}
};
UploadSet.prototype.insertAggregation = function (sAggregationName, oObject, iIndex, bSuppressInvalidate) {
Control.prototype.insertAggregation.call(this, sAggregationName, oObject, iIndex, bSuppressInvalidate);
if (oObject && (sAggregationName === 'items' || sAggregationName === 'incompleteItems')) {
this._projectToNewListItem(oObject, iIndex || 0);
this._refreshInnerListStyle();
}
};
UploadSet.prototype.removeAggregation = function (sAggregationName, oObject, bSuppressInvalidate) {
var oListItem,oItems;
Control.prototype.removeAggregation.call(this, sAggregationName, oObject, bSuppressInvalidate);
if (sAggregationName === "items" || sAggregationName === "incompleteItems") {
if (typeof oObject === 'number') { // "oObject" is the index now
oItems = this.getItems();
oListItem = oItems[oObject];
} else if (typeof oObject === 'object') { // the object itself is given or has just been retrieved
if (this.getList() && this.getList().getItems().length) {
// listItem should not be created if destruction started.
oListItem = oObject.isDestroyStarted() ? oObject : oObject._getListItem();
}
}
var oItem = this.getList().removeAggregation("items", oListItem, bSuppressInvalidate);
if (oItem && oObject) {
oItem.destroy();
oObject.destroy();
}
this._refreshInnerListStyle();
}
};
UploadSet.prototype.removeAllAggregation = function (sAggregationName, bSuppressInvalidate) {
if (sAggregationName === "items") {
this.getItems().forEach(function (oItem) {
if (this._oList) {
this._oList.removeAggregation("items", oItem._getListItem(), bSuppressInvalidate);
}
}.bind(this));
} else if (sAggregationName === "incompleteItems") {
this.getIncompleteItems().forEach(function (oItem) {
if (this._oList) {
this._oList.removeAggregation("items", oItem._getListItem(), bSuppressInvalidate);
}
}.bind(this));
}
Control.prototype.removeAllAggregation.call(this, sAggregationName, bSuppressInvalidate);
};
UploadSet.prototype.setFileTypes = function (aNewTypes) {
var aTypes = aNewTypes || null;
if (typeof aTypes === "string") {
aTypes = aTypes.split(",");
}
aTypes = (aTypes || []).map(function (s) {
return s ? s.toLowerCase() : "";
});
if (!deepEqual(this.getFileTypes(), aTypes)) {
this.setProperty("fileTypes", aTypes, true);
this.getDefaultFileUploader().setFileType(aTypes);
this._checkRestrictions();
}
return this;
};
UploadSet.prototype.setMaxFileNameLength = function (iNewMax) {
if (this.getMaxFileNameLength() !== iNewMax) {
this.setProperty("maxFileNameLength", iNewMax, true);
this.getDefaultFileUploader().setMaximumFilenameLength(iNewMax);
this._checkRestrictions();
}
return this;
};
UploadSet.prototype.setMaxFileSize = function (iNewMax) {
if (this.getMaxFileSize() !== iNewMax) {
this.setProperty("maxFileSize", iNewMax, true);
this.getDefaultFileUploader().setMaximumFileSize(iNewMax);
this._checkRestrictions();
}
return this;
};
UploadSet.prototype.setMediaTypes = function (aNewTypes) {
var aTypes = aNewTypes || null;
if (typeof aTypes === "string") {
aTypes = aTypes.split(",");
}
aTypes = (aTypes || []).map(function (s) {
return s ? s.toLowerCase() : "";
});
if (!deepEqual(this.getMediaTypes(), aTypes)) {
this.setProperty("mediaTypes", aTypes, true);
this.getDefaultFileUploader().setMimeType(aTypes);
this._checkRestrictions();
}
return this;
};
UploadSet.prototype.setShowIcons = function (bShow) {
if (bShow !== this.getShowIcons()) {
this._getAllItems().forEach(function (oItem) {
oItem._getIcon().setVisible(bShow);
});
this.setProperty("showIcons", bShow, false);
}
return this;
};
UploadSet.prototype.setTerminationEnabled = function (bEnable) {
if (bEnable !== this.getTerminationEnabled()) {
this._getAllItems().forEach(function (oItem) {
if (oItem.getUploadState() === UploadState.Uploading) {
oItem._getTerminateButton().setVisible(bEnable);
}
});
this.setProperty("terminationEnabled", bEnable, false);
}
return this;
};
UploadSet.prototype.setUploadButtonInvisible = function (bUploadButtonInvisible) {
if (bUploadButtonInvisible !== this.getUploadButtonInvisible()) {
var bVisible = !bUploadButtonInvisible;
this.getDefaultFileUploader().setVisible(bVisible);
if (this._oUploadButton) {
this._oUploadButton.setVisible(bVisible);
}
this.setProperty("uploadButtonInvisible", bUploadButtonInvisible, true);
}
return this;
};
UploadSet.prototype.setUploadEnabled = function (bEnable) {
if (bEnable !== this.getUploadEnabled()) {
this.getDefaultFileUploader().setEnabled(bEnable); // TODO: This can go, FileUploader doesn't upload anymore
if (this._oUploadButton) {
this._oUploadButton.setEnabled(bEnable);
}
this.setProperty("uploadEnabled", bEnable, false);
}
return this;
};
UploadSet.prototype.setMultiple = function (bMultiple) {
if (this.getMultiple() !== bMultiple) {
this.setProperty("multiple", bMultiple);
this.getDefaultFileUploader().setMultiple(bMultiple);
}
return this;
};
UploadSet.prototype.setDirectory = function (bDirectory) {
if (this.getDirectory() !== bDirectory) {
this.setProperty("directory", bDirectory);
this.getDefaultFileUploader().setDirectory(bDirectory);
if (bDirectory) {
this.setProperty("multiple", false); // disable multiple files selection when directory selection is enabled.
}
}
return this;
};
UploadSet.prototype.setMode = function(sMode) {
if (sMode === MobileLibrary.ListMode.Delete) {
this.setProperty("mode", MobileLibrary.ListMode.None);
Log.info("sap.m.ListMode.Delete is not supported by UploadSet. Value has been resetted to 'None'");
} else if (sMode === MobileLibrary.ListMode.MultiSelect && !this.getInstantUpload()) {
this.setProperty("mode", MobileLibrary.ListMode.None);
Log.info("sap.m.ListMode.MultiSelect is not supported by UploadSet for Pending Upload. Value has been reset to 'None'");
} else {
this.setProperty("mode", sMode);
}
if (this._oList) {
this._oList.setMode(this.getMode());
}
return this;
};
UploadSet.prototype._getIllustratedMessage = function () {
var oAggregation = this.getAggregation("illustratedMessage");
// Early return if no aggregation or the list is not empty
if (!oAggregation || !this._oList || !this._oList.getItems || this._oList.getItems().length) {
return oAggregation;
}
var oIllustratedMessageClone = this._oIllustratedMessageClone;
// Helper to set the title based on various conditions
const setTitle = (title) => {
if (title) {
oAggregation.setTitle(title);
} else if (oIllustratedMessageClone.isBound("title")) {
const boundTitle = oAggregation.mBindingInfos.title.binding.getValue();
oAggregation.setTitle(boundTitle);
} else {
oAggregation.setTitle(this._oRb.getText("UPLOAD_SET_NO_DATA_TEXT"));
}
};
// Helper to set the description based on various conditions
const setDescription = (description) => {
if (description) {
oAggregation.setDescription(this.getUploadEnabled() ? description : " ");
} else if (oIllustratedMessageClone.isBound("description")) {
const boundDescription = oAggregation.mBindingInfos.description.binding.getValue();
oAggregation.setDescription(boundDescription);
} else {
oAggregation.setDescription(
this.getUploadEnabled() ? this._oRb.getText("UPLOADCOLLECTION_NO_DATA_DESCRIPTION") : " "
);
}
};
// Set the illustrated message based on drag indicator presence
if (this._getDragIndicator()) {
oAggregation.setIllustrationType(IllustratedMessageType.DragFilesToUpload);
oAggregation.setTitle(this.getDragDropText());
oAggregation.setDescription(this.getUploadEnabled() ? this.getDragDropDescription() : " ");
} else {
oAggregation.setIllustrationType(oIllustratedMessageClone.getIllustrationType());
setTitle(oIllustratedMessageClone.getTitle());
setDescription(oIllustratedMessageClone.getDescription());
// Handle additional content
oAggregation.removeAllAdditionalContent();
if (oIllustratedMessageClone.getAdditionalContent().length) {
oAggregation.addAdditionalContent(
new Button(oIllustratedMessageClone.getAdditionalContent()[0].mProperties)
);
} else {
oAggregation.addAdditionalContent(this.getUploadButtonForIllustratedMessage());
}
}
return oAggregation;
};
UploadSet.prototype.getUploadButtonForIllustratedMessage = function () {
if (!this._oUploadButton) {
var oAccIds = this.getAggregation("illustratedMessage").getAccessibilityReferences();
var sTitleId = oAccIds.title;
var sDescriptionId = oAccIds.description;
this._oUploadButton = new Button({
id: this.getId() + "-uploadButton",
type: MobileLibrary.ButtonType.Standard,
enabled: this.getUploadEnabled(),
visible: !this.getUploadButtonInvisible(),
text: this._oRb.getText("UPLOADCOLLECTION_UPLOAD"),
ariaDescribedBy: [sTitleId,sDescriptionId],
press: function () {
var FileUploader = this.getDefaultFileUploader();
FileUploader.$().find("input[type=file]").trigger("click");
}.bind(this)
});
}
return this._oUploadButton;
};
UploadSet.prototype.setUploadUrl = function (sUploadUrl) {
this.setProperty("uploadUrl", sUploadUrl);
if (this._oUploader) {
this._oUploader.setUploadUrl(sUploadUrl);
}
return this;
};
/* ============== */
/* Public methods */
/* ============== */
/**
* Provides access to the instance of the inner {@link sap.m.List} control, so that it can be customized.
* @return {sap.m.List} The inner {@link sap.m.List} control.
* @public
*/
UploadSet.prototype.getList = function () {
if (!this._oList) {
this._oList = new List(this.getId() + "-list", {
selectionChange: [this._handleSelectionChange, this],
headerToolbar: this.getToolbar(),
dragDropConfig: [
new DragDropInfo({
dropPosition: "Between",
sourceAggregation: "items",
targetAggregation: "items",
dragStart: [this._onDragStartItem, this],
drop: [this._onDropItem, this]
})
,
new DropInfo({
dropEffect:"Move",
dropPosition:"OnOrBetween",
dragEnter: [this._onDragEnterFile, this],
drop: [this._onDropFile, this]
})
],
mode: this.getMode(),
noDataText: this._setListNoDataText()
});
this._oList.addStyleClass("sapMUCList");
this._oList.applyAriaRoleDescription("UPLOAD_SET_LIST_ROLE_DESCRIPTION");
this.addDependent(this._oList);
}
return this._oList;
};
UploadSet.prototype._onDragStartItem = function (oEvent) {
this.fireItemDragStart(oEvent);
};
UploadSet.prototype._onDropItem = function (oEvent) {
this.fireItemDrop(oEvent);
};
UploadSet.prototype._onDragEnterFile = function (oEvent) {
var oDragSession = oEvent.getParameter("dragSession");
var oDraggedControl = oDragSession.getDragControl();
this._oDragIndicator = true;
this._getIllustratedMessage();
if (oDraggedControl) {
oEvent.preventDefault();
}
};
UploadSet.prototype._onDropFile = function (oEvent) {
this._oDragIndicator = false;
this._getIllustratedMessage();
oEvent.preventDefault();
if (!this.getUploadEnabled()) {
return;
}
var oItems = oEvent.getParameter("browserEvent").dataTransfer.items;
oItems = Array.from(oItems);
// Filtering out only webkitentries (files/folders system entries) by excluding non file / directory types.
oItems = oItems.filter(function(item){
return item.webkitGetAsEntry() ? true : false;
});
var aEntryTypes = oItems.map(function (oEntry) {
var oWebKitEntry = oEntry.webkitGetAsEntry();
return {
entryType: oWebKitEntry && oWebKitEntry.isFile ? 'File' : 'Directory'
};
});
// handlding multiple property drag & drop scenarios
if (oItems && oItems.length > 1 && !this.getMultiple() && !this.getDirectory()) {
// Handling drag and drop of multiple files to upload with multiple property set
var sMessage = this._oRb.getText("UPLOADCOLLECTION_MULTIPLE_FALSE");
Log.warning("Multiple files upload is retsricted for this multiple property set");
MessageBox.error(sMessage);
return;
} else if (oItems && oItems.length > 1 && this.getMultiple() && !isFileOrFolderEntry('File', aEntryTypes)) {
var sMessageDropFilesOnly = this._oRb.getText("UPLOAD_SET_DIRECTORY_FALSE");
Log.warning("Multiple files upload is retsricted, drag & drop only files");
MessageBox.error(sMessageDropFilesOnly);
return;
}
// handling directory property drag & drop scenarios
if (oItems && oItems.length && !this.getDirectory() && isFileOrFolderEntry('Directory', aEntryTypes)) {
var sMessageDirectory = this._oRb.getText("UPLOAD_SET_DIRECTORY_FALSE");
Log.warning("Directory of files upload is retsricted for this directory property set");
MessageBox.error(sMessageDirectory);
return;
} else if (oItems && oItems.length && this.getDirectory() && !isFileOrFolderEntry('Directory', aEntryTypes)) {
var sMessageDragDropDirectory = this._oRb.getText("UPLOAD_SET_DROP_DIRECTORY");
Log.warning("Directory of files upload is retsricted, drag & drop only directories here.");
MessageBox.error(sMessageDragDropDirectory);
return;
}
if (oItems && oItems.length) {
this._getFilesFromDataTransferItems(oItems).then(function (oFiles) {
if (oFiles && oFiles.length) {
this._processNewFileObjects(oFiles);
}
}.bind(this));
}
function isFileOrFolderEntry(sType, aEntries) {
return aEntries.every(function (oEntry) {
return oEntry.entryType === sType;
});
}
};
UploadSet.prototype._getFilesFromDataTransferItems = function (dataTransferItems) {
var aFiles = [];
return new Promise(function (resolve, reject) {
var aEntriesPromises = [];
for (var i = 0; i < dataTransferItems.length; i++) {
aEntriesPromises.push(traverseFileTreePromise(dataTransferItems[i].webkitGetAsEntry()));
}
Promise.all(aEntriesPromises)
.then(function (entries) {
resolve(aFiles);
}, function(err) {
reject(err);
});
});
function traverseFileTreePromise(item) {
return new Promise(function (resolve, reject) {
if (item.isFile) {
item.file(function (oFile) {
aFiles.push(oFile);
resolve(oFile);
}, function(err){
reject(err);
});
} else if (item.isDirectory) {
var dirReader = item.createReader();
dirReader.readEntries(function (entries) {
var aEntriesPromises = [];
for (var i = 0; i < entries.length; i++) {
aEntriesPromises.push(traverseFileTreePromise(entries[i]));
}
resolve(Promise.all(aEntriesPromises));
});
}
});
}
};
UploadSet.prototype._getDragIndicator = function () {
return this._oDragIndicator;
};
/**
* Starts uploading all files that comply with the restrictions defined in the <code>fileTypes</code>,
* <code>maxFileNameLength</code>, <code>maxFileSize</code>, and <code>mediaTypes</code> properties.
* <br>This method works only when the <code>uploadEnabled</code> property is set to <code>true</code>.
* @public
*/
UploadSet.prototype.upload = function () {
if (!this.getUploadEnabled()) {
Log.warning("Upload is currently disabled for this upload set.");
return;
}
this.getIncompleteItems().forEach(function (oItem) {
this._uploadItemIfGoodToGo(oItem);
}.bind(this));
};
/**
* Starts uploading the file if it complies with the restrictions defined in the <code>fileTypes</code>,
* <code>maxFileNameLength</code>, <code>maxFileSize</code>, and <code>mediaTypes</code>
* properties.
* <br>This method works only when the <code>uploadEnabled</code> property is set to <code>true</code>.
* @param {object} oItem File to upload.
* @public
*/
UploadSet.prototype.uploadItem = function (oItem) {
this._uploadItemIfGoodToGo(oItem);
};
/**
* Returns an instance of the default <code>sap.ui.unified.FileUploader</code> used for adding files using
* the operating system's open file dialog, so that it can be customized, for example made invisible or assigned a different icon.
* @return {sap.ui.unified.FileUploader} Instance of the default <code>sap.ui.unified.FileUploader</code>.
* @public
*/
UploadSet.prototype.getDefaultFileUploader = function () {
var sTooltip = this._oRb.getText("UPLOADCOLLECTION_UPLOAD");
if (!this._oFileUploader) {
this._oFileUploader = new FileUploader(this.getId() + "-uploader", {
buttonOnly: true,
buttonText: sTooltip,
tooltip: sTooltip,
iconOnly: false,
enabled: this.getUploadEnabled(),
fileType: this.getFileTypes(),
mimeType: this.getMediaTypes(),
maximumFilenameLength: this.getMaxFileNameLength(),
maximumFileSize: this.getMaxFileSize(),
icon: "",
iconFirst: false,
multiple: this.getDirectory() ? false : this.getMultiple(),
style: "Transparent",
name: "uploadSetFileUploader",
sameFilenameAllowed: true,
useMultipart: false,
sendXHR: true,
change: [this._onFileUploaderChange, this],
uploadStart: [this._onUploadStarted, this],
uploadProgress: [this._onUploadProgressed, this],
uploadComplete: [this._onUploadCompleted, this],
uploadAborted: [this._onUploadAborted, this],
typeMissmatch: [this._fireFileTypeMismatch, this],
fileSizeExceed: [this._fireFileSizeExceed, this],
filenameLengthExceed: [this._fireFilenameLengthExceed, this],
visible: !this.getUploadButtonInvisible(),
directory: this.getDirectory()
});
}
return this._oFileUploader;
};
/**
* Attaches all necessary handlers to the given uploader instance, so that the progress and status of the upload can be
* displayed and monitored.
* This is necessary in case when custom uploader is used.
* @param {sap.m.upload.Uploader} oUploader Instance of <code>sap.m.upload.Uploader</code> to which the default request handlers are attached.
* @public
*/
UploadSet.prototype.registerUploaderEvents = function (oUploader) {
oUploader.attachUploadStarted(this._onUploadStarted.bind(this));
oUploader.attachUploadProgressed(this._onUploadProgressed.bind(this));
oUploader.attachUploadCompleted(this._onUploadCompleted.bind(this));
oUploader.attachUploadAborted(this._onUploadAborted.bind(this));
};
/**
* Returns an array containing the selected UploadSetItems.
* @returns {sap.m.upload.UploadSetItem[]} Array of all selected items
* @public
* @since 1.100.0
*/
UploadSet.prototype.getSelectedItems = function() {
var aSelectedListItems = this._oList.getSelectedItems();
return this._getUploadSetItemsByListItems(aSelectedListItems);
};
/**
* Retrieves the currently selected UploadSetItem.
* @returns {sap.m.upload.UploadSetItem | null} The currently selected item or <code>null</code>
* @public
* @since 1.100.0
*/
UploadSet.prototype.getSelectedItem = function() {
var oSelectedListItem = this._oList.getSelectedItem();
if (oSelectedListItem) {
return this._getUploadSetItemsByListItems([oSelectedListItem]);
}
return null;
};
/**
* Sets an UploadSetItem to be selected by ID. In single selection mode, the method removes the previous selection.
* @param {string} id The ID of the item whose selection is to be changed.
* @param {boolean} [select=true] The selection state of the item.
* @returns {this} this to allow method chaining
* @public
* @since 1.100.0
*/
UploadSet.prototype.setSelectedItemById = function(id, select) {
this._oList.setSelectedItemById(id + "-listItem", select);
this._setSelectedForItems([this._getUploadSetItemById(id)], select);
return this;
};
/**
* Selects or deselects the given list item.
* @param {sap.m.upload.UploadSetItem} uploadSetItem The item whose selection is to be changed. This parameter is mandatory.
* @param {boolean} [se