From b4656a5dd71ce4d34f82689bfc49804456bc18d4 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Thu, 19 Mar 2020 11:14:44 +0200 Subject: [PATCH 01/42] WIP(ui5-upload-collection): implement new webcomponent ui5-upload-collection is new webcomponent located in fiori package, which benefits and brings some of ui5-list features, but it shows different items of type ui5-upload-collection-item. It is in the responsibility of the app developer to put ui5-file-uploader in the header, create and add new ui5-upload-collection-item(s) to the collection. Main features: - header slot - items slot (default) - items have special visualisation, suitable for files representation - items have "file" property, to allow app developers to set and get file object - drag and drop overlay --- packages/fiori/bundle.esm.js | 2 + packages/fiori/src/UploadCollection.hbs | 28 +++ packages/fiori/src/UploadCollection.js | 214 ++++++++++++++++++ packages/fiori/src/UploadCollectionItem.hbs | 38 ++++ packages/fiori/src/UploadCollectionItem.js | 123 ++++++++++ .../fiori/src/themes/UploadCollection.css | 90 ++++++++ .../fiori/src/themes/UploadCollectionItem.css | 46 ++++ .../fiori/test/pages/UploadCollection.html | 85 +++++++ .../test/pages/uploadCollectionDemoHelper.js | 102 +++++++++ 9 files changed, 728 insertions(+) create mode 100644 packages/fiori/src/UploadCollection.hbs create mode 100644 packages/fiori/src/UploadCollection.js create mode 100644 packages/fiori/src/UploadCollectionItem.hbs create mode 100644 packages/fiori/src/UploadCollectionItem.js create mode 100644 packages/fiori/src/themes/UploadCollection.css create mode 100644 packages/fiori/src/themes/UploadCollectionItem.css create mode 100644 packages/fiori/test/pages/UploadCollection.html create mode 100644 packages/fiori/test/pages/uploadCollectionDemoHelper.js diff --git a/packages/fiori/bundle.esm.js b/packages/fiori/bundle.esm.js index 1dde97417f61..c9d0e50219ca 100644 --- a/packages/fiori/bundle.esm.js +++ b/packages/fiori/bundle.esm.js @@ -11,3 +11,5 @@ import ProductSwitch from "./dist/ProductSwitch.js"; import ProductSwitchItem from "./dist/ProductSwitchItem.js"; import ShellBar from "./dist/ShellBar.js"; import ShellBarItem from "./dist/ShellBarItem.js"; +import UploadCollection from "./dist/UploadCollection.js"; +import UploadCollectionItem from "./dist/UploadCollectionItem.js"; diff --git a/packages/fiori/src/UploadCollection.hbs b/packages/fiori/src/UploadCollection.hbs new file mode 100644 index 000000000000..7c2973d8811a --- /dev/null +++ b/packages/fiori/src/UploadCollection.hbs @@ -0,0 +1,28 @@ + +
+ +
+ +
+ +
+ + {{#if _showNoData}} +
+
+ +
+ No Files Found. + Drop files to upload, or use 'Upload' button +
+ {{else if _showDndOverlay}} +
+ + {{_dndOverlayText}} +
+ {{/if}} +
\ No newline at end of file diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js new file mode 100644 index 000000000000..b89226299654 --- /dev/null +++ b/packages/fiori/src/UploadCollection.js @@ -0,0 +1,214 @@ +import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; +import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; +import List from "@ui5/webcomponents/dist/List.js"; +import UploadCollectionTemplate from "./generated/templates/UploadCollectionTemplate.lit.js"; + +// Styles +import UploadCollectionCss from "./generated/themes/UploadCollection.css.js"; + +/** + * @public + */ +const metadata = { + tag: "ui5-upload-collection", + properties: /** @lends sap.ui.webcomponents.fiori.UploadCollection.prototype */ { + mode: { + type: String + }, + _showDndOverlay: { + type: Boolean + }, + _showDropOverlay: { + type: Boolean + }, + }, + managedSlots: true, + slots: /** @lends sap.ui.webcomponents.fiori.UploadCollection.prototype */ { + "default": { + propertyName: "items", + type: HTMLElement, + }, + header: { + type: HTMLElement, + }, + }, + events: /** @lends sap.ui.webcomponents.fiori.UploadCollection.prototype */ { + itemDelete: { + detail: { + item: { type: HTMLElement }, + }, + }, + }, +}; + +const ifDraggingFiles = cb => event => { + if (event.dataTransfer.types.includes("Files")) { + cb(event); + } +} + +/** + * @class + * + *

Overview

+ * + * + *

Usage

+ * + * For the ui5-upload-collection + *

ES6 Module Import

+ * + * import @ui5/webcomponents-fiori/dist/UploadCollection.js"; + * + * @constructor + * @author SAP SE + * @alias sap.ui.webcomponents.fiori.UploadCollection + * @extends UI5Element + * @tagname ui5-upload-collection + * @public + */ +class UploadCollection extends UI5Element { + static get metadata() { + return metadata; + } + + static get render() { + return litRender; + } + + static get styles() { + return UploadCollectionCss; + } + + static get template() { + return UploadCollectionTemplate; + } + + static async onDefine() { + await Promise.all([ + List.define(), + ]); + } + + constructor() { + super(); + this._listeners = { + dragenter: ifDraggingFiles(this._ondragenter.bind(this)), + dragleave: ifDraggingFiles(this._ondragleave.bind(this)), + dragover: ifDraggingFiles(this._ondragover.bind(this)), + drop: ifDraggingFiles(this._ondrop.bind(this)), + }; + + this._bodyListeners = { + dragenter: ifDraggingFiles(this._ondragenterBody.bind(this)), + dragleave: ifDraggingFiles(this._ondragleaveBody.bind(this)), + drop: ifDraggingFiles(this._ondropBody.bind(this)), + }; + } + + onBeforeRendering() { + this._removeDragAndDropListeners(); + } + + onAfterRendering() { + this._addDragAndDropListeners(); + } + + onExitDOM() { + this._removeDragAndDropListeners(); + } + + _onItemDelete(event) { + this.fireEvent("itemDelete", { ...event.detail }); + } + + _addDragAndDropListeners() { + document.body.addEventListener("dragenter", this._bodyListeners.dragenter); + document.body.addEventListener("dragleave", this._bodyListeners.dragleave); + document.body.addEventListener("drop", this._bodyListeners.drop); + + this._root.addEventListener("dragenter", this._listeners.dragenter); + this._root.addEventListener("dragover", this._listeners.dragover); + this._root.addEventListener("dragleave", this._listeners.dragleave); + this._root.addEventListener("drop", this._listeners.drop); + } + + _removeDragAndDropListeners() { + document.body.removeEventListener("dragenter", this._bodyListeners.dragenter); + document.body.removeEventListener("dragleave", this._bodyListeners.dragleave); + document.body.removeEventListener("drop", this._bodyListeners.drop); + + if (this._root) { + this._root.removeEventListener("dragenter", this._listeners.dragenter); + this._root.removeEventListener("dragover", this._listeners.dragover); + this._root.removeEventListener("dragleave", this._listeners.dragleave); + this._root.removeEventListener("drop", this._listeners.drop); + } + } + + _ondragenter(event) { + if (event.target === this._dndOverlay) { + this._showDndOverlay = true; + this._showDropOverlay = true; + } + } + + _ondrop(event) { + this._showDndOverlay = false; + } + + _ondragover(event) { + event.preventDefault() + } + + _ondragleave(event) { + if (event.target === this._dndOverlay) { + this._showDropOverlay = false; + } + } + + _ondragenterBody(event) { + this._showDndOverlay = true; + this._lastDragEnter = event.target; + } + + _ondragleaveBody(event) { + if (this._lastDragEnter === event.target) { + this._showDndOverlay = false; + } + } + + _ondropBody() { + this._showDndOverlay = false; + } + + get classes() { + return { + dndOverlay: { + "uc-dnd-overlay": true, + "uc-drag-overlay": !this._showDropOverlay, + "uc-drop-overlay": this._showDropOverlay + }, + }; + } + + get _root() { + return this.shadowRoot.querySelector(".uc-root"); + } + + get _dndOverlay() { + return this._root.querySelector(".uc-dnd-overlay") + } + + get _showNoData() { + return this.items.length === 0 && !this._showDndOverlay; + } + + get _dndOverlayText() { + return this._showDropOverlay ? "Drop files to upload" : "Drag files here"; + } +} + +UploadCollection.define(); + +export default UploadCollection; diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs new file mode 100644 index 000000000000..23b763e0ca40 --- /dev/null +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -0,0 +1,38 @@ +{{!-- + {{fileName}} + --}} + +{{>include "../../main/src/ListItem.hbs"}} + +{{#*inline "imageBegin"}} + {{#if image}} + + {{/if}} +{{/inline}} + +{{#*inline "iconBegin"}} + {{#if icon}} + + {{/if}} +{{/inline}} + +{{#*inline "listItemContent"}} +
+
{{fileName}}
+ +
+
+ {{#if editable}} + + + {{/if}} +
+{{/inline}} diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js new file mode 100644 index 000000000000..5b430843cb72 --- /dev/null +++ b/packages/fiori/src/UploadCollectionItem.js @@ -0,0 +1,123 @@ +import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; +import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; +import UploadCollectionItemTemplate from "./generated/templates/UploadCollectionItemTemplate.lit.js"; +import ListItem from "@ui5/webcomponents/dist/ListItem.js"; +import { getRegisteredNames, getIconDataSync } from "@ui5/webcomponents-base/dist/SVGIconRegistry.js"; + + +// Styles +import UploadCollectionItemCss from "./generated/themes/UploadCollectionItem.css.js"; +import Button from "@ui5/webcomponents/dist/Button.js"; + +/** + * @public + */ +const metadata = { + tag: "ui5-upload-collection-item", + properties: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { + fileName: { + type: String, + }, + description: { + type: String, + }, + image: { + type: String, + }, + icon: { + type: String, + }, + editable: { + type: Boolean, + }, + deleteDisabled: { + type: Boolean, + }, + }, + slots: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { + "default": { + type: Node, + }, + }, + events: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { + // + }, +}; + +/** + * @class + * + *

Overview

+ * + * + *

Usage

+ * + * For the ui5-upload-collection-item + *

ES6 Module Import

+ * + * import @ui5/webcomponents-fiori/dist/UploadCollectionItem.js"; + * + * @constructor + * @author SAP SE + * @alias sap.ui.webcomponents.fiori.UploadCollectionItem + * @extends UI5Element + * @tagname ui5-upload-collection-item + * @public + */ +class UploadCollectionItem extends ListItem { + static get metadata() { + return metadata; + } + + static get render() { + return litRender; + } + + static get styles() { + return [ListItem.styles ,UploadCollectionItemCss]; + } + + static get template() { + return UploadCollectionItemTemplate; + } + + static async onDefine() { + await Promise.all([ + Button.define(), + ]); + } + + // constructor() { + // super(); + // } + + onBeforeRendering() { + super.onBeforeRendering(); + let iconData = getIconDataSync("help"); + } + + /** + * @override + */ + get classes() { + const result = super.classes; + result.main["ui5-uci-root"] = true; + return result; + } + + /** + * @override + */ + get modeDelete() { + return !this.deleteDisabled && super.modeDelete; + } + + _onEdit() { + + } + +} + +UploadCollectionItem.define(); + +export default UploadCollectionItem; diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css new file mode 100644 index 000000000000..8342c845ebb6 --- /dev/null +++ b/packages/fiori/src/themes/UploadCollection.css @@ -0,0 +1,90 @@ +:host { + display: block; +} + +.uc-root { + position: relative; + height: 100%; +} + +.uc-no-files { + position: absolute; + top: 3rem; + right: 0rem; + left: 0rem; + bottom: 0rem; + box-sizing: border-box; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 1rem; + background-color: var(--sapGroup_ContentBackground); +} + +.uc-no-files .icon-container { + height: 8rem; +} + +.uc-no-files .icon-container ui5-icon { + font-size: 6rem; + width: 6rem; + height: 6rem; + color: rgba(106,109,112,0.5); + /* fade(var(--sapContent_NonInteractiveIconColor), 50); */ +} + +.uc-no-files ui5-title { + margin: 1rem 0; +} + +.uc-no-files .subtitle { + margin: 1rem 0 2rem; +} + +/* Drag and Drop */ + +.uc-dnd-overlay { + position: absolute; + top: 3rem; + right: 0rem; + left: 0rem; + bottom: 0rem; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +.uc-drag-overlay { + /* background-color: fade(var(--sapGroup_ContentBackground), 80); */ + background-color: rgba(255,255,255,0.8); + border: 0.125rem dashed var(--sapContent_ForegroundBorderColor); +} + +.uc-drop-overlay::after { + content: ""; + position: absolute; + top: 0; + right: 0rem; + left: 0rem; + bottom: 0rem; + background-color: rgba(8,84,160,0.05); + /* background-color: fade(var(--sapActiveColor), 5); */ + border: 0.125rem solid var(--sapActiveColor); +} + +.uc-dnd-overlay ui5-icon { + width: 4rem; + height: 4rem; + margin-bottom: 1rem; +} + +.uc-drop-overlay ui5-icon, +.uc-drop-overlay ui5-text { + color: var(--sapActiveColor); +} + +.uc-drop-overlay ui5-text { + font-size: var(--sapMFontHeader4Size) +} \ No newline at end of file diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css new file mode 100644 index 000000000000..f8318612dc8f --- /dev/null +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -0,0 +1,46 @@ +/* .ui5-li-content { + display: block; +} */ +/* +@import "../../../main/src/themes/ListItemBase.css"; +@import "../../../main/src/themes/ListItem.css"; */ +/* @import "../../../main/src/themes/CustomListItem.css"; */ + +:host { + height: auto; +} + +:host(:not([hidden])) { + display: block; +} + +.ui5-uci-img, .ui5-uci-icon { + width: 3rem; + height: 3rem; + margin-right: 0.75rem; +} + +.ui5-uci-icon { + font-size: 2.5rem; +} + +:host([actionable]) .ui5-uci-icon { + color: var(--sapContent_IconColor); +} + +.ui5-li-root.ui5-uci-root { + padding: 1rem; +} + +.ui5-uci-content-text-container { + flex: 1; +} + +.ui5-uci-content-buttons-container { + padding-left: 1rem; + pointer-events: all; +} + +.ui5-uci-content-buttons-container ui5-button { + margin-right: 0.125rem; +} diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html new file mode 100644 index 000000000000..26154182cb9b --- /dev/null +++ b/packages/fiori/test/pages/UploadCollection.html @@ -0,0 +1,85 @@ + + + + + + UploadCollection + + + + + + + + + +
+ Mode: + + None + Delete + MultiSelect + SingleSelect + + +
+ + +
+ Upload Files + Start Uploading +
+ + + +
+ +
+ You cannot delete this file. +
+
+ + Some description + +
+ + +
+ Attachments (0) +
+ + Upload + +
+
+ + \ No newline at end of file diff --git a/packages/fiori/test/pages/uploadCollectionDemoHelper.js b/packages/fiori/test/pages/uploadCollectionDemoHelper.js new file mode 100644 index 000000000000..4cff820c6d78 --- /dev/null +++ b/packages/fiori/test/pages/uploadCollectionDemoHelper.js @@ -0,0 +1,102 @@ +(function () { + var pendingFiles = [], + uploadCollection = document.getElementById("uploadCollection"); + + function removePendingFile (uci) { + pendingFiles = pendingFiles.filter(function (o) { + return o.associatedItem !== uci; + }); + } + + function fileExtensionToIcon(fileName) { + switch (fileName.split(".").pop()) { + case "bmp" : + case "jpg" : + case "jpeg" : + case "png" : + return "card"; + case "csv" : + case "xls" : + case "xlsx" : + return "excel-attachment"; + case "doc" : + case "docx" : + case "odt" : + return "doc-attachment"; + case "pdf" : + return "pdf-attachment"; + case "ppt" : + case "pptx" : + return "ppt-attachment"; + case "txt" : + return "document-text"; + default : + return "document"; + } + } + + function createUCI(settings) { + var uci = document.createElement("ui5-upload-collection-item"), + cont = document.createElement("ui5-label"); + + uci.fileName = settings.name; + uci.icon = fileExtensionToIcon(settings.name); + cont.classList.add("description"); + cont.wrap = true; + cont.textContent = "Last modified: " + settings.lastModifiedDate + + ", size: " + settings.size; + uci.appendChild(cont); + return uci; + } + + document.getElementById("changeMode").addEventListener("change", function(event) { + uploadCollection.mode = event.detail.selectedOption.textContent; + }); + + document.getElementById("fileUploader").addEventListener("change", function(event) { + var files = event.detail.files; + + for (var i = 0; i < files.length; i++) { + uci = createUCI(files[i]); + + uploadCollection.appendChild(uci) + pendingFiles.push({ + file: files[i], + associatedItem: uci + }); + } + }); + + document.getElementById("cb1").addEventListener("change", function(event) { + uploadCollection.items.forEach(function (item) { + item.editable = event.target.checked; + }); + }); + + uploadCollection.addEventListener("itemDelete", function (event) { + removePendingFile(event.detail.item); + uploadCollection.removeChild(event.detail.item) + }); + + document.getElementById("startUploading").addEventListener("click", function(event) { + pendingFiles.forEach(function (file) { + var oXHR = new XMLHttpRequest(); + + oXHR.open("POST", "/backend", true); + oXHR.send(file); + }); + }); + + + // DND + document.getElementById("uploadCollectionDnD").addEventListener("drop", function(event) { + event.preventDefault(); + + var files = event.dataTransfer.files; + + for (var i = 0; i < files.length; i++) { + uci = createUCI(files[i]); + document.getElementById("uploadCollectionDnD").appendChild(uci) + } + }); +})() \ No newline at end of file From 911bb3f65d276d6d07e847781cf85eb715b967b2 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Thu, 19 Mar 2020 15:18:10 +0200 Subject: [PATCH 02/42] add property "file" to UploadCollectionItem --- packages/fiori/src/UploadCollectionItem.js | 4 ++ .../test/pages/uploadCollectionDemoHelper.js | 41 +++++++------------ 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 5b430843cb72..cbbb2059edfa 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -15,6 +15,10 @@ import Button from "@ui5/webcomponents/dist/Button.js"; const metadata = { tag: "ui5-upload-collection-item", properties: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { + file: { + type: Object, + defaultValue: null, + }, fileName: { type: String, }, diff --git a/packages/fiori/test/pages/uploadCollectionDemoHelper.js b/packages/fiori/test/pages/uploadCollectionDemoHelper.js index 4cff820c6d78..797e3aeff95e 100644 --- a/packages/fiori/test/pages/uploadCollectionDemoHelper.js +++ b/packages/fiori/test/pages/uploadCollectionDemoHelper.js @@ -1,12 +1,5 @@ (function () { - var pendingFiles = [], - uploadCollection = document.getElementById("uploadCollection"); - - function removePendingFile (uci) { - pendingFiles = pendingFiles.filter(function (o) { - return o.associatedItem !== uci; - }); - } + var uploadCollection = document.getElementById("uploadCollection"); function fileExtensionToIcon(fileName) { switch (fileName.split(".").pop()) { @@ -35,16 +28,17 @@ } } - function createUCI(settings) { + function createUCI(file) { var uci = document.createElement("ui5-upload-collection-item"), cont = document.createElement("ui5-label"); - uci.fileName = settings.name; - uci.icon = fileExtensionToIcon(settings.name); + uci.file = file; + uci.fileName = file.name; + uci.icon = fileExtensionToIcon(file.name); cont.classList.add("description"); cont.wrap = true; - cont.textContent = "Last modified: " + settings.lastModifiedDate - + ", size: " + settings.size; + cont.textContent = "Last modified: " + file.lastModifiedDate + + ", size: " + file.size; uci.appendChild(cont); return uci; } @@ -57,13 +51,7 @@ var files = event.detail.files; for (var i = 0; i < files.length; i++) { - uci = createUCI(files[i]); - - uploadCollection.appendChild(uci) - pendingFiles.push({ - file: files[i], - associatedItem: uci - }); + uploadCollection.appendChild(createUCI(files[i])); } }); @@ -74,16 +62,17 @@ }); uploadCollection.addEventListener("itemDelete", function (event) { - removePendingFile(event.detail.item); uploadCollection.removeChild(event.detail.item) }); document.getElementById("startUploading").addEventListener("click", function(event) { - pendingFiles.forEach(function (file) { - var oXHR = new XMLHttpRequest(); - - oXHR.open("POST", "/backend", true); - oXHR.send(file); + uploadCollection.items.forEach(function (item) { + if (item.file) { + var oXHR = new XMLHttpRequest(); + + oXHR.open("POST", "/upload", true); + oXHR.send(item.file); + } }); }); From eac9c13ae45b53288617bef83d8b9458d6bb0bdd Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Thu, 19 Mar 2020 15:55:37 +0200 Subject: [PATCH 03/42] remove icon and image properties and add thumbnail slot --- packages/fiori/src/UploadCollectionItem.hbs | 15 +++----------- packages/fiori/src/UploadCollectionItem.js | 9 +++------ .../fiori/src/themes/UploadCollectionItem.css | 20 +++++++++++++------ .../fiori/test/pages/UploadCollection.html | 10 +++++----- .../test/pages/uploadCollectionDemoHelper.js | 12 +++++++++-- 5 files changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index 23b763e0ca40..ea4e368f5527 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -8,19 +8,10 @@ {{>include "../../main/src/ListItem.hbs"}} -{{#*inline "imageBegin"}} - {{#if image}} - - {{/if}} -{{/inline}} - -{{#*inline "iconBegin"}} - {{#if icon}} - - {{/if}} -{{/inline}} - {{#*inline "listItemContent"}} +
+ +
{{fileName}}
diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index cbbb2059edfa..a3195bd720c1 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -25,12 +25,6 @@ const metadata = { description: { type: String, }, - image: { - type: String, - }, - icon: { - type: String, - }, editable: { type: Boolean, }, @@ -42,6 +36,9 @@ const metadata = { "default": { type: Node, }, + thumbnail: { + type: HTMLElement, + } }, events: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { // diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index f8318612dc8f..9a06495b9439 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -14,22 +14,30 @@ display: block; } -.ui5-uci-img, .ui5-uci-icon { +.ui5-li-root.ui5-uci-root { + padding: 1rem; +} + +/* Thumbnail */ +.uci-thumbnail { width: 3rem; height: 3rem; margin-right: 0.75rem; } -.ui5-uci-icon { +::slotted(ui5-icon[slot="thumbnail"]) { + width: 3rem; + height: 3rem; font-size: 2.5rem; } -:host([actionable]) .ui5-uci-icon { - color: var(--sapContent_IconColor); +::slotted(img[slot="thumbnail"]) { + width: 3rem; + height: 3rem; } -.ui5-li-root.ui5-uci-root { - padding: 1rem; +:host([actionable]) ::slotted(ui5-icon[slot="thumbnail"]) { + color: var(--sapContent_IconColor); } .ui5-uci-content-text-container { diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 26154182cb9b..77de1cc5ee3d 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -57,17 +57,17 @@
-
- You cannot delete this file. -
+ +
+ You cannot delete this file. +
+ Some description diff --git a/packages/fiori/test/pages/uploadCollectionDemoHelper.js b/packages/fiori/test/pages/uploadCollectionDemoHelper.js index 797e3aeff95e..ce91361c63ca 100644 --- a/packages/fiori/test/pages/uploadCollectionDemoHelper.js +++ b/packages/fiori/test/pages/uploadCollectionDemoHelper.js @@ -1,7 +1,7 @@ (function () { var uploadCollection = document.getElementById("uploadCollection"); - function fileExtensionToIcon(fileName) { + function fileExtensionToIconName(fileName) { switch (fileName.split(".").pop()) { case "bmp" : case "jpg" : @@ -28,13 +28,21 @@ } } + function createThumbnail(fileName) { + var icon = document.createElement("ui5-icon"); + icon.name = fileExtensionToIconName(fileName); + icon.slot = "thumbnail"; + return icon; + } + function createUCI(file) { var uci = document.createElement("ui5-upload-collection-item"), cont = document.createElement("ui5-label"); + uci.appendChild(createThumbnail(file.name)); uci.file = file; uci.fileName = file.name; - uci.icon = fileExtensionToIcon(file.name); + cont.classList.add("description"); cont.wrap = true; cont.textContent = "Last modified: " + file.lastModifiedDate From 106aa551f72592e3df0158562cfe0918bce92cce Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Thu, 19 Mar 2020 17:06:32 +0200 Subject: [PATCH 04/42] make file name clickable if property is set --- packages/fiori/src/UploadCollectionItem.hbs | 16 +++++++++--- packages/fiori/src/UploadCollectionItem.js | 4 +++ .../fiori/src/themes/UploadCollectionItem.css | 26 ++++++++++++++++--- .../fiori/test/pages/UploadCollection.html | 17 +++++++----- 4 files changed, 50 insertions(+), 13 deletions(-) diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index ea4e368f5527..7a82d8d98b43 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -9,12 +9,20 @@ {{>include "../../main/src/ListItem.hbs"}} {{#*inline "listItemContent"}} -
+
-
-
{{fileName}}
- +
+ {{#if fileNameClickable}} + {{fileName}} + {{else}} + {{fileName}} + {{/if}} + {{!-- TODO: make description property? --}} +
+ +
+ {{!-- TODO: do we need attributes slot? --}}
{{#if editable}} diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index a3195bd720c1..638999c2ff4d 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -31,6 +31,10 @@ const metadata = { deleteDisabled: { type: Boolean, }, + // TODO: better name + event for click + fileNameClickable: { + type: Boolean, + }, }, slots: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { "default": { diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index 9a06495b9439..db2ba2f7c01c 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -19,7 +19,7 @@ } /* Thumbnail */ -.uci-thumbnail { +.ui5-uci-thumbnail { width: 3rem; height: 3rem; margin-right: 0.75rem; @@ -40,10 +40,30 @@ color: var(--sapContent_IconColor); } -.ui5-uci-content-text-container { +/* Content */ +.ui5-uci-content-container { flex: 1; } +.ui5-uci-file-name { + display: block; + font-size: var(--sapFontLargeSize); + margin-bottom: 0.25rem; +} + +ui5-link.ui5-uci-file-name { + pointer-events: all; +} + +.ui5-uci-description { + margin-top: 0.375rem; + font-family: var(--sapFontFamily); + font-size: var(--sapFontMediumSize); + color: var(--sapContent_LabelColor); + white-space: initial; +} + +/* Buttons */ .ui5-uci-content-buttons-container { padding-left: 1rem; pointer-events: all; @@ -51,4 +71,4 @@ .ui5-uci-content-buttons-container ui5-button { margin-right: 0.125rem; -} +} \ No newline at end of file diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 77de1cc5ee3d..774b3764bb06 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -24,9 +24,9 @@ flex: 1; } - .description { + /* .description { white-space: pre-wrap; - } + } */ ui5-upload-collection { margin: 1rem; @@ -55,20 +55,25 @@
+ + + File name is clickable. + -
- You cannot delete this file. -
+ You cannot delete this file.
- Some description + Some description From 34f352d421f081c0a52521a0cff3a2cb07977d0e Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 20 Mar 2020 11:30:39 +0200 Subject: [PATCH 05/42] add withDnd property --- packages/fiori/src/UploadCollection.js | 72 ++++++++++++------- .../fiori/src/themes/UploadCollection.css | 1 - .../fiori/src/themes/UploadCollectionItem.css | 8 --- .../fiori/test/pages/UploadCollection.html | 4 +- 4 files changed, 50 insertions(+), 35 deletions(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index b89226299654..5fa99f21d67d 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -2,10 +2,24 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import List from "@ui5/webcomponents/dist/List.js"; import UploadCollectionTemplate from "./generated/templates/UploadCollectionTemplate.lit.js"; +import ListMode from "@ui5/webcomponents/dist/types/ListMode.js"; // Styles import UploadCollectionCss from "./generated/themes/UploadCollection.css.js"; + +const DndOverlayMode = { + None: "None", + Drag: "Drag", + Drop: "Drop" +}; + +const ifDraggingFiles = cb => event => { + if (event.dataTransfer.types.includes("Files")) { + cb(event); + } +} + /** * @public */ @@ -13,13 +27,15 @@ const metadata = { tag: "ui5-upload-collection", properties: /** @lends sap.ui.webcomponents.fiori.UploadCollection.prototype */ { mode: { - type: String + type: ListMode, + defaultValue: ListMode.None, }, - _showDndOverlay: { - type: Boolean + withDnd: { + type: Boolean, }, - _showDropOverlay: { - type: Boolean + _dndOverlayMode: { + type: String, + defaultValue: DndOverlayMode.None }, }, managedSlots: true, @@ -41,12 +57,6 @@ const metadata = { }, }; -const ifDraggingFiles = cb => event => { - if (event.dataTransfer.types.includes("Files")) { - cb(event); - } -} - /** * @class * @@ -92,6 +102,7 @@ class UploadCollection extends UI5Element { constructor() { super(); + this._listeners = { dragenter: ifDraggingFiles(this._ondragenter.bind(this)), dragleave: ifDraggingFiles(this._ondragleave.bind(this)), @@ -107,15 +118,21 @@ class UploadCollection extends UI5Element { } onBeforeRendering() { - this._removeDragAndDropListeners(); + if (this.withDnd) { + this._removeDragAndDropListeners(); + } } onAfterRendering() { - this._addDragAndDropListeners(); + if (this.withDnd) { + this._addDragAndDropListeners(); + } } onExitDOM() { - this._removeDragAndDropListeners(); + if (this.withDnd) { + this._removeDragAndDropListeners(); + } } _onItemDelete(event) { @@ -148,13 +165,12 @@ class UploadCollection extends UI5Element { _ondragenter(event) { if (event.target === this._dndOverlay) { - this._showDndOverlay = true; - this._showDropOverlay = true; + this._dndOverlayMode = DndOverlayMode.Drop; } } _ondrop(event) { - this._showDndOverlay = false; + this._dndOverlayMode = DndOverlayMode.None; } _ondragover(event) { @@ -163,31 +179,34 @@ class UploadCollection extends UI5Element { _ondragleave(event) { if (event.target === this._dndOverlay) { - this._showDropOverlay = false; + this._dndOverlayMode = DndOverlayMode.Drag; } } _ondragenterBody(event) { - this._showDndOverlay = true; this._lastDragEnter = event.target; + + if (this._dndOverlayMode !== DndOverlayMode.Drop) { + this._dndOverlayMode = DndOverlayMode.Drag; + } } _ondragleaveBody(event) { if (this._lastDragEnter === event.target) { - this._showDndOverlay = false; + this._dndOverlayMode = DndOverlayMode.None; } } _ondropBody() { - this._showDndOverlay = false; + this._dndOverlayMode = "None"; } get classes() { return { dndOverlay: { "uc-dnd-overlay": true, - "uc-drag-overlay": !this._showDropOverlay, - "uc-drop-overlay": this._showDropOverlay + "uc-drag-overlay": this._dndOverlayMode === DndOverlayMode.Drag, + "uc-drop-overlay": this._dndOverlayMode === DndOverlayMode.Drop, }, }; } @@ -200,12 +219,17 @@ class UploadCollection extends UI5Element { return this._root.querySelector(".uc-dnd-overlay") } + get _showDndOverlay() { + return this._dndOverlayMode !== DndOverlayMode.None; + } + get _showNoData() { return this.items.length === 0 && !this._showDndOverlay; } get _dndOverlayText() { - return this._showDropOverlay ? "Drop files to upload" : "Drag files here"; + //TODO: make this translatable + return this._dndOverlayMode === DndOverlayMode.Drag ? "Drag files here" : "Drop files to upload"; } } diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css index 8342c845ebb6..45be878cb4e1 100644 --- a/packages/fiori/src/themes/UploadCollection.css +++ b/packages/fiori/src/themes/UploadCollection.css @@ -43,7 +43,6 @@ } /* Drag and Drop */ - .uc-dnd-overlay { position: absolute; top: 3rem; diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index db2ba2f7c01c..2192c9760407 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -1,11 +1,3 @@ -/* .ui5-li-content { - display: block; -} */ -/* -@import "../../../main/src/themes/ListItemBase.css"; -@import "../../../main/src/themes/ListItem.css"; */ -/* @import "../../../main/src/themes/CustomListItem.css"; */ - :host { height: auto; } diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 774b3764bb06..246489220b96 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -46,7 +46,7 @@
- +
Upload Files Start Uploading @@ -77,7 +77,7 @@ - +
Attachments (0)
From eaa8df775849b317beef7283e23dd5ab65082bfe Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 20 Mar 2020 14:11:19 +0200 Subject: [PATCH 06/42] rename withDnd property to noDnd --- packages/fiori/src/UploadCollection.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index 5fa99f21d67d..4cf84d199215 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -30,7 +30,7 @@ const metadata = { type: ListMode, defaultValue: ListMode.None, }, - withDnd: { + noDnd: { type: Boolean, }, _dndOverlayMode: { @@ -118,19 +118,19 @@ class UploadCollection extends UI5Element { } onBeforeRendering() { - if (this.withDnd) { + if (!this.noDnd) { this._removeDragAndDropListeners(); } } onAfterRendering() { - if (this.withDnd) { + if (!this.noDnd) { this._addDragAndDropListeners(); } } onExitDOM() { - if (this.withDnd) { + if (!this.noDnd) { this._removeDragAndDropListeners(); } } From aa7dda321be94889a56407bf25fbcad10ec71336 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 20 Mar 2020 14:17:27 +0200 Subject: [PATCH 07/42] rename property deleteDisabled to noDelete --- packages/fiori/src/UploadCollectionItem.hbs | 10 ---------- packages/fiori/src/UploadCollectionItem.js | 15 ++------------- packages/fiori/test/pages/UploadCollection.html | 2 +- 3 files changed, 3 insertions(+), 24 deletions(-) diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index 7a82d8d98b43..30ef8ba54602 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -1,11 +1,3 @@ -{{!-- - {{fileName}} - --}} - {{>include "../../main/src/ListItem.hbs"}} {{#*inline "listItemContent"}} @@ -18,11 +10,9 @@ {{else}} {{fileName}} {{/if}} - {{!-- TODO: make description property? --}}
- {{!-- TODO: do we need attributes slot? --}}
{{#if editable}} diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 638999c2ff4d..ad8fbca3c768 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -2,8 +2,6 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import UploadCollectionItemTemplate from "./generated/templates/UploadCollectionItemTemplate.lit.js"; import ListItem from "@ui5/webcomponents/dist/ListItem.js"; -import { getRegisteredNames, getIconDataSync } from "@ui5/webcomponents-base/dist/SVGIconRegistry.js"; - // Styles import UploadCollectionItemCss from "./generated/themes/UploadCollectionItem.css.js"; @@ -28,7 +26,7 @@ const metadata = { editable: { type: Boolean, }, - deleteDisabled: { + noDelete: { type: Boolean, }, // TODO: better name + event for click @@ -92,15 +90,6 @@ class UploadCollectionItem extends ListItem { ]); } - // constructor() { - // super(); - // } - - onBeforeRendering() { - super.onBeforeRendering(); - let iconData = getIconDataSync("help"); - } - /** * @override */ @@ -114,7 +103,7 @@ class UploadCollectionItem extends ListItem { * @override */ get modeDelete() { - return !this.deleteDisabled && super.modeDelete; + return !this.noDelete && super.modeDelete; } _onEdit() { diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 246489220b96..de21f00bc4c6 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -64,7 +64,7 @@ You cannot delete this file. From e6a42077f4f8c718231fd7fa6c9f07536cb07b39 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Mon, 23 Mar 2020 12:24:55 +0200 Subject: [PATCH 08/42] add edit functionality --- packages/fiori/src/UploadCollection.js | 15 ++++- packages/fiori/src/UploadCollectionItem.hbs | 36 ++++++---- packages/fiori/src/UploadCollectionItem.js | 67 +++++++++++++++---- .../fiori/src/themes/UploadCollectionItem.css | 26 ++++++- .../fiori/test/pages/UploadCollection.html | 1 + .../test/pages/uploadCollectionDemoHelper.js | 4 +- packages/main/src/ListItem.hbs | 9 +++ packages/main/src/ListItem.js | 8 +++ packages/main/src/types/ListItemType.js | 7 ++ 9 files changed, 140 insertions(+), 33 deletions(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index 4cf84d199215..ca374749763b 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -49,11 +49,16 @@ const metadata = { }, }, events: /** @lends sap.ui.webcomponents.fiori.UploadCollection.prototype */ { - itemDelete: { + fileDeleted: { detail: { item: { type: HTMLElement }, }, }, + fileRenamed: { + detail: { + item: { type: HTMLElement }, + }, + } }, }; @@ -115,6 +120,8 @@ class UploadCollection extends UI5Element { dragleave: ifDraggingFiles(this._ondragleaveBody.bind(this)), drop: ifDraggingFiles(this._ondropBody.bind(this)), }; + + this.addEventListener("_rename", this._onFileRenamed); } onBeforeRendering() { @@ -136,7 +143,7 @@ class UploadCollection extends UI5Element { } _onItemDelete(event) { - this.fireEvent("itemDelete", { ...event.detail }); + this.fireEvent("fileDeleted", { item: event.detail.item }); } _addDragAndDropListeners() { @@ -201,6 +208,10 @@ class UploadCollection extends UI5Element { this._dndOverlayMode = "None"; } + _onFileRenamed(event) { + this.fireEvent("fileRenamed", { item: event.target }); + } + get classes() { return { dndOverlay: { diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index 30ef8ba54602..1701d8e48b36 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -5,23 +5,31 @@
- {{#if fileNameClickable}} - {{fileName}} - {{else}} - {{fileName}} + {{#if _editing}} +
+ + {{_fileExtension}} +
+ {{else }} + {{#if fileNameClickable}} + {{fileName}} + {{else}} + {{fileName}} + {{/if}} {{/if}}
-
- {{#if editable}} - - - {{/if}} -
+ + {{#if _editing}} +
+ Rename + Cancel +
+ {{/if}} {{/inline}} diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index ad8fbca3c768..b8015eb46484 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -20,12 +20,6 @@ const metadata = { fileName: { type: String, }, - description: { - type: String, - }, - editable: { - type: Boolean, - }, noDelete: { type: Boolean, }, @@ -33,6 +27,9 @@ const metadata = { fileNameClickable: { type: Boolean, }, + _editing: { + type: Boolean + } }, slots: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { "default": { @@ -43,7 +40,7 @@ const metadata = { } }, events: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { - // + _rename: { } }, }; @@ -77,7 +74,7 @@ class UploadCollectionItem extends ListItem { } static get styles() { - return [ListItem.styles ,UploadCollectionItemCss]; + return [ListItem.styles, UploadCollectionItemCss]; } static get template() { @@ -90,13 +87,56 @@ class UploadCollectionItem extends ListItem { ]); } + onBeforeRendering() { + if (!this.focused) { + this._editing = false; + } + } + + onAfterRendering() { + if (this.focused && this._editing) { + const inp = this.shadowRoot.getElementById("ui5-uci-edit-input"); + inp.focus(); + // TODO: find way to select input's value + // inp.setSelectionRange(0, this._fileNameWithoutExtension.length); + } + } + + /** + * @override + */ + onDetailClick(event) { + super.onDetailClick(event); + this._editing = true; + } + + _onInputChange(event) { + if (this.shadowRoot.getElementById("ui5-uci-edit-cancel").active) { + return; + } + + this._editing = false; + this.fileName = event.target.value; + this.fireEvent("_rename"); + } + + _onRenameCancel(event) { + this._editing = false; + } + /** * @override */ get classes() { const result = super.classes; - result.main["ui5-uci-root"] = true; - return result; + + return { + main: { + ...result.main, + "ui5-uci-root": true, + "ui5-uci-root-edit": this._editing + } + } } /** @@ -106,10 +146,13 @@ class UploadCollectionItem extends ListItem { return !this.noDelete && super.modeDelete; } - _onEdit() { - + get _fileNameWithoutExtension() { + return this.fileName.split(".")[0]; } + get _fileExtension() { + return this.fileName.includes(".") ? `.${this.fileName.split(".").pop()}` : ""; + } } UploadCollectionItem.define(); diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index 2192c9760407..52572ca400cd 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -55,12 +55,32 @@ ui5-link.ui5-uci-file-name { white-space: initial; } +/* Edit mode */ +.ui5-uci-edit-container ui5-input { + width: 60%; + pointer-events: all; +} + +.ui5-uci-file-extension { + font-family: var(--sapFontFamily); + font-size: var(--sapFontMediumSize); + color: var(--sapTextColor); + white-space: no-wrap; + overflow: hidden; + margin-left: 0.5rem; + width: 40%; +} + + /* Buttons */ -.ui5-uci-content-buttons-container { - padding-left: 1rem; +.ui5-uci-root-edit .ui5-li-detailbtn, +.ui5-uci-root-edit .ui5-li-deletebtn { + display: none; +} +.ui5-uci-edit-buttons { pointer-events: all; } -.ui5-uci-content-buttons-container ui5-button { +ui5-uci-edit-rename-btn { margin-right: 0.125rem; } \ No newline at end of file diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index de21f00bc4c6..7f622797e21e 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -64,6 +64,7 @@ diff --git a/packages/fiori/test/pages/uploadCollectionDemoHelper.js b/packages/fiori/test/pages/uploadCollectionDemoHelper.js index ce91361c63ca..87d07f1d4513 100644 --- a/packages/fiori/test/pages/uploadCollectionDemoHelper.js +++ b/packages/fiori/test/pages/uploadCollectionDemoHelper.js @@ -65,11 +65,11 @@ document.getElementById("cb1").addEventListener("change", function(event) { uploadCollection.items.forEach(function (item) { - item.editable = event.target.checked; + item.type = event.target.checked ? "Detail" : "Active"; }); }); - uploadCollection.addEventListener("itemDelete", function (event) { + uploadCollection.addEventListener("fileDeleted", function (event) { uploadCollection.removeChild(event.detail.item) }); diff --git a/packages/main/src/ListItem.hbs b/packages/main/src/ListItem.hbs index 6aea94dd9b85..3abbb1ad4215 100644 --- a/packages/main/src/ListItem.hbs +++ b/packages/main/src/ListItem.hbs @@ -23,6 +23,15 @@
{{> iconEnd}} + {{#if typeDetail}} +
+ +
+ {{/if}} {{#if placeSelectionElementAfter}} {{> selectionElement}} diff --git a/packages/main/src/ListItem.js b/packages/main/src/ListItem.js index 5dcdfbb70022..95d34117e420 100644 --- a/packages/main/src/ListItem.js +++ b/packages/main/src/ListItem.js @@ -220,6 +220,10 @@ class ListItem extends ListItemBase { this.fireEvent("_selectionRequested", { item: this, selectionComponentPressed: false }); } + onDetailClick(event) { + this.fireEvent("detailClick", { item: this, selected: this.selected }); + } + fireItemPress(event) { if (this.isInactive) { return; @@ -257,6 +261,10 @@ class ListItem extends ListItemBase { get modeDelete() { return this._mode === ListMode.Delete; } + + get typeDetail() { + return this.type === ListItemType.Detail; + } } export default ListItem; diff --git a/packages/main/src/types/ListItemType.js b/packages/main/src/types/ListItemType.js index 676bb180f029..7d26a8236910 100644 --- a/packages/main/src/types/ListItemType.js +++ b/packages/main/src/types/ListItemType.js @@ -18,6 +18,13 @@ const ListItemTypes = { * @type {Active} */ Active: "Active", + + /** + * Enables detail button of the list item that fires detailClick event. + * @public + * @type {Detail} + */ + Detail: "Detail", }; /** From 96c2ba0dfec1897a8bd62d83c3c6279e6a2a85e9 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Mon, 23 Mar 2020 15:35:04 +0200 Subject: [PATCH 09/42] add event listeners for drag and drop on the body only once --- packages/fiori/src/UploadCollection.js | 100 ++++++++++++++---- .../fiori/test/pages/UploadCollection.html | 6 +- 2 files changed, 81 insertions(+), 25 deletions(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index ca374749763b..8df108ef7610 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -7,17 +7,74 @@ import ListMode from "@ui5/webcomponents/dist/types/ListMode.js"; // Styles import UploadCollectionCss from "./generated/themes/UploadCollection.css.js"; - const DndOverlayMode = { None: "None", Drag: "Drag", Drop: "Drop" }; -const ifDraggingFiles = cb => event => { - if (event.dataTransfer.types.includes("Files")) { - cb(event); - } +const draggingFiles = event => { + return event.dataTransfer.types.includes("Files"); +} + +/** + * Handles drag and drop event listeners on document.body. + * Ensures that there is only 1 listener attached. + */ +const bodyDnDHandler = { + _lastDragEnter: null, + _uploadCollections: new Set(), + _globalHandlersAttached: false, + _ondragenter: event => { + if (!draggingFiles(event)) { + return; + } + + bodyDnDHandler._lastDragEnter = event.target; + bodyDnDHandler._uploadCollections.forEach(uc => { + if (uc._dndOverlayMode !== DndOverlayMode.Drop) { + uc._dndOverlayMode = DndOverlayMode.Drag; + } + }); + }, + _ondragleave: event => { + bodyDnDHandler._uploadCollections.forEach(uc => { + if (bodyDnDHandler._lastDragEnter === event.target) { + uc._dndOverlayMode = DndOverlayMode.None; + } + }); + }, + _ondrop: () => { + bodyDnDHandler._uploadCollections.forEach(uc => { + uc._dndOverlayMode = DndOverlayMode.None; + }); + }, + _attachGlobalHandlers: function() { + if (!this._globalHandlersAttached) { + document.body.addEventListener("dragenter", this._ondragenter); + document.body.addEventListener("dragleave", this._ondragleave); + document.body.addEventListener("drop", this._ondrop); + this._globalHandlersAttached = true; + } + }, + _detachGlobalHandlers: function() { + document.body.removeEventListener("dragenter", this._ondragenter); + document.body.removeEventListener("dragleave", this._dragleave); + document.body.removeEventListener("drop", this._ondrop); + this._globalHandlersAttached = false; + + }, + addUploadCollectionInstance: function(uploadCollections) { + this._uploadCollections.add(uploadCollections); + this._attachGlobalHandlers(); + }, + removeUploadCollectionInstance: () => { + this.uploadCollections.delete(uploadCollections); + + if (this.uploadCollections.size === 0) { + this._detachGlobalHandlers(); + } + }, } /** @@ -109,21 +166,21 @@ class UploadCollection extends UI5Element { super(); this._listeners = { - dragenter: ifDraggingFiles(this._ondragenter.bind(this)), - dragleave: ifDraggingFiles(this._ondragleave.bind(this)), - dragover: ifDraggingFiles(this._ondragover.bind(this)), - drop: ifDraggingFiles(this._ondrop.bind(this)), - }; - - this._bodyListeners = { - dragenter: ifDraggingFiles(this._ondragenterBody.bind(this)), - dragleave: ifDraggingFiles(this._ondragleaveBody.bind(this)), - drop: ifDraggingFiles(this._ondropBody.bind(this)), + dragenter: this._ondragenter.bind(this), + dragleave: this._ondragleave.bind(this), + dragover: this._ondragover.bind(this), + drop: this._ondrop.bind(this), }; this.addEventListener("_rename", this._onFileRenamed); } + onEnterDOM() { + if (!this.noDnd) { + bodyDnDHandler.addUploadCollectionInstance(this); + } + } + onBeforeRendering() { if (!this.noDnd) { this._removeDragAndDropListeners(); @@ -138,6 +195,7 @@ class UploadCollection extends UI5Element { onExitDOM() { if (!this.noDnd) { + bodyDnDHandler.removeUploadCollectionInstance(this); this._removeDragAndDropListeners(); } } @@ -147,10 +205,6 @@ class UploadCollection extends UI5Element { } _addDragAndDropListeners() { - document.body.addEventListener("dragenter", this._bodyListeners.dragenter); - document.body.addEventListener("dragleave", this._bodyListeners.dragleave); - document.body.addEventListener("drop", this._bodyListeners.drop); - this._root.addEventListener("dragenter", this._listeners.dragenter); this._root.addEventListener("dragover", this._listeners.dragover); this._root.addEventListener("dragleave", this._listeners.dragleave); @@ -158,10 +212,6 @@ class UploadCollection extends UI5Element { } _removeDragAndDropListeners() { - document.body.removeEventListener("dragenter", this._bodyListeners.dragenter); - document.body.removeEventListener("dragleave", this._bodyListeners.dragleave); - document.body.removeEventListener("drop", this._bodyListeners.drop); - if (this._root) { this._root.removeEventListener("dragenter", this._listeners.dragenter); this._root.removeEventListener("dragover", this._listeners.dragover); @@ -171,6 +221,10 @@ class UploadCollection extends UI5Element { } _ondragenter(event) { + if (!draggingFiles(event)) { + return; + } + if (event.target === this._dndOverlay) { this._dndOverlayMode = DndOverlayMode.Drop; } diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 7f622797e21e..00da098942eb 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -46,7 +46,9 @@
- +

This element is draggable

+ +
Upload Files Start Uploading @@ -78,7 +80,7 @@ - +
Attachments (0)
From 56a666f747ee32836d8290b7c5469c80404b5f57 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Mon, 23 Mar 2020 16:58:09 +0200 Subject: [PATCH 10/42] make all texts translatable --- packages/fiori/src/UploadCollection.hbs | 4 +- packages/fiori/src/UploadCollection.js | 39 ++++++++++++++++--- packages/fiori/src/UploadCollectionItem.hbs | 4 +- packages/fiori/src/UploadCollectionItem.js | 25 +++++++++++- .../fiori/src/i18n/messagebundle.properties | 17 ++++++++ 5 files changed, 78 insertions(+), 11 deletions(-) diff --git a/packages/fiori/src/UploadCollection.hbs b/packages/fiori/src/UploadCollection.hbs index 7c2973d8811a..6f2f73ce469c 100644 --- a/packages/fiori/src/UploadCollection.hbs +++ b/packages/fiori/src/UploadCollection.hbs @@ -16,8 +16,8 @@
- No Files Found. - Drop files to upload, or use 'Upload' button + {{_noDataText}} + {{_noDataDescription}}
{{else if _showDndOverlay}}
diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index 8df108ef7610..a1fef788f354 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -1,8 +1,17 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; +import { getI18nBundle, fetchI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import { + UPLOADCOLLECTION_NO_DATA_TEXT, + UPLOADCOLLECTION_NO_DATA_DESCRIPTION, + UPLOADCOLLECTION_DRAG_FILE_INDICATOR, + UPLOADCOLLECTION_DROP_FILE_INDICATOR +} from "./generated/i18n/i18n-defaults.js"; +import ListMode from "@ui5/webcomponents/dist/types/ListMode.js"; import List from "@ui5/webcomponents/dist/List.js"; + +// Template import UploadCollectionTemplate from "./generated/templates/UploadCollectionTemplate.lit.js"; -import ListMode from "@ui5/webcomponents/dist/types/ListMode.js"; // Styles import UploadCollectionCss from "./generated/themes/UploadCollection.css.js"; @@ -19,7 +28,8 @@ const draggingFiles = event => { /** * Handles drag and drop event listeners on document.body. - * Ensures that there is only 1 listener attached. + * Ensures that there is only 1 listener per type attached (drag, drop, leave). Event listeners will be only attached when + * there is at least 1 UploadCollection registered in the set. */ const bodyDnDHandler = { _lastDragEnter: null, @@ -68,7 +78,7 @@ const bodyDnDHandler = { this._uploadCollections.add(uploadCollections); this._attachGlobalHandlers(); }, - removeUploadCollectionInstance: () => { + removeUploadCollectionInstance: function() { this.uploadCollections.delete(uploadCollections); if (this.uploadCollections.size === 0) { @@ -90,6 +100,12 @@ const metadata = { noDnd: { type: Boolean, }, + noDataText:{ + type: String, + }, + noDataDescription:{ + type: String, + }, _dndOverlayMode: { type: String, defaultValue: DndOverlayMode.None @@ -159,12 +175,14 @@ class UploadCollection extends UI5Element { static async onDefine() { await Promise.all([ List.define(), + fetchI18nBundle("@ui5/webcomponents"), ]); } constructor() { super(); + this.i18nBundle = getI18nBundle("@ui5/webcomponents"); this._listeners = { dragenter: this._ondragenter.bind(this), dragleave: this._ondragleave.bind(this), @@ -292,9 +310,20 @@ class UploadCollection extends UI5Element { return this.items.length === 0 && !this._showDndOverlay; } + get _noDataText() { + return this.noDataText || this.i18nBundle.getText(UPLOADCOLLECTION_NO_DATA_TEXT); + } + + get _noDataDescription() { + return this.noDataDescription || this.i18nBundle.getText(UPLOADCOLLECTION_NO_DATA_DESCRIPTION); + } + get _dndOverlayText() { - //TODO: make this translatable - return this._dndOverlayMode === DndOverlayMode.Drag ? "Drag files here" : "Drop files to upload"; + if (this._dndOverlayMode === DndOverlayMode.Drag) { + return this.i18nBundle.getText(UPLOADCOLLECTION_DRAG_FILE_INDICATOR); + } else { + return this.i18nBundle.getText(UPLOADCOLLECTION_DROP_FILE_INDICATOR); + } } } diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index 1701d8e48b36..35eb56381360 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -28,8 +28,8 @@ {{#if _editing}}
- Rename - Cancel + {{_renameBtnText}} + {{_cancelRenameBtnText}}
{{/if}} {{/inline}} diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index b8015eb46484..572287cd5837 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -1,11 +1,18 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; -import UploadCollectionItemTemplate from "./generated/templates/UploadCollectionItemTemplate.lit.js"; +import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import { + UPLOADCOLLECTIONITEM_CANCELBUTTON_TEXT, + UPLOADCOLLECTIONITEM_RENAMEBUTTON_TEXT, +} from "./generated/i18n/i18n-defaults.js"; +import Button from "@ui5/webcomponents/dist/Button.js"; import ListItem from "@ui5/webcomponents/dist/ListItem.js"; +// Template +import UploadCollectionItemTemplate from "./generated/templates/UploadCollectionItemTemplate.lit.js"; + // Styles import UploadCollectionItemCss from "./generated/themes/UploadCollectionItem.css.js"; -import Button from "@ui5/webcomponents/dist/Button.js"; /** * @public @@ -84,9 +91,15 @@ class UploadCollectionItem extends ListItem { static async onDefine() { await Promise.all([ Button.define(), + fetchI18nBundle("@ui5/webcomponents"), ]); } + constructor() { + super(); + this.i18nBundle = getI18nBundle("@ui5/webcomponents"); + } + onBeforeRendering() { if (!this.focused) { this._editing = false; @@ -153,6 +166,14 @@ class UploadCollectionItem extends ListItem { get _fileExtension() { return this.fileName.includes(".") ? `.${this.fileName.split(".").pop()}` : ""; } + + get _renameBtnText() { + return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_RENAMEBUTTON_TEXT); + } + + get _cancelRenameBtnText() { + return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_CANCELBUTTON_TEXT); + } } UploadCollectionItem.define(); diff --git a/packages/fiori/src/i18n/messagebundle.properties b/packages/fiori/src/i18n/messagebundle.properties index 9924080ee5fb..9ddd2a47a6b4 100644 --- a/packages/fiori/src/i18n/messagebundle.properties +++ b/packages/fiori/src/i18n/messagebundle.properties @@ -1,3 +1,20 @@ #This is the resource bundle for the UI5 Web Components #__ldi.translation.uuid=95d47730-48a4-4d6d-92f6-61f8c9d8f274 +#XBUT: Button text for cancel button in the upload collection +UPLOADCOLLECTIONITEM_CANCELBUTTON_TEXT=Cancel + +#XBUT: Text for Rename button in the upload collection in case of renaming a file +UPLOADCOLLECTIONITEM_RENAMEBUTTON_TEXT=Rename + +#XMSG: Message text for no data text in the upload collection +UPLOADCOLLECTION_NO_DATA_TEXT=No files found. + +#XMSG: Message text for no data description in the upload collection +UPLOADCOLLECTION_NO_DATA_DESCRIPTION=Drop files to upload, or use the "Upload" button. + +#XMSG: Message text indicating where to drag +UPLOADCOLLECTION_DRAG_FILE_INDICATOR=Drag files here + +#XMSG: Message text indicating where to drop file and upload +UPLOADCOLLECTION_DROP_FILE_INDICATOR=Drop files to upload \ No newline at end of file From 7cdba4d4f78fe74990fb25c2c40bd0bab169d760 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 10:27:59 +0200 Subject: [PATCH 11/42] add missing css vars --- packages/fiori/src/UploadCollection.hbs | 2 +- packages/fiori/src/i18n/messagebundle.properties | 2 +- packages/fiori/src/themes/UploadCollection.css | 16 +++++++++------- .../fiori/src/themes/UploadCollectionItem.css | 1 + .../themes/base/UploadCollection-parameters.css | 4 ++++ .../src/themes/sap_belize/parameters-bundle.css | 3 ++- .../themes/sap_belize_hcb/parameters-bundle.css | 3 ++- .../themes/sap_belize_hcw/parameters-bundle.css | 3 ++- .../src/themes/sap_fiori_3/parameters-bundle.css | 3 ++- .../sap_fiori_3_dark/parameters-bundle.css | 3 ++- .../themes/sap_belize/base-parameters-vars.less | 3 +++ .../src/themes/sap_belize/base-parameters.less | 5 ++++- .../sap_belize_hcb/base-parameters-vars.less | 3 +++ .../themes/sap_belize_hcb/base-parameters.less | 5 ++++- .../sap_belize_hcw/base-parameters-vars.less | 3 +++ .../themes/sap_belize_hcw/base-parameters.less | 4 +++- .../themes/sap_fiori_3/base-parameters-vars.less | 3 +++ .../src/themes/sap_fiori_3/base-parameters.less | 5 ++++- .../sap_fiori_3_dark/base-parameters-vars.less | 3 +++ .../themes/sap_fiori_3_dark/base-parameters.less | 5 ++++- 20 files changed, 60 insertions(+), 19 deletions(-) create mode 100644 packages/fiori/src/themes/base/UploadCollection-parameters.css diff --git a/packages/fiori/src/UploadCollection.hbs b/packages/fiori/src/UploadCollection.hbs index 6f2f73ce469c..9f3aab757025 100644 --- a/packages/fiori/src/UploadCollection.hbs +++ b/packages/fiori/src/UploadCollection.hbs @@ -14,7 +14,7 @@ {{#if _showNoData}}
- +
{{_noDataText}} {{_noDataDescription}} diff --git a/packages/fiori/src/i18n/messagebundle.properties b/packages/fiori/src/i18n/messagebundle.properties index 9ddd2a47a6b4..e9394a7f2e8f 100644 --- a/packages/fiori/src/i18n/messagebundle.properties +++ b/packages/fiori/src/i18n/messagebundle.properties @@ -11,7 +11,7 @@ UPLOADCOLLECTIONITEM_RENAMEBUTTON_TEXT=Rename UPLOADCOLLECTION_NO_DATA_TEXT=No files found. #XMSG: Message text for no data description in the upload collection -UPLOADCOLLECTION_NO_DATA_DESCRIPTION=Drop files to upload, or use the "Upload" button. +UPLOADCOLLECTION_NO_DATA_DESCRIPTION=Drop files to upload, or use the Upload button. #XMSG: Message text indicating where to drag UPLOADCOLLECTION_DRAG_FILE_INDICATOR=Drag files here diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css index 45be878cb4e1..c999d98ea714 100644 --- a/packages/fiori/src/themes/UploadCollection.css +++ b/packages/fiori/src/themes/UploadCollection.css @@ -7,6 +7,7 @@ height: 100%; } +/* No Files */ .uc-no-files { position: absolute; top: 3rem; @@ -30,16 +31,19 @@ font-size: 6rem; width: 6rem; height: 6rem; - color: rgba(106,109,112,0.5); - /* fade(var(--sapContent_NonInteractiveIconColor), 50); */ + color: var(--sapUploadCollection_NoFilesIconColor); } .uc-no-files ui5-title { + font-size: var(--ui5_upload_collection_level_2Size); + color: var(--sapGroup_TitleTextColor); margin: 1rem 0; } .uc-no-files .subtitle { - margin: 1rem 0 2rem; + font-size: var(--ui5_upload_collection_level_5Size); + color: var(--sapContent_LabelColor); + margin-bottom: 2rem; } /* Drag and Drop */ @@ -56,8 +60,7 @@ } .uc-drag-overlay { - /* background-color: fade(var(--sapGroup_ContentBackground), 80); */ - background-color: rgba(255,255,255,0.8); + background-color: var(--sapUploadCollection_DragOverlayBackground); border: 0.125rem dashed var(--sapContent_ForegroundBorderColor); } @@ -68,8 +71,7 @@ right: 0rem; left: 0rem; bottom: 0rem; - background-color: rgba(8,84,160,0.05); - /* background-color: fade(var(--sapActiveColor), 5); */ + background-color: var(--sapUploadCollection_DropOverlayBackground); border: 0.125rem solid var(--sapActiveColor); } diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index 52572ca400cd..20b9609637b9 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -77,6 +77,7 @@ ui5-link.ui5-uci-file-name { .ui5-uci-root-edit .ui5-li-deletebtn { display: none; } + .ui5-uci-edit-buttons { pointer-events: all; } diff --git a/packages/fiori/src/themes/base/UploadCollection-parameters.css b/packages/fiori/src/themes/base/UploadCollection-parameters.css new file mode 100644 index 000000000000..ba930d49120f --- /dev/null +++ b/packages/fiori/src/themes/base/UploadCollection-parameters.css @@ -0,0 +1,4 @@ +:root { + --ui5_upload_collection_level_2Size: 1.375rem; + --ui5_upload_collection_level_5Size: 1rem; +} \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize/parameters-bundle.css b/packages/fiori/src/themes/sap_belize/parameters-bundle.css index b86ce8c0537a..bb852676b2ec 100644 --- a/packages/fiori/src/themes/sap_belize/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_belize/parameters-bundle.css @@ -1 +1,2 @@ -@import "../base/ProductSwitchItem-parameters.css"; \ No newline at end of file +@import "../base/ProductSwitchItem-parameters.css"; +@import "../base/UploadCollection-parameters.css"; \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css b/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css index db8996474e7a..154b36c0dc5f 100644 --- a/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css @@ -1 +1,2 @@ -@import "./ProductSwitchItem-parameters.css"; \ No newline at end of file +@import "./ProductSwitchItem-parameters.css"; +@import "../base/UploadCollection-parameters.css"; \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css b/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css index db8996474e7a..154b36c0dc5f 100644 --- a/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css @@ -1 +1,2 @@ -@import "./ProductSwitchItem-parameters.css"; \ No newline at end of file +@import "./ProductSwitchItem-parameters.css"; +@import "../base/UploadCollection-parameters.css"; \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_fiori_3/parameters-bundle.css b/packages/fiori/src/themes/sap_fiori_3/parameters-bundle.css index b86ce8c0537a..bb852676b2ec 100644 --- a/packages/fiori/src/themes/sap_fiori_3/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_fiori_3/parameters-bundle.css @@ -1 +1,2 @@ -@import "../base/ProductSwitchItem-parameters.css"; \ No newline at end of file +@import "../base/ProductSwitchItem-parameters.css"; +@import "../base/UploadCollection-parameters.css"; \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_fiori_3_dark/parameters-bundle.css b/packages/fiori/src/themes/sap_fiori_3_dark/parameters-bundle.css index b86ce8c0537a..bb852676b2ec 100644 --- a/packages/fiori/src/themes/sap_fiori_3_dark/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_fiori_3_dark/parameters-bundle.css @@ -1 +1,2 @@ -@import "../base/ProductSwitchItem-parameters.css"; \ No newline at end of file +@import "../base/ProductSwitchItem-parameters.css"; +@import "../base/UploadCollection-parameters.css"; \ No newline at end of file diff --git a/packages/theme-base/src/themes/sap_belize/base-parameters-vars.less b/packages/theme-base/src/themes/sap_belize/base-parameters-vars.less index d8e3c45f3ec7..2314ee548577 100644 --- a/packages/theme-base/src/themes/sap_belize/base-parameters-vars.less +++ b/packages/theme-base/src/themes/sap_belize/base-parameters-vars.less @@ -302,4 +302,7 @@ // custom added params as no base ("sap" prefix) params equivalent exist --sapToggleButton_Pressed_HoverBackground: @sapToggleButton_Pressed_HoverBackground; --sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBorderColor; + --sapUploadCollection_NoFilesIconColor: @sapUploadCollection_NoFilesIconColor; + --sapUploadCollection_DragOverlayBackground: @sapUploadCollection_DragOverlayBackground; + --sapUploadCollection_DropOverlayBackground: @sapUploadCollection_DropOverlayBackground; } diff --git a/packages/theme-base/src/themes/sap_belize/base-parameters.less b/packages/theme-base/src/themes/sap_belize/base-parameters.less index e88545f1e647..fc37ac50f7a6 100644 --- a/packages/theme-base/src/themes/sap_belize/base-parameters.less +++ b/packages/theme-base/src/themes/sap_belize/base-parameters.less @@ -297,4 +297,7 @@ // custom added params as no base ("sap" prefix) params equivalent exist @sapToggleButton_Pressed_HoverBackground: lighten(@sapButton_Selected_Background, 10); -@sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBackground; \ No newline at end of file +@sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBackground; +@sapUploadCollection_NoFilesIconColor: fade(@sapContent_NonInteractiveIconColor, 50); +@sapUploadCollection_DragOverlayBackground: fade(@sapGroup_ContentBackground, 80); +@sapUploadCollection_DropOverlayBackground: fade(@sapActiveColor, 5); \ No newline at end of file diff --git a/packages/theme-base/src/themes/sap_belize_hcb/base-parameters-vars.less b/packages/theme-base/src/themes/sap_belize_hcb/base-parameters-vars.less index 2acad42169b7..75196750c415 100644 --- a/packages/theme-base/src/themes/sap_belize_hcb/base-parameters-vars.less +++ b/packages/theme-base/src/themes/sap_belize_hcb/base-parameters-vars.less @@ -306,4 +306,7 @@ // custom added params as no base ("sap" prefix) params equivalent exist --sapToggleButton_Pressed_HoverBackground: @sapToggleButton_Pressed_HoverBackground; --sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBorderColor; + --sapUploadCollection_NoFilesIconColor: @sapUploadCollection_NoFilesIconColor; + --sapUploadCollection_DragOverlayBackground: @sapUploadCollection_DragOverlayBackground; + --sapUploadCollection_DropOverlayBackground: @sapUploadCollection_DropOverlayBackground; } diff --git a/packages/theme-base/src/themes/sap_belize_hcb/base-parameters.less b/packages/theme-base/src/themes/sap_belize_hcb/base-parameters.less index 7d9060d4d801..97adcedef996 100644 --- a/packages/theme-base/src/themes/sap_belize_hcb/base-parameters.less +++ b/packages/theme-base/src/themes/sap_belize_hcb/base-parameters.less @@ -304,4 +304,7 @@ // custom added params as no base ("sap" prefix) params equivalent exist @sapToggleButton_Pressed_HoverBackground: @sapButton_Hover_Background; -@sapToggleButton_Pressed_HoverBorderColor: @sapButton_Hover_BorderColor; \ No newline at end of file +@sapToggleButton_Pressed_HoverBorderColor: @sapButton_Hover_BorderColor; +@sapUploadCollection_NoFilesIconColor: fade(@sapContent_NonInteractiveIconColor, 50); +@sapUploadCollection_DragOverlayBackground: fade(@sapGroup_ContentBackground, 80); +@sapUploadCollection_DropOverlayBackground: fade(@sapActiveColor, 5); \ No newline at end of file diff --git a/packages/theme-base/src/themes/sap_belize_hcw/base-parameters-vars.less b/packages/theme-base/src/themes/sap_belize_hcw/base-parameters-vars.less index 4ae0c0835885..8de95b7f2ebd 100644 --- a/packages/theme-base/src/themes/sap_belize_hcw/base-parameters-vars.less +++ b/packages/theme-base/src/themes/sap_belize_hcw/base-parameters-vars.less @@ -307,4 +307,7 @@ // custom added params as no base ("sap" prefix) params equivalent exist --sapToggleButton_Pressed_HoverBackground: @sapToggleButton_Pressed_HoverBackground; --sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBorderColor; + --sapUploadCollection_NoFilesIconColor: @sapUploadCollection_NoFilesIconColor; + --sapUploadCollection_DragOverlayBackground: @sapUploadCollection_DragOverlayBackground; + --sapUploadCollection_DropOverlayBackground: @sapUploadCollection_DropOverlayBackground; } diff --git a/packages/theme-base/src/themes/sap_belize_hcw/base-parameters.less b/packages/theme-base/src/themes/sap_belize_hcw/base-parameters.less index 28dabb5c226b..ee3ba2afcbcf 100644 --- a/packages/theme-base/src/themes/sap_belize_hcw/base-parameters.less +++ b/packages/theme-base/src/themes/sap_belize_hcw/base-parameters.less @@ -305,4 +305,6 @@ // custom added params as no base ("sap" prefix) params equivalent exist @sapToggleButton_Pressed_HoverBackground: @sapButton_Hover_Background; @sapToggleButton_Pressed_HoverBorderColor: @sapButton_Hover_BorderColor; - +@sapUploadCollection_NoFilesIconColor: fade(@sapContent_NonInteractiveIconColor, 50); +@sapUploadCollection_DragOverlayBackground: fade(@sapGroup_ContentBackground, 80); +@sapUploadCollection_DropOverlayBackground: fade(@sapActiveColor, 5); diff --git a/packages/theme-base/src/themes/sap_fiori_3/base-parameters-vars.less b/packages/theme-base/src/themes/sap_fiori_3/base-parameters-vars.less index 18287201fb2a..66eb2f072c75 100644 --- a/packages/theme-base/src/themes/sap_fiori_3/base-parameters-vars.less +++ b/packages/theme-base/src/themes/sap_fiori_3/base-parameters-vars.less @@ -299,4 +299,7 @@ // custom added params as no base ("sap" prefix) params equivalent exist --sapToggleButton_Pressed_HoverBackground: @sapToggleButton_Pressed_HoverBackground; --sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBorderColor; + --sapUploadCollection_NoFilesIconColor: @sapUploadCollection_NoFilesIconColor; + --sapUploadCollection_DragOverlayBackground: @sapUploadCollection_DragOverlayBackground; + --sapUploadCollection_DropOverlayBackground: @sapUploadCollection_DropOverlayBackground; } \ No newline at end of file diff --git a/packages/theme-base/src/themes/sap_fiori_3/base-parameters.less b/packages/theme-base/src/themes/sap_fiori_3/base-parameters.less index ce7f552f3c03..5fe81d2dae03 100644 --- a/packages/theme-base/src/themes/sap_fiori_3/base-parameters.less +++ b/packages/theme-base/src/themes/sap_fiori_3/base-parameters.less @@ -295,4 +295,7 @@ // custom added params as no base ("sap" prefix) params equivalent exist @sapToggleButton_Pressed_HoverBackground: lighten(@sapSelectedColor, 3); -@sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBackground; \ No newline at end of file +@sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBackground; +@sapUploadCollection_NoFilesIconColor: fade(@sapContent_NonInteractiveIconColor, 50); +@sapUploadCollection_DragOverlayBackground: fade(@sapGroup_ContentBackground, 80); +@sapUploadCollection_DropOverlayBackground: fade(@sapActiveColor, 5); \ No newline at end of file diff --git a/packages/theme-base/src/themes/sap_fiori_3_dark/base-parameters-vars.less b/packages/theme-base/src/themes/sap_fiori_3_dark/base-parameters-vars.less index 6d7860bf6b35..cc9304414290 100644 --- a/packages/theme-base/src/themes/sap_fiori_3_dark/base-parameters-vars.less +++ b/packages/theme-base/src/themes/sap_fiori_3_dark/base-parameters-vars.less @@ -296,4 +296,7 @@ // custom added params as no base ("sap" prefix) params equivalent exist --sapToggleButton_Pressed_HoverBackground: @sapToggleButton_Pressed_HoverBackground; --sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBorderColor; + --sapUploadCollection_NoFilesIconColor: @sapUploadCollection_NoFilesIconColor; + --sapUploadCollection_DragOverlayBackground: @sapUploadCollection_DragOverlayBackground; + --sapUploadCollection_DropOverlayBackground: @sapUploadCollection_DropOverlayBackground; } diff --git a/packages/theme-base/src/themes/sap_fiori_3_dark/base-parameters.less b/packages/theme-base/src/themes/sap_fiori_3_dark/base-parameters.less index 257c4a4ece64..4870282d777d 100644 --- a/packages/theme-base/src/themes/sap_fiori_3_dark/base-parameters.less +++ b/packages/theme-base/src/themes/sap_fiori_3_dark/base-parameters.less @@ -294,4 +294,7 @@ // custom added params as no base ("sap" prefix) params equivalent exist @sapToggleButton_Pressed_HoverBackground: darken(@sapSelectedColor, 3); -@sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBackground; \ No newline at end of file +@sapToggleButton_Pressed_HoverBorderColor: @sapToggleButton_Pressed_HoverBackground; +@sapUploadCollection_NoFilesIconColor: fade(@sapContent_NonInteractiveIconColor, 50); +@sapUploadCollection_DragOverlayBackground: fade(@sapGroup_ContentBackground, 80); +@sapUploadCollection_DropOverlayBackground: fade(@sapActiveColor, 5); \ No newline at end of file From cfda15b34f87f8673b3a2bf3e54f20b8892670e5 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 11:32:44 +0200 Subject: [PATCH 12/42] make borders correct in belize_hcb/hcw --- packages/fiori/src/UploadCollection.hbs | 50 +++++++++---------- packages/fiori/src/UploadCollection.js | 2 +- .../fiori/src/themes/UploadCollection.css | 47 ++++++++++------- .../base/UploadCollection-parameters.css | 4 ++ .../UploadCollection-parameters.css | 6 +++ .../sap_belize_hcb/parameters-bundle.css | 2 +- .../UploadCollection-parameters.css | 6 +++ .../sap_belize_hcw/parameters-bundle.css | 2 +- 8 files changed, 72 insertions(+), 47 deletions(-) create mode 100644 packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css create mode 100644 packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css diff --git a/packages/fiori/src/UploadCollection.hbs b/packages/fiori/src/UploadCollection.hbs index 9f3aab757025..3d4a46b9d60c 100644 --- a/packages/fiori/src/UploadCollection.hbs +++ b/packages/fiori/src/UploadCollection.hbs @@ -1,28 +1,28 @@ -
- -
- -
- -
- - {{#if _showNoData}} -
-
- +
+
+ +
+
+ + + + {{#if _showNoData}} +
+
+ +
+ {{_noDataText}} + {{_noDataDescription}} +
+ {{else if _showDndOverlay}} +
+ + {{_dndOverlayText}}
- {{_noDataText}} - {{_noDataDescription}} -
- {{else if _showDndOverlay}} -
- - {{_dndOverlayText}} -
- {{/if}} + {{/if}} +
\ No newline at end of file diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index a1fef788f354..434b4977361a 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -295,7 +295,7 @@ class UploadCollection extends UI5Element { } get _root() { - return this.shadowRoot.querySelector(".uc-root"); + return this.shadowRoot.querySelector(".ui5-uc-root"); } get _dndOverlay() { diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css index c999d98ea714..c640e37d9d29 100644 --- a/packages/fiori/src/themes/UploadCollection.css +++ b/packages/fiori/src/themes/UploadCollection.css @@ -2,18 +2,24 @@ display: block; } -.uc-root { - position: relative; +.ui5-uc-root { height: 100%; + display: flex; + flex-direction: column; +} + +.ui5-uc-content { + position: relative; + flex: 1; } /* No Files */ .uc-no-files { position: absolute; - top: 3rem; - right: 0rem; - left: 0rem; - bottom: 0rem; + top: 0; + right: 0; + left: 0; + bottom: 0; box-sizing: border-box; display: flex; flex-direction: column; @@ -49,10 +55,10 @@ /* Drag and Drop */ .uc-dnd-overlay { position: absolute; - top: 3rem; - right: 0rem; - left: 0rem; - bottom: 0rem; + top: 0.5rem; + right: 0.5rem; + left: 0.5rem; + bottom: 0.5rem; display: flex; flex-direction: column; align-items: center; @@ -60,8 +66,8 @@ } .uc-drag-overlay { - background-color: var(--sapUploadCollection_DragOverlayBackground); - border: 0.125rem dashed var(--sapContent_ForegroundBorderColor); + background-color: var(--ui5_upload_collection_drag_overlay_background); + border: var(--ui5_upload_collection_drag_overlay_border); } .uc-drop-overlay::after { @@ -71,21 +77,24 @@ right: 0rem; left: 0rem; bottom: 0rem; - background-color: var(--sapUploadCollection_DropOverlayBackground); - border: 0.125rem solid var(--sapActiveColor); + background-color: var(--ui5_upload_collection_drop_overlay_background); + border: var(--ui5_upload_collection_drop_overlay_border); } .uc-dnd-overlay ui5-icon { width: 4rem; height: 4rem; margin-bottom: 1rem; + color: var(--sapContent_NonInteractiveIconColor); } -.uc-drop-overlay ui5-icon, -.uc-drop-overlay ui5-text { - color: var(--sapActiveColor); +.uc-dnd-overlay .dnd-overlay-text { + font-family: var(--sapFontFamily); + font-size: var(--sapMFontHeader4Size); + color: var(--sapContent_NonInteractiveIconColor); } -.uc-drop-overlay ui5-text { - font-size: var(--sapMFontHeader4Size) +.uc-drop-overlay ui5-icon, +.uc-drop-overlay .dnd-overlay-text { + color: var(--sapActiveColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/base/UploadCollection-parameters.css b/packages/fiori/src/themes/base/UploadCollection-parameters.css index ba930d49120f..d8ab744c8783 100644 --- a/packages/fiori/src/themes/base/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/base/UploadCollection-parameters.css @@ -1,4 +1,8 @@ :root { --ui5_upload_collection_level_2Size: 1.375rem; --ui5_upload_collection_level_5Size: 1rem; + --ui5_upload_collection_drag_overlay_background: var(--sapUploadCollection_DragOverlayBackground); + --ui5_upload_collection_drag_overlay_border: 0.125rem dashed var(--sapContent_ForegroundBorderColor); + --ui5_upload_collection_drop_overlay_background: var(--sapUploadCollection_DropOverlayBackground); + --ui5_upload_collection_drop_overlay_border: 0.125rem solid var(--sapActiveColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css new file mode 100644 index 000000000000..12286325ed99 --- /dev/null +++ b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css @@ -0,0 +1,6 @@ +@import "../base/UploadCollection-parameters.css"; + +:root { + --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); + --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapActiveColor); +} \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css b/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css index 154b36c0dc5f..97855c33e4b4 100644 --- a/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_belize_hcb/parameters-bundle.css @@ -1,2 +1,2 @@ @import "./ProductSwitchItem-parameters.css"; -@import "../base/UploadCollection-parameters.css"; \ No newline at end of file +@import "./UploadCollection-parameters.css"; \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css new file mode 100644 index 000000000000..12286325ed99 --- /dev/null +++ b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css @@ -0,0 +1,6 @@ +@import "../base/UploadCollection-parameters.css"; + +:root { + --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); + --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapActiveColor); +} \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css b/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css index 154b36c0dc5f..97855c33e4b4 100644 --- a/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css +++ b/packages/fiori/src/themes/sap_belize_hcw/parameters-bundle.css @@ -1,2 +1,2 @@ @import "./ProductSwitchItem-parameters.css"; -@import "../base/UploadCollection-parameters.css"; \ No newline at end of file +@import "./UploadCollection-parameters.css"; \ No newline at end of file From f7a16eefb5d76b3d77d6e31fbac50052f8227020 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 13:30:04 +0200 Subject: [PATCH 13/42] added fileNameClick event on UploadCollectionItem --- packages/fiori/src/UploadCollection.hbs | 3 +- packages/fiori/src/UploadCollection.js | 81 ++++++++++++------- packages/fiori/src/UploadCollectionItem.hbs | 2 +- packages/fiori/src/UploadCollectionItem.js | 29 ++++--- .../fiori/test/pages/UploadCollection.html | 19 +++-- .../test/pages/uploadCollectionDemoHelper.js | 18 ++++- 6 files changed, 99 insertions(+), 53 deletions(-) diff --git a/packages/fiori/src/UploadCollection.hbs b/packages/fiori/src/UploadCollection.hbs index 3d4a46b9d60c..a4002446c0b3 100644 --- a/packages/fiori/src/UploadCollection.hbs +++ b/packages/fiori/src/UploadCollection.hbs @@ -6,7 +6,8 @@
diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index 434b4977361a..e585015291f2 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -1,14 +1,14 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { getI18nBundle, fetchI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import List from "@ui5/webcomponents/dist/List.js"; +import ListMode from "@ui5/webcomponents/dist/types/ListMode.js"; import { UPLOADCOLLECTION_NO_DATA_TEXT, UPLOADCOLLECTION_NO_DATA_DESCRIPTION, UPLOADCOLLECTION_DRAG_FILE_INDICATOR, - UPLOADCOLLECTION_DROP_FILE_INDICATOR + UPLOADCOLLECTION_DROP_FILE_INDICATOR, } from "./generated/i18n/i18n-defaults.js"; -import ListMode from "@ui5/webcomponents/dist/types/ListMode.js"; -import List from "@ui5/webcomponents/dist/List.js"; // Template import UploadCollectionTemplate from "./generated/templates/UploadCollectionTemplate.lit.js"; @@ -19,12 +19,12 @@ import UploadCollectionCss from "./generated/themes/UploadCollection.css.js"; const DndOverlayMode = { None: "None", Drag: "Drag", - Drop: "Drop" + Drop: "Drop", }; const draggingFiles = event => { return event.dataTransfer.types.includes("Files"); -} +}; /** * Handles drag and drop event listeners on document.body. @@ -35,6 +35,7 @@ const bodyDnDHandler = { _lastDragEnter: null, _uploadCollections: new Set(), _globalHandlersAttached: false, + _ondragenter: event => { if (!draggingFiles(event)) { return; @@ -47,6 +48,7 @@ const bodyDnDHandler = { } }); }, + _ondragleave: event => { bodyDnDHandler._uploadCollections.forEach(uc => { if (bodyDnDHandler._lastDragEnter === event.target) { @@ -54,12 +56,14 @@ const bodyDnDHandler = { } }); }, - _ondrop: () => { + + _ondrop: event => { bodyDnDHandler._uploadCollections.forEach(uc => { uc._dndOverlayMode = DndOverlayMode.None; }); }, - _attachGlobalHandlers: function() { + + _attachGlobalHandlers() { if (!this._globalHandlersAttached) { document.body.addEventListener("dragenter", this._ondragenter); document.body.addEventListener("dragleave", this._ondragleave); @@ -67,25 +71,27 @@ const bodyDnDHandler = { this._globalHandlersAttached = true; } }, - _detachGlobalHandlers: function() { + + _detachGlobalHandlers() { document.body.removeEventListener("dragenter", this._ondragenter); document.body.removeEventListener("dragleave", this._dragleave); document.body.removeEventListener("drop", this._ondrop); this._globalHandlersAttached = false; - }, - addUploadCollectionInstance: function(uploadCollections) { - this._uploadCollections.add(uploadCollections); + + addUploadCollectionInstance(uploadCollection) { + this._uploadCollections.add(uploadCollection); this._attachGlobalHandlers(); }, - removeUploadCollectionInstance: function() { - this.uploadCollections.delete(uploadCollections); + + removeUploadCollectionInstance(uploadCollection) { + this.uploadCollections.delete(uploadCollection); if (this.uploadCollections.size === 0) { this._detachGlobalHandlers(); } }, -} +}; /** * @public @@ -97,18 +103,18 @@ const metadata = { type: ListMode, defaultValue: ListMode.None, }, - noDnd: { - type: Boolean, - }, - noDataText:{ + noDataDescription: { type: String, }, - noDataDescription:{ + noDataText: { type: String, }, + noDnd: { + type: Boolean, + }, _dndOverlayMode: { type: String, - defaultValue: DndOverlayMode.None + defaultValue: DndOverlayMode.None, }, }, managedSlots: true, @@ -131,7 +137,20 @@ const metadata = { detail: { item: { type: HTMLElement }, }, - } + }, + /** + * Fired when selection is changed by user interaction + * in SingleSelect and MultiSelect modes. + * + * @event + * @param {Array} selectedItems An array of the selected items. + * @public + */ + selectionChange: { + detail: { + selectedItems: { type: Array }, + }, + }, }, }; @@ -217,10 +236,6 @@ class UploadCollection extends UI5Element { this._removeDragAndDropListeners(); } } - - _onItemDelete(event) { - this.fireEvent("fileDeleted", { item: event.detail.item }); - } _addDragAndDropListeners() { this._root.addEventListener("dragenter", this._listeners.dragenter); @@ -253,7 +268,7 @@ class UploadCollection extends UI5Element { } _ondragover(event) { - event.preventDefault() + event.preventDefault(); } _ondragleave(event) { @@ -284,6 +299,14 @@ class UploadCollection extends UI5Element { this.fireEvent("fileRenamed", { item: event.target }); } + _onItemDelete(event) { + this.fireEvent("fileDeleted", { item: event.detail.item }); + } + + _onSelectionChange(event) { + this.fireEvent("selectionChange", { selectedItems: event.detail.selectedItems }); + } + get classes() { return { dndOverlay: { @@ -299,7 +322,7 @@ class UploadCollection extends UI5Element { } get _dndOverlay() { - return this._root.querySelector(".uc-dnd-overlay") + return this._root.querySelector(".uc-dnd-overlay"); } get _showDndOverlay() { @@ -321,9 +344,9 @@ class UploadCollection extends UI5Element { get _dndOverlayText() { if (this._dndOverlayMode === DndOverlayMode.Drag) { return this.i18nBundle.getText(UPLOADCOLLECTION_DRAG_FILE_INDICATOR); - } else { - return this.i18nBundle.getText(UPLOADCOLLECTION_DROP_FILE_INDICATOR); } + + return this.i18nBundle.getText(UPLOADCOLLECTION_DROP_FILE_INDICATOR); } } diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index 35eb56381360..8bfeefa406d6 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -16,7 +16,7 @@
{{else }} {{#if fileNameClickable}} - {{fileName}} + {{fileName}} {{else}} {{fileName}} {{/if}} diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 572287cd5837..39c567ce9ead 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -1,12 +1,11 @@ -import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import Button from "@ui5/webcomponents/dist/Button.js"; +import ListItem from "@ui5/webcomponents/dist/ListItem.js"; import { UPLOADCOLLECTIONITEM_CANCELBUTTON_TEXT, UPLOADCOLLECTIONITEM_RENAMEBUTTON_TEXT, } from "./generated/i18n/i18n-defaults.js"; -import Button from "@ui5/webcomponents/dist/Button.js"; -import ListItem from "@ui5/webcomponents/dist/ListItem.js"; // Template import UploadCollectionItemTemplate from "./generated/templates/UploadCollectionItemTemplate.lit.js"; @@ -27,16 +26,15 @@ const metadata = { fileName: { type: String, }, - noDelete: { + fileNameClickable: { type: Boolean, }, - // TODO: better name + event for click - fileNameClickable: { + noDelete: { type: Boolean, }, _editing: { - type: Boolean - } + type: Boolean, + }, }, slots: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { "default": { @@ -44,10 +42,11 @@ const metadata = { }, thumbnail: { type: HTMLElement, - } + }, }, events: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { - _rename: { } + fileNameClick: { }, + _rename: { }, }, }; @@ -137,6 +136,10 @@ class UploadCollectionItem extends ListItem { this._editing = false; } + _onFileNameClick(event) { + this.fireEvent("fileNameClick"); + } + /** * @override */ @@ -147,9 +150,9 @@ class UploadCollectionItem extends ListItem { main: { ...result.main, "ui5-uci-root": true, - "ui5-uci-root-edit": this._editing - } - } + "ui5-uci-root-edit": this._editing, + }, + }; } /** diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 00da098942eb..250cdafbdd77 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -36,14 +36,23 @@
- Mode: + UC Mode: None - Delete - MultiSelect SingleSelect + SingleSelectBegin + SingleSelectEnd + MultiSelect + Delete + + UCI Type: + + Active + Inactive + Detail - + Selected items: +

This element is draggable

@@ -58,7 +67,7 @@
diff --git a/packages/fiori/test/pages/uploadCollectionDemoHelper.js b/packages/fiori/test/pages/uploadCollectionDemoHelper.js index 87d07f1d4513..178c163b6db2 100644 --- a/packages/fiori/test/pages/uploadCollectionDemoHelper.js +++ b/packages/fiori/test/pages/uploadCollectionDemoHelper.js @@ -55,6 +55,12 @@ uploadCollection.mode = event.detail.selectedOption.textContent; }); + document.getElementById("changeType").addEventListener("change", function(event) { + uploadCollection.items.forEach(function (uci) { + uci.type = event.detail.selectedOption.textContent; + }); + }); + document.getElementById("fileUploader").addEventListener("change", function(event) { var files = event.detail.files; @@ -63,10 +69,14 @@ } }); - document.getElementById("cb1").addEventListener("change", function(event) { - uploadCollection.items.forEach(function (item) { - item.type = event.target.checked ? "Detail" : "Active"; - }); + uploadCollection.addEventListener("selectionChange", function (event) { + var selectedItems = event.detail.selectedItems.reduce(function (acc, item) { + return acc + item.fileName + ","; + }, "["); + + selectedItems += "]" + + document.getElementById("selectedItems").innerText = selectedItems; }); uploadCollection.addEventListener("fileDeleted", function (event) { From 74331e09a554d4c5fcd9b5654a3df8449b8a0ef7 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 14:15:33 +0200 Subject: [PATCH 14/42] add jsdoc and missing dependencies --- packages/fiori/src/UploadCollection.js | 87 +++++++++++++++++++++- packages/fiori/src/UploadCollectionItem.js | 65 ++++++++++++++++ 2 files changed, 151 insertions(+), 1 deletion(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index e585015291f2..a5ad8fdbaab2 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -1,8 +1,13 @@ import UI5Element from "@ui5/webcomponents-base/dist/UI5Element.js"; import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { getI18nBundle, fetchI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; +import Icon from "@ui5/webcomponents/dist/Icon.js"; +import Label from "@ui5/webcomponents/dist/Label.js"; import List from "@ui5/webcomponents/dist/List.js"; import ListMode from "@ui5/webcomponents/dist/types/ListMode.js"; +import Title from "@ui5/webcomponents/dist/Title.js"; +import "@ui5/webcomponents-icons/dist/icons/upload-to-cloud.js"; +import "@ui5/webcomponents-icons/dist/icons/document.js"; import { UPLOADCOLLECTION_NO_DATA_TEXT, UPLOADCOLLECTION_NO_DATA_DESCRIPTION, @@ -28,7 +33,7 @@ const draggingFiles = event => { /** * Handles drag and drop event listeners on document.body. - * Ensures that there is only 1 listener per type attached (drag, drop, leave). Event listeners will be only attached when + * Ensures that there is only 1 listener per type attached (drag, drop, leave). Event listeners will only be attached when * there is at least 1 UploadCollection registered in the set. */ const bodyDnDHandler = { @@ -99,19 +104,60 @@ const bodyDnDHandler = { const metadata = { tag: "ui5-upload-collection", properties: /** @lends sap.ui.webcomponents.fiori.UploadCollection.prototype */ { + /** + * Defines the mode of the ui5-upload-collection. + *

+ * Note: Available options are None, SingleSelect, + * MultiSelect, and Delete. + * + * @type {string} + * @defaultvalue "None" + * @public + */ mode: { type: ListMode, defaultValue: ListMode.None, }, + + /** + * Allows you to set your own text for the 'No data' description. + * + * @type {string} + * @public + */ noDataDescription: { type: String, }, + + /** + * Allows you to set your own text for the 'No data' text. + * + * @type {string} + * @public + */ noDataText: { type: String, }, + + /** + * By default there will be drag and drop overlay shown over the ui5-upload-collection when files + * are dragged. If you don't intend to use drag and drop, set this property to true + *

+ * Note: It is up to the application developer to add handler for drop event and handle it. + * ui5-upload-collection only shows an overlay. + * + * @type {boolean} + * @public + */ noDnd: { type: Boolean, }, + + /** + * Indicates what overlay to show when files are being dragged. + * + * @private + */ _dndOverlayMode: { type: String, defaultValue: DndOverlayMode.None, @@ -119,25 +165,61 @@ const metadata = { }, managedSlots: true, slots: /** @lends sap.ui.webcomponents.fiori.UploadCollection.prototype */ { + /** + * Defines the items of the ui5-upload-collection. + *
Note: Use ui5-upload-collection-item for the intended design. + * + * @type {HTMLElement[]} + * @slot + * @public + */ "default": { propertyName: "items", type: HTMLElement, }, + + /** + * Defines the ui5-upload-collection header. + * + * @type {HTMLElement[]} + * @slot + * @public + */ header: { type: HTMLElement, }, }, events: /** @lends sap.ui.webcomponents.fiori.UploadCollection.prototype */ { + /** + * Fired when the Delete button of any item is pressed. + *

+ * Note: A Delete button is displayed on each item, + * when the ui5-upload-collection mode property is set to Delete. + * @event + * @param {HTMLElement} item The ui5-upload-collection-item which was renamed. + * @public + */ fileDeleted: { detail: { item: { type: HTMLElement }, }, }, + + /** + * Fired when any item gets its property fileName changed. + *

+ * Note: An edit button is displayed on each item, + * when the ui5-upload-collection-item type property is set to Detail. + * @event + * @param {HTMLElement} item The ui5-upload-collection-item which was renamed. + * @public + */ fileRenamed: { detail: { item: { type: HTMLElement }, }, }, + /** * Fired when selection is changed by user interaction * in SingleSelect and MultiSelect modes. @@ -193,7 +275,10 @@ class UploadCollection extends UI5Element { static async onDefine() { await Promise.all([ + Icon.define(), + Label.define(), List.define(), + Title.define(), fetchI18nBundle("@ui5/webcomponents"), ]); } diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 39c567ce9ead..3211c33ee829 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -1,6 +1,8 @@ import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import Button from "@ui5/webcomponents/dist/Button.js"; +import Input from "@ui5/webcomponents/dist/Input.js"; +import Link from "@ui5/webcomponents/dist/Link.js"; import ListItem from "@ui5/webcomponents/dist/ListItem.js"; import { UPLOADCOLLECTIONITEM_CANCELBUTTON_TEXT, @@ -19,33 +21,94 @@ import UploadCollectionItemCss from "./generated/themes/UploadCollectionItem.css const metadata = { tag: "ui5-upload-collection-item", properties: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { + /** + * Holds File, associated with this item. + * + * @type {File} + * @defaultvalue null + * @public + */ file: { type: Object, defaultValue: null, }, + + /** + * The name of the file. + * + * @type {string} + * @public + */ fileName: { type: String, }, + + /** + * If set to true the file name will be clickable and it will fire fileNameClick event upon click. + * + * @type {boolean} + * @public + */ fileNameClickable: { type: Boolean, }, + + /** + * Removes delete option from ui5-upload-collection with mode Delete for this item. + * + * @type {boolean} + * @public + */ noDelete: { type: Boolean, }, + + /** + * Indicates if editing. + * + * @private + */ _editing: { type: Boolean, }, }, slots: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { + /** + * Hold the description of the ui5-upload-collection-item. Will be shown below the file name. + * + * @type {Node[]} + * @slot + * @public + */ "default": { type: Node, }, + + /** + * A thumbnail, which will be shown in the beginning of the ui5-upload-collection-item. + *

+ * Note: Use ui5-icon or img for the intended design. + * + * @type {HTMLElement} + * @slot + * @public + */ thumbnail: { type: HTMLElement, }, }, events: /** @lends sap.ui.webcomponents.fiori.UploadCollectionItem.prototype */ { + /** + * Fired when the file name is clicked. + *

+ * Note: This event is only available when fileNameClickable property is true. + * + * @event + * @param {HTMLElement} item The ui5-upload-collection-item which was renamed. + * @public + */ fileNameClick: { }, + _rename: { }, }, }; @@ -90,6 +153,8 @@ class UploadCollectionItem extends ListItem { static async onDefine() { await Promise.all([ Button.define(), + Input.define(), + Link.define(), fetchI18nBundle("@ui5/webcomponents"), ]); } From 1309612a7de49c31cf67b57a73b258acd293f821 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 15:05:30 +0200 Subject: [PATCH 15/42] move BodyDragAndDrop to fiori/src/upload-utils/BodyDragAndDrop.js --- packages/fiori/src/UploadCollection.js | 109 +++--------------- .../src/types/UploadCollectionDnDMode.js | 29 +++++ .../fiori/src/upload-utils/BodyDragAndDrop.js | 79 +++++++++++++ 3 files changed, 127 insertions(+), 90 deletions(-) create mode 100644 packages/fiori/src/types/UploadCollectionDnDMode.js create mode 100644 packages/fiori/src/upload-utils/BodyDragAndDrop.js diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index a5ad8fdbaab2..d7bc87a8145b 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -14,6 +14,12 @@ import { UPLOADCOLLECTION_DRAG_FILE_INDICATOR, UPLOADCOLLECTION_DROP_FILE_INDICATOR, } from "./generated/i18n/i18n-defaults.js"; +import { + addUploadCollectionInstance, + removeUploadCollectionInstance, + draggingFiles, +} from "./upload-utils/BodyDragAndDrop.js"; +import UploadCollectionDnDOverlayMode from "./types/UploadCollectionDnDMode.js"; // Template import UploadCollectionTemplate from "./generated/templates/UploadCollectionTemplate.lit.js"; @@ -21,83 +27,6 @@ import UploadCollectionTemplate from "./generated/templates/UploadCollectionTemp // Styles import UploadCollectionCss from "./generated/themes/UploadCollection.css.js"; -const DndOverlayMode = { - None: "None", - Drag: "Drag", - Drop: "Drop", -}; - -const draggingFiles = event => { - return event.dataTransfer.types.includes("Files"); -}; - -/** - * Handles drag and drop event listeners on document.body. - * Ensures that there is only 1 listener per type attached (drag, drop, leave). Event listeners will only be attached when - * there is at least 1 UploadCollection registered in the set. - */ -const bodyDnDHandler = { - _lastDragEnter: null, - _uploadCollections: new Set(), - _globalHandlersAttached: false, - - _ondragenter: event => { - if (!draggingFiles(event)) { - return; - } - - bodyDnDHandler._lastDragEnter = event.target; - bodyDnDHandler._uploadCollections.forEach(uc => { - if (uc._dndOverlayMode !== DndOverlayMode.Drop) { - uc._dndOverlayMode = DndOverlayMode.Drag; - } - }); - }, - - _ondragleave: event => { - bodyDnDHandler._uploadCollections.forEach(uc => { - if (bodyDnDHandler._lastDragEnter === event.target) { - uc._dndOverlayMode = DndOverlayMode.None; - } - }); - }, - - _ondrop: event => { - bodyDnDHandler._uploadCollections.forEach(uc => { - uc._dndOverlayMode = DndOverlayMode.None; - }); - }, - - _attachGlobalHandlers() { - if (!this._globalHandlersAttached) { - document.body.addEventListener("dragenter", this._ondragenter); - document.body.addEventListener("dragleave", this._ondragleave); - document.body.addEventListener("drop", this._ondrop); - this._globalHandlersAttached = true; - } - }, - - _detachGlobalHandlers() { - document.body.removeEventListener("dragenter", this._ondragenter); - document.body.removeEventListener("dragleave", this._dragleave); - document.body.removeEventListener("drop", this._ondrop); - this._globalHandlersAttached = false; - }, - - addUploadCollectionInstance(uploadCollection) { - this._uploadCollections.add(uploadCollection); - this._attachGlobalHandlers(); - }, - - removeUploadCollectionInstance(uploadCollection) { - this.uploadCollections.delete(uploadCollection); - - if (this.uploadCollections.size === 0) { - this._detachGlobalHandlers(); - } - }, -}; - /** * @public */ @@ -160,7 +89,7 @@ const metadata = { */ _dndOverlayMode: { type: String, - defaultValue: DndOverlayMode.None, + defaultValue: UploadCollectionDnDOverlayMode.None, }, }, managedSlots: true, @@ -299,7 +228,7 @@ class UploadCollection extends UI5Element { onEnterDOM() { if (!this.noDnd) { - bodyDnDHandler.addUploadCollectionInstance(this); + addUploadCollectionInstance(this); } } @@ -317,7 +246,7 @@ class UploadCollection extends UI5Element { onExitDOM() { if (!this.noDnd) { - bodyDnDHandler.removeUploadCollectionInstance(this); + removeUploadCollectionInstance(this); this._removeDragAndDropListeners(); } } @@ -344,12 +273,12 @@ class UploadCollection extends UI5Element { } if (event.target === this._dndOverlay) { - this._dndOverlayMode = DndOverlayMode.Drop; + this._dndOverlayMode = UploadCollectionDnDOverlayMode.Drop; } } _ondrop(event) { - this._dndOverlayMode = DndOverlayMode.None; + this._dndOverlayMode = UploadCollectionDnDOverlayMode.None; } _ondragover(event) { @@ -358,21 +287,21 @@ class UploadCollection extends UI5Element { _ondragleave(event) { if (event.target === this._dndOverlay) { - this._dndOverlayMode = DndOverlayMode.Drag; + this._dndOverlayMode = UploadCollectionDnDOverlayMode.Drag; } } _ondragenterBody(event) { this._lastDragEnter = event.target; - if (this._dndOverlayMode !== DndOverlayMode.Drop) { - this._dndOverlayMode = DndOverlayMode.Drag; + if (this._dndOverlayMode !== UploadCollectionDnDOverlayMode.Drop) { + this._dndOverlayMode = UploadCollectionDnDOverlayMode.Drag; } } _ondragleaveBody(event) { if (this._lastDragEnter === event.target) { - this._dndOverlayMode = DndOverlayMode.None; + this._dndOverlayMode = UploadCollectionDnDOverlayMode.None; } } @@ -396,8 +325,8 @@ class UploadCollection extends UI5Element { return { dndOverlay: { "uc-dnd-overlay": true, - "uc-drag-overlay": this._dndOverlayMode === DndOverlayMode.Drag, - "uc-drop-overlay": this._dndOverlayMode === DndOverlayMode.Drop, + "uc-drag-overlay": this._dndOverlayMode === UploadCollectionDnDOverlayMode.Drag, + "uc-drop-overlay": this._dndOverlayMode === UploadCollectionDnDOverlayMode.Drop, }, }; } @@ -411,7 +340,7 @@ class UploadCollection extends UI5Element { } get _showDndOverlay() { - return this._dndOverlayMode !== DndOverlayMode.None; + return this._dndOverlayMode !== UploadCollectionDnDOverlayMode.None; } get _showNoData() { @@ -427,7 +356,7 @@ class UploadCollection extends UI5Element { } get _dndOverlayText() { - if (this._dndOverlayMode === DndOverlayMode.Drag) { + if (this._dndOverlayMode === UploadCollectionDnDOverlayMode.Drag) { return this.i18nBundle.getText(UPLOADCOLLECTION_DRAG_FILE_INDICATOR); } diff --git a/packages/fiori/src/types/UploadCollectionDnDMode.js b/packages/fiori/src/types/UploadCollectionDnDMode.js new file mode 100644 index 000000000000..471010276222 --- /dev/null +++ b/packages/fiori/src/types/UploadCollectionDnDMode.js @@ -0,0 +1,29 @@ +import DataType from "@ui5/webcomponents-base/dist/types/DataType.js"; + +/** + * Different drag and drop overlay modes of UploadCollection. + * @private + */ +const DndOverlayMode = { + None: "None", + Drag: "Drag", + Drop: "Drop", +}; + +/** + * @class + * Different types of drag and drop overlay modes. + * @constructor + * @author SAP SE + * @private + * @enum {string} + */ +class UploadCollectionDnDOverlayMode extends DataType { + static isValid(value) { + return !!DndOverlayMode[value]; + } +} + +UploadCollectionDnDOverlayMode.generataTypeAcessors(DndOverlayMode); + +export default UploadCollectionDnDOverlayMode; diff --git a/packages/fiori/src/upload-utils/BodyDragAndDrop.js b/packages/fiori/src/upload-utils/BodyDragAndDrop.js new file mode 100644 index 000000000000..349af994bf31 --- /dev/null +++ b/packages/fiori/src/upload-utils/BodyDragAndDrop.js @@ -0,0 +1,79 @@ + +/** + * Handles drag and drop event listeners on document.body. + * Ensures that there is only 1 listener per type attached (drag, drop, leave). Event listeners will only be attached when + * there is at least 1 UploadCollection registered in the set. + */ + +import UploadCollectionDnDOverlayMode from "./types/UploadCollectionDnDMode.js"; + +const draggingFiles = event => { + return event.dataTransfer.types.includes("Files"); +}; + +const uploadCollections = new Set(); +let lastDragEnter = null; +let globalHandlersAttached = false; + +const ondragenter = event => { + if (!draggingFiles(event)) { + return; + } + + lastDragEnter = event.target; + uploadCollections.forEach(uc => { + if (uc._dndOverlayMode !== UploadCollectionDnDOverlayMode.Drop) { + uc._dndOverlayMode = UploadCollectionDnDOverlayMode.Drag; + } + }); +}; + +const ondragleave = event => { + uploadCollections.forEach(uc => { + if (lastDragEnter === event.target) { + uc._dndOverlayMode = UploadCollectionDnDOverlayMode.None; + } + }); +}; + +const ondrop = event => { + bodyDnDHandler._uploadCollections.forEach(uc => { + uc._dndOverlayMode = UploadCollectionDnDOverlayMode.None; + }); +}; + +const attachGlobalHandlers = () => { + document.body.addEventListener("dragenter", ondragenter); + document.body.addEventListener("dragleave", ondragleave); + document.body.addEventListener("drop", ondrop); +}; + +const detachGlobalHandlers = () => { + document.body.removeEventListener("dragenter", ondragenter); + document.body.removeEventListener("dragleave", ondragleave); + document.body.removeEventListener("drop", ondrop); + globalHandlersAttached = false; +}; + +const addUploadCollectionInstance = uploadCollection => { + uploadCollections.add(uploadCollection); + + if (!globalHandlersAttached) { + attachGlobalHandlers(); + globalHandlersAttached = true; + } +}; + +const removeUploadCollectionInstance = uploadCollection => { + uploadCollections.delete(uploadCollection); + + if (uploadCollections.size === 0) { + detachGlobalHandlers(); + } +}; + +export { + addUploadCollectionInstance, + removeUploadCollectionInstance, + draggingFiles, +}; From fbcaebe09e31b4fca08a8f4db1bc4e1b882f5571 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 15:08:22 +0200 Subject: [PATCH 16/42] combined noDnd with return statements for readability --- packages/fiori/src/UploadCollection.js | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index d7bc87a8145b..fb855bc2c92b 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -227,28 +227,36 @@ class UploadCollection extends UI5Element { } onEnterDOM() { - if (!this.noDnd) { - addUploadCollectionInstance(this); + if (this.noDnd) { + return; } + + addUploadCollectionInstance(this); } onBeforeRendering() { - if (!this.noDnd) { - this._removeDragAndDropListeners(); + if (this.noDnd) { + return; } + + this._removeDragAndDropListeners(); } onAfterRendering() { - if (!this.noDnd) { - this._addDragAndDropListeners(); + if (this.noDnd) { + return; } + + this._addDragAndDropListeners(); } onExitDOM() { - if (!this.noDnd) { - removeUploadCollectionInstance(this); - this._removeDragAndDropListeners(); + if (this.noDnd) { + return; } + + removeUploadCollectionInstance(this); + this._removeDragAndDropListeners(); } _addDragAndDropListeners() { From 0605ac4a5aa45ef13d1d82a35ceb484e4a9c4ba4 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 15:19:42 +0200 Subject: [PATCH 17/42] fix BodyDragAndDrop import path and append file extension after edit --- packages/fiori/src/UploadCollectionItem.js | 2 +- packages/fiori/src/upload-utils/BodyDragAndDrop.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 3211c33ee829..87510ec29461 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -193,7 +193,7 @@ class UploadCollectionItem extends ListItem { } this._editing = false; - this.fileName = event.target.value; + this.fileName = event.target.value + this._fileExtension; this.fireEvent("_rename"); } diff --git a/packages/fiori/src/upload-utils/BodyDragAndDrop.js b/packages/fiori/src/upload-utils/BodyDragAndDrop.js index 349af994bf31..2f4b6011d64c 100644 --- a/packages/fiori/src/upload-utils/BodyDragAndDrop.js +++ b/packages/fiori/src/upload-utils/BodyDragAndDrop.js @@ -5,7 +5,7 @@ * there is at least 1 UploadCollection registered in the set. */ -import UploadCollectionDnDOverlayMode from "./types/UploadCollectionDnDMode.js"; +import UploadCollectionDnDOverlayMode from "../types/UploadCollectionDnDMode.js"; const draggingFiles = event => { return event.dataTransfer.types.includes("Files"); From 066232a95011bc5972e0642c90aad126b644e06d Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 15:41:24 +0200 Subject: [PATCH 18/42] fix IE11 flex issues --- packages/fiori/src/themes/UploadCollection.css | 2 +- packages/fiori/test/pages/UploadCollection.html | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css index c640e37d9d29..59fb9ae1658a 100644 --- a/packages/fiori/src/themes/UploadCollection.css +++ b/packages/fiori/src/themes/UploadCollection.css @@ -10,7 +10,7 @@ .ui5-uc-content { position: relative; - flex: 1; + flex: 1 1 auto; } /* No Files */ diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 250cdafbdd77..31e44e777022 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -16,12 +16,12 @@ overflow: hidden; } - .header * { + .header > * { margin: 4px; } .spacer { - flex: 1; + flex: 1 1 auto; } /* .description { From 6850bb058afac6ac44c6614c3237cb2e3a8e9a9a Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 16:02:34 +0200 Subject: [PATCH 19/42] improve _fileNameWithoutExtension method --- packages/fiori/src/UploadCollectionItem.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 87510ec29461..50de2a98fc58 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -228,7 +228,7 @@ class UploadCollectionItem extends ListItem { } get _fileNameWithoutExtension() { - return this.fileName.split(".")[0]; + return this.fileName.substring(0, this.fileName.length - this._fileExtension.length); } get _fileExtension() { From 594440d116ab3de4116ead207f2093aa6c12f034 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Tue, 24 Mar 2020 17:20:07 +0200 Subject: [PATCH 20/42] use data-sap-focus-ref for focusing input --- packages/fiori/src/UploadCollectionItem.hbs | 1 + packages/fiori/src/UploadCollectionItem.js | 4 ++-- packages/fiori/src/upload-utils/BodyDragAndDrop.js | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index 8bfeefa406d6..5977677d03ef 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -10,6 +10,7 @@ {{_fileExtension}} diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 50de2a98fc58..f2ec4ff05784 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -172,9 +172,9 @@ class UploadCollectionItem extends ListItem { onAfterRendering() { if (this.focused && this._editing) { - const inp = this.shadowRoot.getElementById("ui5-uci-edit-input"); - inp.focus(); + this.focus(); // TODO: find way to select input's value + // const inp = this.shadowRoot.getElementById("ui5-uci-edit-input"); // inp.setSelectionRange(0, this._fileNameWithoutExtension.length); } } diff --git a/packages/fiori/src/upload-utils/BodyDragAndDrop.js b/packages/fiori/src/upload-utils/BodyDragAndDrop.js index 2f4b6011d64c..056752b92ed6 100644 --- a/packages/fiori/src/upload-utils/BodyDragAndDrop.js +++ b/packages/fiori/src/upload-utils/BodyDragAndDrop.js @@ -13,7 +13,7 @@ const draggingFiles = event => { const uploadCollections = new Set(); let lastDragEnter = null; -let globalHandlersAttached = false; +let globalHandlersAttached = false; const ondragenter = event => { if (!draggingFiles(event)) { @@ -37,7 +37,7 @@ const ondragleave = event => { }; const ondrop = event => { - bodyDnDHandler._uploadCollections.forEach(uc => { + uploadCollections.forEach(uc => { uc._dndOverlayMode = UploadCollectionDnDOverlayMode.None; }); }; From fd4c91db8889f220a8d2b20e5ce6931613a5d796 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 25 Mar 2020 15:03:41 +0200 Subject: [PATCH 21/42] add tests --- packages/fiori/src/UploadCollection.hbs | 4 +- packages/fiori/src/UploadCollection.js | 2 +- packages/fiori/src/UploadCollectionItem.hbs | 2 +- .../fiori/test/pages/UploadCollection.html | 34 ++++--- .../test/pages/uploadCollectionDemoHelper.js | 15 +-- .../fiori/test/specs/UploadCollection.spec.js | 93 +++++++++++++++++++ 6 files changed, 128 insertions(+), 22 deletions(-) create mode 100644 packages/fiori/test/specs/UploadCollection.spec.js diff --git a/packages/fiori/src/UploadCollection.hbs b/packages/fiori/src/UploadCollection.hbs index a4002446c0b3..3a31a97594a9 100644 --- a/packages/fiori/src/UploadCollection.hbs +++ b/packages/fiori/src/UploadCollection.hbs @@ -6,8 +6,8 @@
diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index fb855bc2c92b..e1ec27636dad 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -223,7 +223,7 @@ class UploadCollection extends UI5Element { drop: this._ondrop.bind(this), }; - this.addEventListener("_rename", this._onFileRenamed); + this.addEventListener("ui5-_rename", this._onFileRenamed); } onEnterDOM() { diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index 5977677d03ef..d8c94ccd4475 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -11,7 +11,7 @@ id="ui5-uci-edit-input" value="{{_fileNameWithoutExtension}}" data-sap-focus-ref - @change="{{_onInputChange}}" + @ui5-change="{{_onInputChange}}" > {{_fileExtension}}
diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 31e44e777022..3352cea5381c 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -24,10 +24,6 @@ flex: 1 1 auto; } - /* .description { - white-space: pre-wrap; - } */ - ui5-upload-collection { margin: 1rem; } @@ -53,9 +49,11 @@ Selected items: + Renamed file index: +
-

This element is draggable

+

This element is draggable

@@ -67,13 +65,15 @@
- - File name is clickable. - + id="firstItem" + file-name="LaptopHT-1000.jpg" + file-name-clickable + > + + File name is clickable. + + + Some description + + Some description diff --git a/packages/fiori/test/pages/uploadCollectionDemoHelper.js b/packages/fiori/test/pages/uploadCollectionDemoHelper.js index 178c163b6db2..9e0fe375707f 100644 --- a/packages/fiori/test/pages/uploadCollectionDemoHelper.js +++ b/packages/fiori/test/pages/uploadCollectionDemoHelper.js @@ -51,17 +51,17 @@ return uci; } - document.getElementById("changeMode").addEventListener("change", function(event) { + document.getElementById("changeMode").addEventListener("ui5-change", function(event) { uploadCollection.mode = event.detail.selectedOption.textContent; }); - document.getElementById("changeType").addEventListener("change", function(event) { + document.getElementById("changeType").addEventListener("ui5-change", function(event) { uploadCollection.items.forEach(function (uci) { uci.type = event.detail.selectedOption.textContent; }); }); - document.getElementById("fileUploader").addEventListener("change", function(event) { + document.getElementById("fileUploader").addEventListener("ui5-change", function(event) { var files = event.detail.files; for (var i = 0; i < files.length; i++) { @@ -69,7 +69,7 @@ } }); - uploadCollection.addEventListener("selectionChange", function (event) { + uploadCollection.addEventListener("ui5-selectionChange", function (event) { var selectedItems = event.detail.selectedItems.reduce(function (acc, item) { return acc + item.fileName + ","; }, "["); @@ -79,10 +79,14 @@ document.getElementById("selectedItems").innerText = selectedItems; }); - uploadCollection.addEventListener("fileDeleted", function (event) { + uploadCollection.addEventListener("ui5-fileDeleted", function (event) { uploadCollection.removeChild(event.detail.item) }); + uploadCollection.addEventListener("ui5-fileRenamed", function (event) { + document.getElementById("renamedFileIndex").innerText = uploadCollection.items.indexOf(event.detail.item); + }); + document.getElementById("startUploading").addEventListener("click", function(event) { uploadCollection.items.forEach(function (item) { if (item.file) { @@ -94,7 +98,6 @@ }); }); - // DND document.getElementById("uploadCollectionDnD").addEventListener("drop", function(event) { event.preventDefault(); diff --git a/packages/fiori/test/specs/UploadCollection.spec.js b/packages/fiori/test/specs/UploadCollection.spec.js new file mode 100644 index 000000000000..dbc228a6c3f1 --- /dev/null +++ b/packages/fiori/test/specs/UploadCollection.spec.js @@ -0,0 +1,93 @@ +const assert = require("chai").assert; + +describe("UploadCollection", () => { + describe("Rendering", () => { + browser.url("http://localhost:8081/test-resources/pages/UploadCollection.html"); + + it("should show Link when 'fileNameClickable'", () => { + const firstItem = browser.$("#firstItem"); + assert.ok(firstItem.shadow$("ui5-link"), "Link should be rendered"); + }); + + it("should show span when file name is NOT clickable", () => { + const secondItem = browser.$("#secondItem"); + assert.ok(secondItem.shadow$("span.ui5-uci-file-name"), "span should be rendered"); + }); + + it("should show input and buttons when editing", () => { + const secondItem = browser.$("#secondItem"); + const editButton = secondItem.shadow$(".ui5-li-detailbtn"); + editButton.click(); + + assert.ok(secondItem.shadow$(".ui5-uci-edit-container"), "edit container should be rendered"); + assert.ok(secondItem.shadow$(".ui5-uci-edit-buttons"), "edit buttons should be rendered"); + assert.notOk(secondItem.shadow$(".ui5-li-detailbtn").isDisplayed(), "detail button should be hidden"); + + // focus out the second item, to hide edit buttons (reset state for the following tests) + browser.$("#firstItem").click(); + }); + }); + + describe("Events", () => { + it("should fire 'fileRenamed'", () => { + const secondItem = browser.$("#secondItem"); + const secondItemIndex = 1; + const editButton = secondItem.shadow$(".ui5-li-detailbtn"); + + editButton.click(); + browser.keys("fileNameSuffix"); + browser.keys("Enter"); + + assert.strictEqual(parseInt(browser.$("#renamedFileIndex").getText()), secondItemIndex, "renamed file index should be updated after rename") + }); + + it("should fire 'fileDeleted'", () => { + const uploadCollection = browser.$("#uploadCollection"); + const firstItem = browser.$("#firstItem"); + + browser.execute(() => { + uploadCollection.setAttribute("mode", "Delete"); + }); + + const deleteBtn = firstItem.shadow$(".ui5-li-deletebtn"); + deleteBtn.click(); + + assert.strictEqual(uploadCollection.getProperty("items").length, 3, "item should be deleted when 'fileDeleted' event is fired"); + }); + }); + + describe("Edit - various file names", () => { + it("should preserve dots in the file name", () => { + const latestReportsPdf = browser.$("#latestReportsPdf"); + const editButton = latestReportsPdf.shadow$(".ui5-li-detailbtn"); + + editButton.click(); + browser.keys("-edited"); + browser.keys("Enter"); + + assert.strictEqual(latestReportsPdf.getProperty("fileName"), "latest.reports-edited.pdf", "dots in the file name should be preserved"); + }); + + it("should be able to add extension, if there isn't such", () => { + const noFileExtensionItem = browser.$("#noFileExtension"); + const editButton = noFileExtensionItem.shadow$(".ui5-li-detailbtn"); + + editButton.click(); + browser.keys(".newfileextension"); + browser.keys("Enter"); + + assert.strictEqual(noFileExtensionItem.getProperty("fileName"), "noextension.newfileextension", "the string after last dot is considered as extension"); + }); + }); + + describe("Drag and Drop", () => { + it("should NOT show drag and drop overlay when NOT dragging files", () => { + const uploadCollection = browser.$("#uploadCollection"); + const draggableElement = browser.$("#draggableElement"); + + draggableElement.dragAndDrop(uploadCollection); + + assert.notOk(browser.$(".uc-dnd-overlay").isDisplayed(), "the string after last dot is considered as extension"); + }); + }); +}); From f99c33e578aca01a9189eeea8889d51dea2d2b57 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 25 Mar 2020 15:06:13 +0200 Subject: [PATCH 22/42] rename uploadCollectionDemoHelper to uploadCollectionScript --- packages/fiori/test/pages/UploadCollection.html | 2 +- ...{uploadCollectionDemoHelper.js => uploadCollectionScript.js} | 0 packages/fiori/test/specs/UploadCollection.spec.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/fiori/test/pages/{uploadCollectionDemoHelper.js => uploadCollectionScript.js} (100%) diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 3352cea5381c..9d310da525b1 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -28,7 +28,7 @@ margin: 1rem; } - +
diff --git a/packages/fiori/test/pages/uploadCollectionDemoHelper.js b/packages/fiori/test/pages/uploadCollectionScript.js similarity index 100% rename from packages/fiori/test/pages/uploadCollectionDemoHelper.js rename to packages/fiori/test/pages/uploadCollectionScript.js diff --git a/packages/fiori/test/specs/UploadCollection.spec.js b/packages/fiori/test/specs/UploadCollection.spec.js index dbc228a6c3f1..ac986bf18e88 100644 --- a/packages/fiori/test/specs/UploadCollection.spec.js +++ b/packages/fiori/test/specs/UploadCollection.spec.js @@ -87,7 +87,7 @@ describe("UploadCollection", () => { draggableElement.dragAndDrop(uploadCollection); - assert.notOk(browser.$(".uc-dnd-overlay").isDisplayed(), "the string after last dot is considered as extension"); + assert.notOk(browser.$(".uc-dnd-overlay").isDisplayed(), "drag and drop overlay is not displayed"); }); }); }); From 797d14510468950cf8ea5fe43e73f6a1b98ad2ac Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 25 Mar 2020 15:50:03 +0200 Subject: [PATCH 23/42] use correct css vars for belize hcb/hcw --- packages/fiori/src/themes/UploadCollection.css | 3 ++- packages/fiori/src/themes/base/UploadCollection-parameters.css | 1 + .../src/themes/sap_belize_hcb/UploadCollection-parameters.css | 3 ++- .../src/themes/sap_belize_hcw/UploadCollection-parameters.css | 3 ++- .../theme-base/src/themes/sap_belize_hcb/base-parameters.less | 2 +- .../theme-base/src/themes/sap_belize_hcw/base-parameters.less | 2 +- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css index 59fb9ae1658a..8c866654cefb 100644 --- a/packages/fiori/src/themes/UploadCollection.css +++ b/packages/fiori/src/themes/UploadCollection.css @@ -96,5 +96,6 @@ .uc-drop-overlay ui5-icon, .uc-drop-overlay .dnd-overlay-text { - color: var(--sapActiveColor); + color: var(--ui5_upload_collection_drop_overlay_icon_color); + z-index: 1; } \ No newline at end of file diff --git a/packages/fiori/src/themes/base/UploadCollection-parameters.css b/packages/fiori/src/themes/base/UploadCollection-parameters.css index d8ab744c8783..890ccb74618c 100644 --- a/packages/fiori/src/themes/base/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/base/UploadCollection-parameters.css @@ -5,4 +5,5 @@ --ui5_upload_collection_drag_overlay_border: 0.125rem dashed var(--sapContent_ForegroundBorderColor); --ui5_upload_collection_drop_overlay_background: var(--sapUploadCollection_DropOverlayBackground); --ui5_upload_collection_drop_overlay_border: 0.125rem solid var(--sapActiveColor); + --ui5_upload_collection_drop_overlay_icon_color: var(--sapContent_NonInteractiveIconColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css index 12286325ed99..a9ad87d98ba9 100644 --- a/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css @@ -2,5 +2,6 @@ :root { --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); - --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapActiveColor); + --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapContent_HelpColor); + --ui5_upload_collection_drop_overlay_icon_color: var(--sapContent_HelpColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css index 12286325ed99..a9ad87d98ba9 100644 --- a/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css @@ -2,5 +2,6 @@ :root { --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); - --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapActiveColor); + --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapContent_HelpColor); + --ui5_upload_collection_drop_overlay_icon_color: var(--sapContent_HelpColor); } \ No newline at end of file diff --git a/packages/theme-base/src/themes/sap_belize_hcb/base-parameters.less b/packages/theme-base/src/themes/sap_belize_hcb/base-parameters.less index 97adcedef996..d2966b4975fd 100644 --- a/packages/theme-base/src/themes/sap_belize_hcb/base-parameters.less +++ b/packages/theme-base/src/themes/sap_belize_hcb/base-parameters.less @@ -307,4 +307,4 @@ @sapToggleButton_Pressed_HoverBorderColor: @sapButton_Hover_BorderColor; @sapUploadCollection_NoFilesIconColor: fade(@sapContent_NonInteractiveIconColor, 50); @sapUploadCollection_DragOverlayBackground: fade(@sapGroup_ContentBackground, 80); -@sapUploadCollection_DropOverlayBackground: fade(@sapActiveColor, 5); \ No newline at end of file +@sapUploadCollection_DropOverlayBackground: fade(@sapGroup_ContentBackground, 80); \ No newline at end of file diff --git a/packages/theme-base/src/themes/sap_belize_hcw/base-parameters.less b/packages/theme-base/src/themes/sap_belize_hcw/base-parameters.less index ee3ba2afcbcf..29bb43ba7828 100644 --- a/packages/theme-base/src/themes/sap_belize_hcw/base-parameters.less +++ b/packages/theme-base/src/themes/sap_belize_hcw/base-parameters.less @@ -307,4 +307,4 @@ @sapToggleButton_Pressed_HoverBorderColor: @sapButton_Hover_BorderColor; @sapUploadCollection_NoFilesIconColor: fade(@sapContent_NonInteractiveIconColor, 50); @sapUploadCollection_DragOverlayBackground: fade(@sapGroup_ContentBackground, 80); -@sapUploadCollection_DropOverlayBackground: fade(@sapActiveColor, 5); +@sapUploadCollection_DropOverlayBackground: fade(@sapGroup_ContentBackground, 80); From ae878d170105bb3e56cbcab280a4502bc0d4b6ab Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 25 Mar 2020 15:56:06 +0200 Subject: [PATCH 24/42] use correct css var for dnd icon and text --- packages/fiori/src/themes/base/UploadCollection-parameters.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/fiori/src/themes/base/UploadCollection-parameters.css b/packages/fiori/src/themes/base/UploadCollection-parameters.css index 890ccb74618c..2c26d796fecc 100644 --- a/packages/fiori/src/themes/base/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/base/UploadCollection-parameters.css @@ -5,5 +5,5 @@ --ui5_upload_collection_drag_overlay_border: 0.125rem dashed var(--sapContent_ForegroundBorderColor); --ui5_upload_collection_drop_overlay_background: var(--sapUploadCollection_DropOverlayBackground); --ui5_upload_collection_drop_overlay_border: 0.125rem solid var(--sapActiveColor); - --ui5_upload_collection_drop_overlay_icon_color: var(--sapContent_NonInteractiveIconColor); + --ui5_upload_collection_drop_overlay_icon_color: var(--sapActiveColor); } \ No newline at end of file From b6f31573ab87a2d722dc13682a06698c8a0ae46c Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 25 Mar 2020 16:16:39 +0200 Subject: [PATCH 25/42] select input's text after edit button is pressed --- packages/fiori/src/UploadCollectionItem.js | 12 ++++++++---- .../fiori/test/specs/UploadCollection.spec.js | 17 +++++++++++++---- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index f2ec4ff05784..ff745cef1720 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -172,13 +172,17 @@ class UploadCollectionItem extends ListItem { onAfterRendering() { if (this.focused && this._editing) { - this.focus(); - // TODO: find way to select input's value - // const inp = this.shadowRoot.getElementById("ui5-uci-edit-input"); - // inp.setSelectionRange(0, this._fileNameWithoutExtension.length); + this.focusAndSelectText(); } } + async focusAndSelectText() { + await this.focus(); + + const inp = this.shadowRoot.getElementById("ui5-uci-edit-input"); + inp.getFocusDomRef().setSelectionRange(0, this._fileNameWithoutExtension.length); + } + /** * @override */ diff --git a/packages/fiori/test/specs/UploadCollection.spec.js b/packages/fiori/test/specs/UploadCollection.spec.js index ac986bf18e88..c07e4fd4c35a 100644 --- a/packages/fiori/test/specs/UploadCollection.spec.js +++ b/packages/fiori/test/specs/UploadCollection.spec.js @@ -62,21 +62,30 @@ describe("UploadCollection", () => { const editButton = latestReportsPdf.shadow$(".ui5-li-detailbtn"); editButton.click(); - browser.keys("-edited"); + browser.keys("last.reports-edited"); browser.keys("Enter"); - assert.strictEqual(latestReportsPdf.getProperty("fileName"), "latest.reports-edited.pdf", "dots in the file name should be preserved"); + assert.strictEqual(latestReportsPdf.getProperty("fileName"), "last.reports-edited.pdf", "file extension '.pdf' should be preserved"); }); it("should be able to add extension, if there isn't such", () => { const noFileExtensionItem = browser.$("#noFileExtension"); const editButton = noFileExtensionItem.shadow$(".ui5-li-detailbtn"); + const newFileName = "newFileName.newExtension"; editButton.click(); - browser.keys(".newfileextension"); + browser.keys(newFileName); browser.keys("Enter"); - assert.strictEqual(noFileExtensionItem.getProperty("fileName"), "noextension.newfileextension", "the string after last dot is considered as extension"); + assert.strictEqual(noFileExtensionItem.getProperty("fileName"), newFileName, "file name should be changed"); + + const newFileName2 = "newFileName2"; + + editButton.click(); + browser.keys(newFileName2); + browser.keys("Enter"); + + assert.strictEqual(noFileExtensionItem.getProperty("fileName"), newFileName2 + ".newExtension", "the string after the last dot is considered as extension"); }); }); From 72a56a82b9775912951fa1b07f824dd9021f8c40 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 25 Mar 2020 17:20:15 +0200 Subject: [PATCH 26/42] implement design when media with is lower than 30rem --- packages/fiori/src/UploadCollectionItem.hbs | 50 ++++++++++--------- packages/fiori/src/UploadCollectionItem.js | 5 +- .../fiori/src/themes/UploadCollectionItem.css | 21 +++++++- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index d8c94ccd4475..525ed2c9a337 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -5,32 +5,34 @@
+
+ {{#if _editing}} +
+ + {{_fileExtension}} +
+ {{else }} + {{#if fileNameClickable}} + {{fileName}} + {{else}} + {{fileName}} + {{/if}} + {{/if}} +
+ +
+
+ {{#if _editing}} -
- - {{_fileExtension}} +
+ {{_renameBtnText}} + {{_cancelRenameBtnText}}
- {{else }} - {{#if fileNameClickable}} - {{fileName}} - {{else}} - {{fileName}} - {{/if}} {{/if}} -
- -
- - {{#if _editing}} -
- {{_renameBtnText}} - {{_cancelRenameBtnText}} -
- {{/if}} {{/inline}} diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index ff745cef1720..6d0eb88888a6 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -180,7 +180,10 @@ class UploadCollectionItem extends ListItem { await this.focus(); const inp = this.shadowRoot.getElementById("ui5-uci-edit-input"); - inp.getFocusDomRef().setSelectionRange(0, this._fileNameWithoutExtension.length); + + if (inp.getFocusDomRef()) { + inp.getFocusDomRef().setSelectionRange(0, this._fileNameWithoutExtension.length); + } } /** diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index 20b9609637b9..bb5df6e52dfe 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -34,7 +34,12 @@ /* Content */ .ui5-uci-content-container { - flex: 1; + flex: 1 1 0; + display: flex; +} + +.ui5-uci-content { + flex: 1 1 0; } .ui5-uci-file-name { @@ -82,6 +87,18 @@ ui5-link.ui5-uci-file-name { pointer-events: all; } -ui5-uci-edit-rename-btn { +.ui5-uci-edit-rename-btn { margin-right: 0.125rem; +} + +@media(max-width: 30rem) { + .ui5-uci-content-container { + display: block; + } + + .ui5-uci-edit-buttons, + .ui5-li-detailbtn, + .ui5-li-deletebtn { + margin-top: 0.75rem; + } } \ No newline at end of file From e2c4390e49a8503c05ac80fe046f16fafd995db4 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Thu, 26 Mar 2020 17:30:28 +0200 Subject: [PATCH 27/42] add progress indicator --- packages/fiori/src/UploadCollection.js | 21 --- packages/fiori/src/UploadCollectionItem.hbs | 83 +++++++---- packages/fiori/src/UploadCollectionItem.js | 135 +++++++++++++++++- .../fiori/src/i18n/messagebundle.properties | 23 ++- .../fiori/src/themes/UploadCollectionItem.css | 62 +++++++- .../base/UploadCollection-parameters.css | 2 + .../UploadCollection-parameters.css | 2 + .../UploadCollection-parameters.css | 2 + packages/fiori/src/types/UploadState.js | 46 ++++++ .../fiori/test/pages/UploadCollection.html | 51 ++++++- .../test/pages/uploadCollectionScript.js | 23 ++- 11 files changed, 383 insertions(+), 67 deletions(-) create mode 100644 packages/fiori/src/types/UploadState.js diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index e1ec27636dad..b18274f39fec 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -134,21 +134,6 @@ const metadata = { }, }, - /** - * Fired when any item gets its property fileName changed. - *

- * Note: An edit button is displayed on each item, - * when the ui5-upload-collection-item type property is set to Detail. - * @event - * @param {HTMLElement} item The ui5-upload-collection-item which was renamed. - * @public - */ - fileRenamed: { - detail: { - item: { type: HTMLElement }, - }, - }, - /** * Fired when selection is changed by user interaction * in SingleSelect and MultiSelect modes. @@ -222,8 +207,6 @@ class UploadCollection extends UI5Element { dragover: this._ondragover.bind(this), drop: this._ondrop.bind(this), }; - - this.addEventListener("ui5-_rename", this._onFileRenamed); } onEnterDOM() { @@ -317,10 +300,6 @@ class UploadCollection extends UI5Element { this._dndOverlayMode = "None"; } - _onFileRenamed(event) { - this.fireEvent("fileRenamed", { item: event.target }); - } - _onItemDelete(event) { this.fireEvent("fileDeleted", { item: event.detail.item }); } diff --git a/packages/fiori/src/UploadCollectionItem.hbs b/packages/fiori/src/UploadCollectionItem.hbs index 525ed2c9a337..49521457d7c8 100644 --- a/packages/fiori/src/UploadCollectionItem.hbs +++ b/packages/fiori/src/UploadCollectionItem.hbs @@ -4,35 +4,66 @@
-
-
- {{#if _editing}} -
- - {{_fileExtension}} -
- {{else }} - {{#if fileNameClickable}} - {{fileName}} - {{else}} - {{fileName}} + +
+
+
+ {{#if _editing}} +
+ + {{_fileExtension}} +
+ {{else }} + {{#if fileNameClickable}} + {{fileName}} + {{else}} + {{fileName}} + {{/if}} {{/if}} - {{/if}} -
- +
+ +
+ {{#if _showProgressIndicator}} +
+
+
+
+
+
+ {{_progressText}} + {{progress}}% +
+
+ {{/if}}
- - {{#if _editing}} -
+
+ {{#if _editing}} {{_renameBtnText}} {{_cancelRenameBtnText}} -
- {{/if}} + {{else}} + {{#if _showRetry}} + + {{/if}} + {{#if _showTerminate}} + + + {{/if}} + {{/if}} +
-{{/inline}} +{{/inline}} \ No newline at end of file diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 6d0eb88888a6..372286867bf5 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -1,12 +1,23 @@ import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import Button from "@ui5/webcomponents/dist/Button.js"; +import Icon from "@ui5/webcomponents/dist/Icon.js"; import Input from "@ui5/webcomponents/dist/Input.js"; +import Label from "@ui5/webcomponents/dist/Label.js"; import Link from "@ui5/webcomponents/dist/Link.js"; import ListItem from "@ui5/webcomponents/dist/ListItem.js"; +import Integer from "@ui5/webcomponents-base/dist/types/Integer.js"; +import UploadState from "./types/UploadState.js"; +import "@ui5/webcomponents-icons/dist/icons/refresh.js"; +import "@ui5/webcomponents-icons/dist/icons/stop.js"; import { UPLOADCOLLECTIONITEM_CANCELBUTTON_TEXT, UPLOADCOLLECTIONITEM_RENAMEBUTTON_TEXT, + UPLOADCOLLECTIONITEM_ERROR_STATE, + UPLOADCOLLECTIONITEM_UPLOADING_STATE, + UPLOADCOLLECTIONITEM_READY_STATE, + UPLOADCOLLECTIONITEM_RETRY_BUTTON_TEXT, + UPLOADCOLLECTIONITEM_TERMINATE_BUTTON_TEXT, } from "./generated/i18n/i18n-defaults.js"; // Template @@ -63,6 +74,40 @@ const metadata = { type: Boolean, }, + noRetry: { + type: Boolean, + }, + + noTerminate: { + type: Boolean, + }, + + /** + * The upload progress in percentage. + *

+ * Note: Expected values are in the interval [0, 100]. + * + * @type {Integer} + * @defaultvalue 0 + * @public + */ + progress: { + type: Integer, + defaultValue: 0, + }, + + /** + * If set to Uploading or Error, a progress indicator showing the progress is displayed. + * + * @type {string} + * @defaultvalue "Ready" + * @public + */ + uploadState: { + type: UploadState, + defaultValue: UploadState.Ready, + }, + /** * Indicates if editing. * @@ -104,12 +149,39 @@ const metadata = { * Note: This event is only available when fileNameClickable property is true. * * @event - * @param {HTMLElement} item The ui5-upload-collection-item which was renamed. * @public */ fileNameClick: { }, - _rename: { }, + /** + * Fired when the fileName property gets changed. + *

+ * Note: An edit button is displayed on each item, + * when the ui5-upload-collection-item type property is set to Detail. + * + * @event + * @public + */ + rename: { }, + + /** + * Fired when the terminate button is pressed. + *

+ * Note: Terminate button is displayed when uploadState property is set to Uploading. + * + * @event + * @public + */ + terminate: {}, + + /** + * Fired when the retry button is pressed. + *

+ * Note: Retry button is displayed when uploadState property is set to Error. + * @event + * @public + */ + retry: {}, }, }; @@ -153,8 +225,10 @@ class UploadCollectionItem extends ListItem { static async onDefine() { await Promise.all([ Button.define(), + Icon.define(), Input.define(), Link.define(), + Label.define(), fetchI18nBundle("@ui5/webcomponents"), ]); } @@ -201,7 +275,7 @@ class UploadCollectionItem extends ListItem { this._editing = false; this.fileName = event.target.value + this._fileExtension; - this.fireEvent("_rename"); + this.fireEvent("rename"); } _onRenameCancel(event) { @@ -212,6 +286,14 @@ class UploadCollectionItem extends ListItem { this.fireEvent("fileNameClick"); } + _onRetry(event) { + this.fireEvent("retry"); + } + + _onTerminate(event) { + this.fireEvent("terminate"); + } + /** * @override */ @@ -222,7 +304,24 @@ class UploadCollectionItem extends ListItem { main: { ...result.main, "ui5-uci-root": true, - "ui5-uci-root-edit": this._editing, + "ui5-uci-root-editing": this._editing, + "ui5-uci-root-uploading": this.uploadState === UploadState.Uploading, + }, + progressIndicator: { + "ui5-uci-progress-indicator": true, + "error": this.uploadState === UploadState.Error, + }, + }; + } + + get styles() { + return { + progressBar: { + "flex-basis": `${this.progress}%`, + }, + progressBarRemaining: { + "border-left": this.progress !== 0 ? "none" : "", + "border-radius": this.progress === 0 ? "0.5rem" : "0 0.5rem 0.5rem 0", }, }; } @@ -249,6 +348,34 @@ class UploadCollectionItem extends ListItem { get _cancelRenameBtnText() { return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_CANCELBUTTON_TEXT); } + + get _showProgressIndicator() { + return this.uploadState !== UploadState.Complete; + } + + get _progressText() { + switch (this.uploadState) { + case UploadState.Error: return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_ERROR_STATE); + case UploadState.Uploading: return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_UPLOADING_STATE); + default: return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_READY_STATE); + } + } + + get _showRetry() { + return !this.noRetry && this.uploadState === UploadState.Error; + } + + get _showTerminate() { + return !this.noTerminate && this.uploadState === UploadState.Uploading; + } + + get _retryButtonTooltip() { + return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_RETRY_BUTTON_TEXT); + } + + get _terminateButtonTooltip() { + return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_TERMINATE_BUTTON_TEXT); + } } UploadCollectionItem.define(); diff --git a/packages/fiori/src/i18n/messagebundle.properties b/packages/fiori/src/i18n/messagebundle.properties index e9394a7f2e8f..742bfd79f9f4 100644 --- a/packages/fiori/src/i18n/messagebundle.properties +++ b/packages/fiori/src/i18n/messagebundle.properties @@ -1,16 +1,31 @@ #This is the resource bundle for the UI5 Web Components #__ldi.translation.uuid=95d47730-48a4-4d6d-92f6-61f8c9d8f274 -#XBUT: Button text for cancel button in the upload collection +#XBUT: Button text for cancel button in the UploadCollectionItem UPLOADCOLLECTIONITEM_CANCELBUTTON_TEXT=Cancel -#XBUT: Text for Rename button in the upload collection in case of renaming a file +#XBUT: Text for Rename button in the UploadCollectionItem in case of renaming a file UPLOADCOLLECTIONITEM_RENAMEBUTTON_TEXT=Rename -#XMSG: Message text for no data text in the upload collection +#XTXT: Text for 'Error' upload state in the UploadCollectionItem +UPLOADCOLLECTIONITEM_ERROR_STATE=Terminated + +#XTXT: Text for 'Ready' upload state in the UploadCollectionItem +UPLOADCOLLECTIONITEM_READY_STATE=Pending + +#XTXT: Text for 'Uploading' upload state in the UploadCollectionItem +UPLOADCOLLECTIONITEM_UPLOADING_STATE=Uploading + +#XBUT: Tooltip text for 'Terminate' button in the UploadCollectionItem +UPLOADCOLLECTIONITEM_TERMINATE_BUTTON_TEXT=Terminate + +#XBUT: Tooltip text for 'Retrry' button in the UploadCollectionItem +UPLOADCOLLECTIONITEM_RETRY_BUTTON_TEXT=Retry + +#XMSG: Message text for no data text in the UploadCollection UPLOADCOLLECTION_NO_DATA_TEXT=No files found. -#XMSG: Message text for no data description in the upload collection +#XMSG: Message text for no data description in the UploadCollection UPLOADCOLLECTION_NO_DATA_DESCRIPTION=Drop files to upload, or use the Upload button. #XMSG: Message text indicating where to drag diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index bb5df6e52dfe..242383ab8845 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -33,13 +33,19 @@ } /* Content */ -.ui5-uci-content-container { - flex: 1 1 0; +.ui5-uci-content-and-edit-container { + flex: 1 1 auto; display: flex; + align-items: center; +} + +.ui5-uci-content-and-progress { + display: flex; + flex: 1 1 auto; } .ui5-uci-content { - flex: 1 1 0; + flex: 1 1 auto; } .ui5-uci-file-name { @@ -76,15 +82,17 @@ ui5-link.ui5-uci-file-name { width: 40%; } - /* Buttons */ -.ui5-uci-root-edit .ui5-li-detailbtn, -.ui5-uci-root-edit .ui5-li-deletebtn { +.ui5-uci-root-editing .ui5-li-detailbtn, +.ui5-uci-root-editing .ui5-li-deletebtn, +.ui5-uci-root-uploading .ui5-li-detailbtn, +.ui5-uci-root-uploading .ui5-li-deletebtn { display: none; } .ui5-uci-edit-buttons { pointer-events: all; + margin-left: 1rem; } .ui5-uci-edit-rename-btn { @@ -92,7 +100,7 @@ ui5-link.ui5-uci-file-name { } @media(max-width: 30rem) { - .ui5-uci-content-container { + .ui5-uci-content-and-edit-container { display: block; } @@ -101,4 +109,44 @@ ui5-link.ui5-uci-file-name { .ui5-li-deletebtn { margin-top: 0.75rem; } +} + +/* Progress Box */ +.ui5-uci-progress-box { + width: 20%; + margin-left: 0.5rem; +} + +.ui5-uci-progress-indicator { + display: flex; + background: var(--sapField_Background); + height: 1.125rem; + min-height: 1rem; + width: 100%; + min-width: 4rem; + margin: 0.5rem 0; + padding: 5px; + box-sizing: border-box; +} + + +.ui5-uci-progress-indicator.error .ui5-uci-progress-bar { + background: var(--ui5_upload_collection_progress_indicator_error_background); +} + +.ui5-uci-progress-bar { + border-radius: 0.5rem 0 0 0.5rem; + flex-basis: 30%; + background: var(--ui5_upload_collection_progress_indicator_background); +} + +.ui5-uci-progress-bar-remaining { + border: 0.0625rem solid var(--sapField_BorderColor); + box-sizing: border-box; + flex: 1 1 auto; +} + +.ui5-uci-progress-labels { + display: flex; + justify-content: space-between; } \ No newline at end of file diff --git a/packages/fiori/src/themes/base/UploadCollection-parameters.css b/packages/fiori/src/themes/base/UploadCollection-parameters.css index 2c26d796fecc..d7603a2ebe60 100644 --- a/packages/fiori/src/themes/base/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/base/UploadCollection-parameters.css @@ -6,4 +6,6 @@ --ui5_upload_collection_drop_overlay_background: var(--sapUploadCollection_DropOverlayBackground); --ui5_upload_collection_drop_overlay_border: 0.125rem solid var(--sapActiveColor); --ui5_upload_collection_drop_overlay_icon_color: var(--sapActiveColor); + --ui5_upload_collection_progress_indicator_background: var(--sapInformativeElementColor); + --ui5_upload_collection_progress_indicator_error_background: var(--sapNegativeElementColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css index a9ad87d98ba9..77e92274d1af 100644 --- a/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css @@ -4,4 +4,6 @@ --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapContent_HelpColor); --ui5_upload_collection_drop_overlay_icon_color: var(--sapContent_HelpColor); + --ui5_upload_collection_progress_indicator_background: var(--sapHighlightColor); + --ui5_upload_collection_progress_indicator_error_background: var(--sapHighlightColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css index a9ad87d98ba9..77e92274d1af 100644 --- a/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css @@ -4,4 +4,6 @@ --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapContent_HelpColor); --ui5_upload_collection_drop_overlay_icon_color: var(--sapContent_HelpColor); + --ui5_upload_collection_progress_indicator_background: var(--sapHighlightColor); + --ui5_upload_collection_progress_indicator_error_background: var(--sapHighlightColor); } \ No newline at end of file diff --git a/packages/fiori/src/types/UploadState.js b/packages/fiori/src/types/UploadState.js new file mode 100644 index 000000000000..33bb4c8eef6a --- /dev/null +++ b/packages/fiori/src/types/UploadState.js @@ -0,0 +1,46 @@ +import DataType from "@ui5/webcomponents-base/dist/types/DataType.js"; + +const UploadStates = { + /** + * The file has been uploaded successfully. + * @public + */ + Complete: "Complete", + + /** + * The file cannot be uploaded due to an error. + * @public + */ + Error: "Error", + + /** + * The file is awaiting an explicit command to start being uploaded. + * @public + */ + Ready: "Ready", + + /** + * The file is currently being uploaded. + * @public + */ + Uploading: "Uploading", +}; + +/** + * States of the upload process of ui5-upload-collection-item. + * + * @class + * @constructor + * @author SAP SE + * @public + * @enum {string} + */ +class UploadState extends DataType { + static isValid(value) { + return !!UploadStates[value]; + } +} + +UploadState.generataTypeAcessors(UploadStates); + +export default UploadState; diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 9d310da525b1..ad4c32802b9a 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -68,6 +68,7 @@ id="firstItem" file-name="LaptopHT-1000.jpg" file-name-clickable + upload-state="Complete" > File name is clickable. @@ -77,6 +78,7 @@ file-name="Laptop.jpg" type="Detail" no-delete + upload-state="Complete" > You cannot delete this file. @@ -85,17 +87,18 @@ id="latestReportsPdf" file-name="latest.reports.pdf" type="Detail" + upload-state="Complete" > - Some description + Some description. - Some description @@ -108,5 +111,49 @@
+ + +
+ Upload States +
+ + + uploadState="Complete" + + + + uploadState="Uploading" + + + + uploadState="Error" + + + + uploadState="Ready" (default) + +
\ No newline at end of file diff --git a/packages/fiori/test/pages/uploadCollectionScript.js b/packages/fiori/test/pages/uploadCollectionScript.js index 9e0fe375707f..40ace22dafe7 100644 --- a/packages/fiori/test/pages/uploadCollectionScript.js +++ b/packages/fiori/test/pages/uploadCollectionScript.js @@ -83,17 +83,23 @@ uploadCollection.removeChild(event.detail.item) }); - uploadCollection.addEventListener("ui5-fileRenamed", function (event) { - document.getElementById("renamedFileIndex").innerText = uploadCollection.items.indexOf(event.detail.item); + uploadCollection.addEventListener("ui5-rename", function (event) { + document.getElementById("renamedFileIndex").innerText = uploadCollection.items.indexOf(event.target); }); document.getElementById("startUploading").addEventListener("click", function(event) { uploadCollection.items.forEach(function (item) { if (item.file) { var oXHR = new XMLHttpRequest(); - + oXHR.open("POST", "/upload", true); + oXHR.onreadystatechange = function () { + if (this.status !== 200) { + item.uploadState = "Error"; + } + }; oXHR.send(item.file); + item.uploadState="Uploading"; } }); }); @@ -109,4 +115,15 @@ document.getElementById("uploadCollectionDnD").appendChild(uci) } }); + + // Upload States + var uploadCollectionDifferentStates = document.getElementById("uploadCollectionStates"); + + uploadCollectionDifferentStates.addEventListener("ui5-retry", function (event) { + console.log("Retry uploading: ", event.target); + }); + + uploadCollectionDifferentStates.addEventListener("ui5-terminate", function (event) { + console.log("Terminate uploading of: ", event.target); + }); })() \ No newline at end of file From 2bc17ae9d7908a89d55defa9f1178c8fcdfbfa2f Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Thu, 26 Mar 2020 18:01:46 +0200 Subject: [PATCH 28/42] add tests for progress indicator --- .../fiori/test/pages/UploadCollection.html | 11 +++-- .../test/pages/uploadCollectionScript.js | 2 + .../fiori/test/specs/UploadCollection.spec.js | 49 ++++++++++++++++--- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index ad4c32802b9a..a66d13e2e7a5 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -112,12 +112,15 @@
+
+ +
Upload States
diff --git a/packages/fiori/test/pages/uploadCollectionScript.js b/packages/fiori/test/pages/uploadCollectionScript.js index 40ace22dafe7..6c8bc0c41291 100644 --- a/packages/fiori/test/pages/uploadCollectionScript.js +++ b/packages/fiori/test/pages/uploadCollectionScript.js @@ -121,9 +121,11 @@ uploadCollectionDifferentStates.addEventListener("ui5-retry", function (event) { console.log("Retry uploading: ", event.target); + document.getElementById("uploadStateEvent").innerText = "Retry"; }); uploadCollectionDifferentStates.addEventListener("ui5-terminate", function (event) { console.log("Terminate uploading of: ", event.target); + document.getElementById("uploadStateEvent").innerText = "Terminate"; }); })() \ No newline at end of file diff --git a/packages/fiori/test/specs/UploadCollection.spec.js b/packages/fiori/test/specs/UploadCollection.spec.js index c07e4fd4c35a..2b2d9d8954aa 100644 --- a/packages/fiori/test/specs/UploadCollection.spec.js +++ b/packages/fiori/test/specs/UploadCollection.spec.js @@ -6,12 +6,12 @@ describe("UploadCollection", () => { it("should show Link when 'fileNameClickable'", () => { const firstItem = browser.$("#firstItem"); - assert.ok(firstItem.shadow$("ui5-link"), "Link should be rendered"); + assert.ok(firstItem.shadow$("ui5-link").isDisplayed(), "Link should be rendered"); }); it("should show span when file name is NOT clickable", () => { const secondItem = browser.$("#secondItem"); - assert.ok(secondItem.shadow$("span.ui5-uci-file-name"), "span should be rendered"); + assert.ok(secondItem.shadow$("span.ui5-uci-file-name").isDisplayed(), "span should be rendered"); }); it("should show input and buttons when editing", () => { @@ -19,17 +19,37 @@ describe("UploadCollection", () => { const editButton = secondItem.shadow$(".ui5-li-detailbtn"); editButton.click(); - assert.ok(secondItem.shadow$(".ui5-uci-edit-container"), "edit container should be rendered"); - assert.ok(secondItem.shadow$(".ui5-uci-edit-buttons"), "edit buttons should be rendered"); + assert.ok(secondItem.shadow$(".ui5-uci-edit-container").isDisplayed(), "edit container should be rendered"); + assert.ok(secondItem.shadow$(".ui5-uci-edit-buttons").isDisplayed(), "edit buttons should be rendered"); assert.notOk(secondItem.shadow$(".ui5-li-detailbtn").isDisplayed(), "detail button should be hidden"); // focus out the second item, to hide edit buttons (reset state for the following tests) browser.$("#firstItem").click(); }); + + it("should show NOT show any buttons besides 'Terminate', when uploadState is 'Uploading'", () => { + const uploadingStateItem = browser.$("#uploadingState"); + + assert.ok(uploadingStateItem.shadow$("ui5-button[icon=stop]").isDisplayed(), "'Terminate' button is displayed'"); + assert.notOk(uploadingStateItem.shadow$(".ui5-li-detailbtn").isDisplayed(), "detail button should be hidden"); + assert.notOk(uploadingStateItem.shadow$(".ui5-li-deletebtn").isDisplayed(), "detail button should be hidden"); + }); + + it("should show 'Retry' button when uploadState is 'Error'", () => { + const errorStateItem = browser.$("#errorState"); + + assert.ok(errorStateItem.shadow$("ui5-button[icon=refresh]").isDisplayed(), "'Retry' button is displayed"); + assert.ok(errorStateItem.shadow$(".ui5-li-detailbtn").isDisplayed(), "detail button is also displayed"); + + errorStateItem.shadow$(".ui5-li-detailbtn").click(); + + assert.notOk(errorStateItem.shadow$("ui5-button[icon=refresh]").isDisplayed(), "'Retry' button is NOT displayed when editing"); + assert.notOk(errorStateItem.shadow$(".ui5-li-detailbtn").isDisplayed(), "detail button is NOT displayed when editing"); + }); }); describe("Events", () => { - it("should fire 'fileRenamed'", () => { + it("item should fire 'rename'", () => { const secondItem = browser.$("#secondItem"); const secondItemIndex = 1; const editButton = secondItem.shadow$(".ui5-li-detailbtn"); @@ -41,7 +61,7 @@ describe("UploadCollection", () => { assert.strictEqual(parseInt(browser.$("#renamedFileIndex").getText()), secondItemIndex, "renamed file index should be updated after rename") }); - it("should fire 'fileDeleted'", () => { + it("upload collection should fire 'fileDeleted'", () => { const uploadCollection = browser.$("#uploadCollection"); const firstItem = browser.$("#firstItem"); @@ -54,6 +74,22 @@ describe("UploadCollection", () => { assert.strictEqual(uploadCollection.getProperty("items").length, 3, "item should be deleted when 'fileDeleted' event is fired"); }); + + it("item should fire 'retry'", () => { + const errorStateItem = browser.$("#errorState"); + + errorStateItem.shadow$("ui5-button[icon=refresh]").click(); + + assert.ok(browser.$("#uploadStateEvent").getText().includes("Retry"), "Retry event is fired"); + }); + + it("item should fire 'terminate'", () => { + const uploadingStateItem = browser.$("#uploadingState"); + + uploadingStateItem.shadow$("ui5-button[icon=stop]").click(); + + assert.ok(browser.$("#uploadStateEvent").getText().includes("Terminate"), "Terminate event is fired"); + }); }); describe("Edit - various file names", () => { @@ -94,6 +130,7 @@ describe("UploadCollection", () => { const uploadCollection = browser.$("#uploadCollection"); const draggableElement = browser.$("#draggableElement"); + draggableElement.scrollIntoView(); draggableElement.dragAndDrop(uploadCollection); assert.notOk(browser.$(".uc-dnd-overlay").isDisplayed(), "drag and drop overlay is not displayed"); From 062b138c617f55ab96338bc8f9cdf93ea5e17bd5 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 27 Mar 2020 11:50:55 +0200 Subject: [PATCH 29/42] fix overflow issues --- packages/fiori/src/themes/UploadCollectionItem.css | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index 242383ab8845..f29c8e390d5e 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -35,6 +35,7 @@ /* Content */ .ui5-uci-content-and-edit-container { flex: 1 1 auto; + min-width: 0; /* fixes chrome overflow issue */ display: flex; align-items: center; } @@ -46,12 +47,14 @@ .ui5-uci-content { flex: 1 1 auto; + min-width: 0; /* fixes chrome overflow issue */ } .ui5-uci-file-name { display: block; font-size: var(--sapFontLargeSize); margin-bottom: 0.25rem; + white-space: pre-wrap; } ui5-link.ui5-uci-file-name { @@ -70,6 +73,7 @@ ui5-link.ui5-uci-file-name { .ui5-uci-edit-container ui5-input { width: 60%; pointer-events: all; + min-width: auto; } .ui5-uci-file-extension { @@ -109,12 +113,17 @@ ui5-link.ui5-uci-file-name { .ui5-li-deletebtn { margin-top: 0.75rem; } + + .ui5-uci-edit-buttons { + margin-left: 0; + } } /* Progress Box */ .ui5-uci-progress-box { width: 20%; margin-left: 0.5rem; + min-width: 4rem; } .ui5-uci-progress-indicator { @@ -124,7 +133,7 @@ ui5-link.ui5-uci-file-name { min-height: 1rem; width: 100%; min-width: 4rem; - margin: 0.5rem 0; + margin-bottom: 0.5rem; padding: 5px; box-sizing: border-box; } From 10ecceccdb43519d61a668de3109d0a36da71f31 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 27 Mar 2020 11:55:08 +0200 Subject: [PATCH 30/42] make span for file extension inline-block --- packages/fiori/src/themes/UploadCollectionItem.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index f29c8e390d5e..b6e02948beca 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -84,6 +84,8 @@ ui5-link.ui5-uci-file-name { overflow: hidden; margin-left: 0.5rem; width: 40%; + display: inline-block; + vertical-align: middle; } /* Buttons */ From aa7a75e85d6604876c41a48555878a5e0f82049b Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 27 Mar 2020 16:21:59 +0200 Subject: [PATCH 31/42] add playground sample --- packages/fiori/src/UploadCollection.js | 8 +- packages/fiori/src/UploadCollectionItem.js | 5 +- .../fiori/test/pages/UploadCollection.html | 5 +- .../test/pages/uploadCollectionScript.js | 13 +- .../test/samples/UploadCollection.sample.html | 517 ++++++++++++++++++ packages/playground/assets/images/HT-1000.jpg | Bin 0 -> 57712 bytes 6 files changed, 528 insertions(+), 20 deletions(-) create mode 100644 packages/fiori/test/samples/UploadCollection.sample.html create mode 100644 packages/playground/assets/images/HT-1000.jpg diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index b18274f39fec..d4b69190d1c9 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -154,13 +154,10 @@ const metadata = { * @class * *

Overview

+ * This component allows you to represent files before uploading them to a server, with the help of ui5-upload-collection-item. + * It also allows you to show already uploaded files. * - * - *

Usage

- * - * For the ui5-upload-collection *

ES6 Module Import

- * * import @ui5/webcomponents-fiori/dist/UploadCollection.js"; * * @constructor @@ -168,6 +165,7 @@ const metadata = { * @alias sap.ui.webcomponents.fiori.UploadCollection * @extends UI5Element * @tagname ui5-upload-collection + * @appenddocs UploadCollectionItem * @public */ class UploadCollection extends UI5Element { diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 372286867bf5..6ba2d1f58d28 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -189,11 +189,8 @@ const metadata = { * @class * *

Overview

+ * A component to be used within the ui5-upload-collection. * - * - *

Usage

- * - * For the ui5-upload-collection-item *

ES6 Module Import

* * import @ui5/webcomponents-fiori/dist/UploadCollectionItem.js"; diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index a66d13e2e7a5..3521e8cc7cd3 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -57,8 +57,9 @@
- Upload Files - Start Uploading + Uploaded (4) + Add new files and press to start uploading pending files: + Start
diff --git a/packages/fiori/test/pages/uploadCollectionScript.js b/packages/fiori/test/pages/uploadCollectionScript.js index 6c8bc0c41291..860980140dd6 100644 --- a/packages/fiori/test/pages/uploadCollectionScript.js +++ b/packages/fiori/test/pages/uploadCollectionScript.js @@ -36,18 +36,13 @@ } function createUCI(file) { - var uci = document.createElement("ui5-upload-collection-item"), - cont = document.createElement("ui5-label"); + var uci = document.createElement("ui5-upload-collection-item"); + description = document.createTextNode("Last modified: " + file.lastModifiedDate + ", size: " + file.size); uci.appendChild(createThumbnail(file.name)); + uci.appendChild(description); uci.file = file; uci.fileName = file.name; - - cont.classList.add("description"); - cont.wrap = true; - cont.textContent = "Last modified: " + file.lastModifiedDate - + ", size: " + file.size; - uci.appendChild(cont); return uci; } @@ -89,7 +84,7 @@ document.getElementById("startUploading").addEventListener("click", function(event) { uploadCollection.items.forEach(function (item) { - if (item.file) { + if (item.uploadState === "Ready" && item.file) { var oXHR = new XMLHttpRequest(); oXHR.open("POST", "/upload", true); diff --git a/packages/fiori/test/samples/UploadCollection.sample.html b/packages/fiori/test/samples/UploadCollection.sample.html new file mode 100644 index 000000000000..a9939ca217cd --- /dev/null +++ b/packages/fiori/test/samples/UploadCollection.sample.html @@ -0,0 +1,517 @@ + + +
+

UploadCollection

+
+ +
+
+ +
@ui5/webcomponents-fiori
+ +
<ui5-upload-collection>
+ + +
+

UploadCollection

+
+ +
+ Uploaded (2) + Add new files and press to start uploading pending files: + Start +
+ + + +
+ + + Uploaded By: David Keane · Uploaded On: 2014-07-26 · File Size: 35 KB + + + + Uploaded By: John Smith · Uploaded On: 2014-09-02 · File Size: 226.6 KB · + +
+ + +
+

+<style>
+	.header {
+		display: flex;
+		align-items: center;
+		overflow: hidden;
+	}
+
+	.spacer {
+		flex: 1 1 auto;
+	}
+
+	.header > * {
+		margin: 4px;
+	}
+</style>
+
+<ui5-upload-collection id="uploadCollection">
+	<div slot="header" class="header">
+		<ui5-title>Uploaded (2)</ui5-title>
+		<ui5-label>Add new files and press to start uploading pending files:</ui5-label>
+		<ui5-button id="startUploading">Start</ui5-button>
+		<div class="spacer"></div>
+		<ui5-file-uploader id="fileUploader" hide-input multiple>
+			<ui5-button icon="add" design="Transparent"></ui5-button>
+		</ui5-file-uploader>
+	</div>
+	<ui5-upload-collection-item
+		file-name="LaptopHT-1000.jpg"
+		file-name-clickable
+		upload-state="Complete"
+	>
+		<img src="../../../assets/images/HT-1000.jpg" slot="thumbnail">
+		Uploaded By: David Keane · Uploaded On: 2014-07-26 · File Size: 35 KB
+	</ui5-upload-collection-item>
+	<ui5-upload-collection-item
+		file-name="Notes.txt"
+		upload-state="Complete"
+	>
+		<ui5-icon name="document-text" slot="thumbnail"></ui5-icon>
+		Uploaded By: John Smith · Uploaded On: 2014-09-02 · File Size: 226.6 KB ·
+	</ui5-upload-collection-item>
+</ui5-upload-collection>	
+
+<script>
+	function fileExtensionToIconName(fileName) {
+		var extension = fileName.split(".").pop();
+
+		switch (extension) {
+			case "bmp":
+			case "jpg":
+			case "jpeg":
+			case "png":
+				return "card";
+			case "docx":
+			case "pdf":
+				return "pdf-attachment";
+			case "txt":
+				return "document-text";
+			default:
+				return "document";
+		}
+	}
+
+	function createThumbnail(fileName) {
+		var icon = document.createElement("ui5-icon");
+		icon.name = fileExtensionToIconName(fileName);
+		icon.slot = "thumbnail";
+		return icon;
+	}
+
+	function createUCI(file) {
+		var uci = document.createElement("ui5-upload-collection-item");
+			description = document.createTextNode("Last modified: " + file.lastModifiedDate + ", size: " + file.size);
+
+		uci.appendChild(createThumbnail(file.name));
+		uci.appendChild(description);
+		uci.file = file;
+		uci.fileName = file.name;
+		return uci;
+	}
+
+	fileUploader.addEventListener("ui5-change", function(event) {
+		var files = event.detail.files;
+
+		for (var i = 0; i < files.length; i++) {
+			uploadCollection.appendChild(createUCI(files[i]));
+		}
+	});
+
+	startUploading.addEventListener("click", function(event) {
+		uploadCollection.items.forEach(function (item) {
+			if (item.uploadState === "Ready" && item.file) {
+				var oXHR = new XMLHttpRequest();
+				
+				oXHR.open("POST", "/upload", true);
+				oXHR.onreadystatechange  = function () {
+					if (this.status !== 200) {
+						item.uploadState = "Error";
+					}
+				};
+				oXHR.send(item.file);
+				item.uploadState="Uploading";
+			}
+		});
+	});
+</script>
+	
+
+ + +
+

UploadCollection With File Renaming Enabled

+
+ +
+ Attachments(2) +
+ + + Uploaded By: David Keane · Uploaded On: 2014-07-26 · File Size: 35 KB + + + + Uploaded By: John Smith · Uploaded On: 2014-09-02 · File Size: 226.6 KB · + +
+ + +
+ +

+<ui5-upload-collection id="uploadCollectionWithRenaming">
+	<div slot="header" class="header">
+		<ui5-title>Attachments(2)</ui5-title>
+	</div>
+	<ui5-upload-collection-item
+		file-name="LaptopHT-1000.jpg"
+		file-name-clickable
+		type="Detail"
+		upload-state="Complete"
+	>
+		<img src="../../../assets/images/HT-1000.jpg" slot="thumbnail">
+		Uploaded By: David Keane · Uploaded On: 2014-07-26 · File Size: 35 KB
+	</ui5-upload-collection-item>
+	<ui5-upload-collection-item
+		file-name="Notes.txt"
+		type="Detail"
+		upload-state="Complete"
+	>
+		<ui5-icon name="document-text" slot="thumbnail"></ui5-icon>
+		Uploaded By: John Smith · Uploaded On: 2014-09-02 · File Size: 226.6 KB ·
+	</ui5-upload-collection-item>
+</ui5-upload-collection>	
+
+<script>
+	uploadCollectionWithRenaming.addEventListener("ui5-rename", function (event) {
+		alert("Rename event:" + event.target.fileName)
+	});
+</script>
+	
+
+ + +
+

UploadCollection With Different Uploading States of Items

+
+ +
+ Upload States +
+ + + uploadState="Complete" + + + + uploadState="Uploading" + + + + uploadState="Error" + + + + uploadState="Ready" (default) + +
+ + +
+ +

+<ui5-upload-collection id="uploadCollectionStates">
+	<div class="header" slot="header">
+		<ui5-title>Upload States</ui5-title>
+	</div>
+	<ui5-upload-collection-item
+		file-name="LaptopHT-1000.jpg"
+		upload-state="Complete"
+	>
+		<img src="../../../assets/images/HT-1000.jpg" slot="thumbnail">
+		uploadState="Complete"
+	</ui5-upload-collection-item>
+	<ui5-upload-collection-item
+		file-name="Laptop.jpg"
+		upload-state="Uploading"
+		progress="37"
+	>
+		<img src="../../../assets/images/HT-1000.jpg"slot="thumbnail">
+		uploadState="Uploading"
+	</ui5-upload-collection-item>
+	<ui5-upload-collection-item
+		file-name="latest.reports.pdf"
+		upload-state="Error"
+		progress="59"
+	>
+		<ui5-icon name="document-text" slot="thumbnail"></ui5-icon>
+		uploadState="Error"
+	</ui5-upload-collection-item>
+	<ui5-upload-collection-item
+		file-name="Notes.txt"
+	>
+		<ui5-icon name="document-text" slot="thumbnail"></ui5-icon>
+		uploadState="Ready" (default)
+	</ui5-upload-collection-item>
+</ui5-upload-collection>
+
+<script>
+	uploadCollectionStates.addEventListener("ui5-retry", function (event) {
+		alert("Retry uploading: " + event.target.fileName);
+	});
+
+	uploadCollectionStates.addEventListener("ui5-terminate", function (event) {
+		alert("Terminate uploading of: " + event.target.fileName);
+	});
+</script>
+	
+
+ + +
+

UploadCollection With Drag and Drop and No Initial Data

+
+ +
+ Attachments +
+
+ + +
+ +

+<ui5-upload-collection id="uploadCollectionDnD" style="height: 30rem;">
+	<div class="header" slot="header">
+		<ui5-title>Attachments</ui5-title>
+	</div>
+</ui5-upload-collection>
+
+<script>
+	function fileExtensionToIconName(fileName) {
+		var extension = fileName.split(".").pop();
+
+		switch (extension) {
+			case "bmp":
+			case "jpg":
+			case "jpeg":
+			case "png":
+				return "card";
+			case "docx":
+			case "pdf":
+				return "pdf-attachment";
+			case "txt":
+				return "document-text";
+			default:
+				return "document";
+		}
+	}
+
+	function createThumbnail(fileName) {
+		var icon = document.createElement("ui5-icon");
+		icon.name = fileExtensionToIconName(fileName);
+		icon.slot = "thumbnail";
+		return icon;
+	}
+
+	function createUCI(file) {
+		var uci = document.createElement("ui5-upload-collection-item");
+			description = document.createTextNode("Last modified: " + file.lastModifiedDate + ", size: " + file.size);
+
+		uci.appendChild(createThumbnail(file.name));
+		uci.appendChild(description);
+		uci.file = file;
+		uci.fileName = file.name;
+		return uci;
+	}
+
+	uploadCollectionDnD.addEventListener("drop", function(event) {
+		event.preventDefault();
+
+		var files = event.dataTransfer.files;
+
+		for (var i = 0; i < files.length; i++) {
+			uci = createUCI(files[i]);
+			uploadCollectionDnD.appendChild(uci)
+		}
+	});
+</script>
+	
+
+ + \ No newline at end of file diff --git a/packages/playground/assets/images/HT-1000.jpg b/packages/playground/assets/images/HT-1000.jpg new file mode 100644 index 0000000000000000000000000000000000000000..913e2bc27d649e0e7273d0950cada9c77d498c96 GIT binary patch literal 57712 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

4{2Bl7R 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 literal 0 HcmV?d00001 From f59fe6aca671ab33d45447996044be0a73dd605c Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 1 Apr 2020 13:39:35 +0300 Subject: [PATCH 32/42] use @ui5/webcomponents-fiori messagebundle --- packages/fiori/src/UploadCollection.js | 4 ++-- packages/fiori/src/UploadCollectionItem.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index d4b69190d1c9..348f52bb9a66 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -191,14 +191,14 @@ class UploadCollection extends UI5Element { Label.define(), List.define(), Title.define(), - fetchI18nBundle("@ui5/webcomponents"), + fetchI18nBundle("@ui5/webcomponents-fiori"), ]); } constructor() { super(); - this.i18nBundle = getI18nBundle("@ui5/webcomponents"); + this.i18nBundle = getI18nBundle("@ui5/webcomponents-fiori"); this._listeners = { dragenter: this._ondragenter.bind(this), dragleave: this._ondragleave.bind(this), diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 6ba2d1f58d28..7976615a6267 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -226,13 +226,13 @@ class UploadCollectionItem extends ListItem { Input.define(), Link.define(), Label.define(), - fetchI18nBundle("@ui5/webcomponents"), + fetchI18nBundle("@ui5/webcomponents-fiori"), ]); } constructor() { super(); - this.i18nBundle = getI18nBundle("@ui5/webcomponents"); + this.i18nBundle = getI18nBundle("@ui5/webcomponents-fiori"); } onBeforeRendering() { From 99d0c20aca42deb18c656f97cb2822a8bb774bb3 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 1 Apr 2020 14:25:54 +0300 Subject: [PATCH 33/42] subscribe UploadCollection's dnd listeners in the hbs --- packages/fiori/src/UploadCollection.hbs | 8 +- packages/fiori/src/UploadCollection.js | 76 ++++--------------- .../fiori/src/themes/UploadCollection.css | 9 +-- ...gAndDrop.js => UploadCollectionBodyDnD.js} | 0 4 files changed, 24 insertions(+), 69 deletions(-) rename packages/fiori/src/upload-utils/{BodyDragAndDrop.js => UploadCollectionBodyDnD.js} (100%) diff --git a/packages/fiori/src/UploadCollection.hbs b/packages/fiori/src/UploadCollection.hbs index 3a31a97594a9..fd0bfcda3c36 100644 --- a/packages/fiori/src/UploadCollection.hbs +++ b/packages/fiori/src/UploadCollection.hbs @@ -20,7 +20,13 @@ {{_noDataDescription}}

{{else if _showDndOverlay}} -
+
{{_dndOverlayText}}
diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index 348f52bb9a66..29739f9c8210 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -18,7 +18,7 @@ import { addUploadCollectionInstance, removeUploadCollectionInstance, draggingFiles, -} from "./upload-utils/BodyDragAndDrop.js"; +} from "./upload-utils/UploadCollectionBodyDnD.js"; import UploadCollectionDnDOverlayMode from "./types/UploadCollectionDnDMode.js"; // Template @@ -197,14 +197,7 @@ class UploadCollection extends UI5Element { constructor() { super(); - this.i18nBundle = getI18nBundle("@ui5/webcomponents-fiori"); - this._listeners = { - dragenter: this._ondragenter.bind(this), - dragleave: this._ondragleave.bind(this), - dragover: this._ondragover.bind(this), - drop: this._ondrop.bind(this), - }; } onEnterDOM() { @@ -215,87 +208,48 @@ class UploadCollection extends UI5Element { addUploadCollectionInstance(this); } - onBeforeRendering() { + onExitDOM() { if (this.noDnd) { return; } - this._removeDragAndDropListeners(); + removeUploadCollectionInstance(this); } - onAfterRendering() { + _ondragenter(event) { if (this.noDnd) { return; } - this._addDragAndDropListeners(); - } - - onExitDOM() { - if (this.noDnd) { + if (!draggingFiles(event)) { return; } - removeUploadCollectionInstance(this); - this._removeDragAndDropListeners(); - } - - _addDragAndDropListeners() { - this._root.addEventListener("dragenter", this._listeners.dragenter); - this._root.addEventListener("dragover", this._listeners.dragover); - this._root.addEventListener("dragleave", this._listeners.dragleave); - this._root.addEventListener("drop", this._listeners.drop); + this._dndOverlayMode = UploadCollectionDnDOverlayMode.Drop; } - _removeDragAndDropListeners() { - if (this._root) { - this._root.removeEventListener("dragenter", this._listeners.dragenter); - this._root.removeEventListener("dragover", this._listeners.dragover); - this._root.removeEventListener("dragleave", this._listeners.dragleave); - this._root.removeEventListener("drop", this._listeners.drop); - } - } - - _ondragenter(event) { - if (!draggingFiles(event)) { + _ondrop(event) { + if (this.noDnd) { return; } - if (event.target === this._dndOverlay) { - this._dndOverlayMode = UploadCollectionDnDOverlayMode.Drop; - } - } - - _ondrop(event) { this._dndOverlayMode = UploadCollectionDnDOverlayMode.None; } _ondragover(event) { - event.preventDefault(); - } - - _ondragleave(event) { - if (event.target === this._dndOverlay) { - this._dndOverlayMode = UploadCollectionDnDOverlayMode.Drag; + if (this.noDnd) { + return; } - } - - _ondragenterBody(event) { - this._lastDragEnter = event.target; - if (this._dndOverlayMode !== UploadCollectionDnDOverlayMode.Drop) { - this._dndOverlayMode = UploadCollectionDnDOverlayMode.Drag; - } + event.preventDefault(); } - _ondragleaveBody(event) { - if (this._lastDragEnter === event.target) { - this._dndOverlayMode = UploadCollectionDnDOverlayMode.None; + _ondragleave(event) { + if (this.noDnd) { + return; } - } - _ondropBody() { - this._dndOverlayMode = "None"; + this._dndOverlayMode = UploadCollectionDnDOverlayMode.Drag; } _onItemDelete(event) { diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css index 8c866654cefb..efb6dbd46d67 100644 --- a/packages/fiori/src/themes/UploadCollection.css +++ b/packages/fiori/src/themes/UploadCollection.css @@ -70,13 +70,7 @@ border: var(--ui5_upload_collection_drag_overlay_border); } -.uc-drop-overlay::after { - content: ""; - position: absolute; - top: 0; - right: 0rem; - left: 0rem; - bottom: 0rem; +.uc-drop-overlay { background-color: var(--ui5_upload_collection_drop_overlay_background); border: var(--ui5_upload_collection_drop_overlay_border); } @@ -98,4 +92,5 @@ .uc-drop-overlay .dnd-overlay-text { color: var(--ui5_upload_collection_drop_overlay_icon_color); z-index: 1; + pointer-events: none; } \ No newline at end of file diff --git a/packages/fiori/src/upload-utils/BodyDragAndDrop.js b/packages/fiori/src/upload-utils/UploadCollectionBodyDnD.js similarity index 100% rename from packages/fiori/src/upload-utils/BodyDragAndDrop.js rename to packages/fiori/src/upload-utils/UploadCollectionBodyDnD.js From 8b72a56c73267327089ca84d3e906575b664d830 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Wed, 1 Apr 2020 16:07:17 +0300 Subject: [PATCH 34/42] use publish-subscribe pattern for drag and drop events on the body --- packages/fiori/src/UploadCollection.js | 13 +++++-- .../upload-utils/UploadCollectionBodyDnD.js | 38 ++++++++----------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index 29739f9c8210..b774880068bb 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -15,8 +15,8 @@ import { UPLOADCOLLECTION_DROP_FILE_INDICATOR, } from "./generated/i18n/i18n-defaults.js"; import { - addUploadCollectionInstance, - removeUploadCollectionInstance, + attachBodyDnDHandler, + detachBodyDnDHandler, draggingFiles, } from "./upload-utils/UploadCollectionBodyDnD.js"; import UploadCollectionDnDOverlayMode from "./types/UploadCollectionDnDMode.js"; @@ -198,6 +198,11 @@ class UploadCollection extends UI5Element { constructor() { super(); this.i18nBundle = getI18nBundle("@ui5/webcomponents-fiori"); + this._bodyDnDHandler = event => { + if (this._dndOverlayMode !== UploadCollectionDnDOverlayMode.Drop) { + this._dndOverlayMode = event.mode; + } + }; } onEnterDOM() { @@ -205,7 +210,7 @@ class UploadCollection extends UI5Element { return; } - addUploadCollectionInstance(this); + attachBodyDnDHandler(this._bodyDnDHandler); } onExitDOM() { @@ -213,7 +218,7 @@ class UploadCollection extends UI5Element { return; } - removeUploadCollectionInstance(this); + detachBodyDnDHandler(this._bodyDnDHandler); } _ondragenter(event) { diff --git a/packages/fiori/src/upload-utils/UploadCollectionBodyDnD.js b/packages/fiori/src/upload-utils/UploadCollectionBodyDnD.js index 056752b92ed6..edc5d1901e5c 100644 --- a/packages/fiori/src/upload-utils/UploadCollectionBodyDnD.js +++ b/packages/fiori/src/upload-utils/UploadCollectionBodyDnD.js @@ -2,16 +2,18 @@ /** * Handles drag and drop event listeners on document.body. * Ensures that there is only 1 listener per type attached (drag, drop, leave). Event listeners will only be attached when - * there is at least 1 UploadCollection registered in the set. + * there is at least 1 UploadCollection subscribed. */ +import EventProvider from "@ui5/webcomponents-base/dist/EventProvider.js"; import UploadCollectionDnDOverlayMode from "../types/UploadCollectionDnDMode.js"; const draggingFiles = event => { return event.dataTransfer.types.includes("Files"); }; -const uploadCollections = new Set(); +const eventProvider = new EventProvider(); +const EVENT = "UploadCollectionBodyDndEvent"; let lastDragEnter = null; let globalHandlersAttached = false; @@ -21,25 +23,17 @@ const ondragenter = event => { } lastDragEnter = event.target; - uploadCollections.forEach(uc => { - if (uc._dndOverlayMode !== UploadCollectionDnDOverlayMode.Drop) { - uc._dndOverlayMode = UploadCollectionDnDOverlayMode.Drag; - } - }); + eventProvider.fireEvent(EVENT, { mode: UploadCollectionDnDOverlayMode.Drag }); }; const ondragleave = event => { - uploadCollections.forEach(uc => { - if (lastDragEnter === event.target) { - uc._dndOverlayMode = UploadCollectionDnDOverlayMode.None; - } - }); + if (lastDragEnter === event.target) { + eventProvider.fireEvent(EVENT, { mode: UploadCollectionDnDOverlayMode.None }); + } }; const ondrop = event => { - uploadCollections.forEach(uc => { - uc._dndOverlayMode = UploadCollectionDnDOverlayMode.None; - }); + eventProvider.fireEvent(EVENT, { mode: UploadCollectionDnDOverlayMode.None }); }; const attachGlobalHandlers = () => { @@ -55,8 +49,8 @@ const detachGlobalHandlers = () => { globalHandlersAttached = false; }; -const addUploadCollectionInstance = uploadCollection => { - uploadCollections.add(uploadCollection); +const attachBodyDnDHandler = handler => { + eventProvider.attachEvent(EVENT, handler); if (!globalHandlersAttached) { attachGlobalHandlers(); @@ -64,16 +58,16 @@ const addUploadCollectionInstance = uploadCollection => { } }; -const removeUploadCollectionInstance = uploadCollection => { - uploadCollections.delete(uploadCollection); +const detachBodyDnDHandler = handler => { + eventProvider.detachEvent(EVENT, handler); - if (uploadCollections.size === 0) { + if (!eventProvider.hasListeners(EVENT)) { detachGlobalHandlers(); } }; export { - addUploadCollectionInstance, - removeUploadCollectionInstance, + attachBodyDnDHandler, + detachBodyDnDHandler, draggingFiles, }; From 0cccd7557f11db43e9a2b9f434cc75b54920fca9 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Thu, 2 Apr 2020 16:25:16 +0300 Subject: [PATCH 35/42] adopt global css vars --- .../fiori/src/themes/UploadCollection.css | 39 ++++++++++++++++--- .../fiori/src/themes/UploadCollectionItem.css | 2 + .../base/UploadCollection-parameters.css | 7 ++-- .../UploadCollection-parameters.css | 3 +- .../UploadCollection-parameters.css | 3 +- 5 files changed, 42 insertions(+), 12 deletions(-) diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css index efb6dbd46d67..384f8077d454 100644 --- a/packages/fiori/src/themes/UploadCollection.css +++ b/packages/fiori/src/themes/UploadCollection.css @@ -37,7 +37,8 @@ font-size: 6rem; width: 6rem; height: 6rem; - color: var(--sapUploadCollection_NoFilesIconColor); + color: var(--sapContent_NonInteractiveIconColor); + opacity: 0.5; } .uc-no-files ui5-title { @@ -66,15 +67,37 @@ } .uc-drag-overlay { - background-color: var(--ui5_upload_collection_drag_overlay_background); border: var(--ui5_upload_collection_drag_overlay_border); } +/* use pseudo element to set opacity only for the content and not on the border */ +.uc-drag-overlay::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: var(--sapGroup_ContentBackground); + opacity: 0.8; +} + .uc-drop-overlay { - background-color: var(--ui5_upload_collection_drop_overlay_background); border: var(--ui5_upload_collection_drop_overlay_border); } +/* use pseudo element to set opacity only for the content and not on the border */ +.uc-drop-overlay::after { + content: ""; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: var(--ui5_upload_collection_drop_overlay_background); + opacity: var(--ui5_upload_collection_drop_overlay_background_opacity); +} + .uc-dnd-overlay ui5-icon { width: 4rem; height: 4rem; @@ -88,9 +111,13 @@ color: var(--sapContent_NonInteractiveIconColor); } -.uc-drop-overlay ui5-icon, -.uc-drop-overlay .dnd-overlay-text { - color: var(--ui5_upload_collection_drop_overlay_icon_color); +.uc-dnd-overlay ui5-icon, +.uc-dnd-overlay .dnd-overlay-text { z-index: 1; pointer-events: none; +} + +.uc-drop-overlay ui5-icon, +.uc-drop-overlay .dnd-overlay-text { + color: var(--sapContent_DragAndDropActiveColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/UploadCollectionItem.css b/packages/fiori/src/themes/UploadCollectionItem.css index b6e02948beca..30609fa00fdc 100644 --- a/packages/fiori/src/themes/UploadCollectionItem.css +++ b/packages/fiori/src/themes/UploadCollectionItem.css @@ -52,7 +52,9 @@ .ui5-uci-file-name { display: block; + font-family: var(--sapFontFamily); font-size: var(--sapFontLargeSize); + color: var(--sapTextColor); margin-bottom: 0.25rem; white-space: pre-wrap; } diff --git a/packages/fiori/src/themes/base/UploadCollection-parameters.css b/packages/fiori/src/themes/base/UploadCollection-parameters.css index d7603a2ebe60..3e3a2d778cee 100644 --- a/packages/fiori/src/themes/base/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/base/UploadCollection-parameters.css @@ -1,11 +1,10 @@ :root { --ui5_upload_collection_level_2Size: 1.375rem; --ui5_upload_collection_level_5Size: 1rem; - --ui5_upload_collection_drag_overlay_background: var(--sapUploadCollection_DragOverlayBackground); --ui5_upload_collection_drag_overlay_border: 0.125rem dashed var(--sapContent_ForegroundBorderColor); - --ui5_upload_collection_drop_overlay_background: var(--sapUploadCollection_DropOverlayBackground); - --ui5_upload_collection_drop_overlay_border: 0.125rem solid var(--sapActiveColor); - --ui5_upload_collection_drop_overlay_icon_color: var(--sapActiveColor); + --ui5_upload_collection_drop_overlay_border: 0.125rem solid var(--sapContent_DragAndDropActiveColor); + --ui5_upload_collection_drop_overlay_background: var(--sapContent_DragAndDropActiveColor); + --ui5_upload_collection_drop_overlay_background_opacity: 0.05; --ui5_upload_collection_progress_indicator_background: var(--sapInformativeElementColor); --ui5_upload_collection_progress_indicator_error_background: var(--sapNegativeElementColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css index 77e92274d1af..a95c7c39ff72 100644 --- a/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css @@ -3,7 +3,8 @@ :root { --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapContent_HelpColor); - --ui5_upload_collection_drop_overlay_icon_color: var(--sapContent_HelpColor); + --ui5_upload_collection_drop_overlay_background: var(--sapGroup_ContentBackground); + --ui5_upload_collection_drop_overlay_background_opacity: 0.8; --ui5_upload_collection_progress_indicator_background: var(--sapHighlightColor); --ui5_upload_collection_progress_indicator_error_background: var(--sapHighlightColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css index 77e92274d1af..a95c7c39ff72 100644 --- a/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css @@ -3,7 +3,8 @@ :root { --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapContent_HelpColor); - --ui5_upload_collection_drop_overlay_icon_color: var(--sapContent_HelpColor); + --ui5_upload_collection_drop_overlay_background: var(--sapGroup_ContentBackground); + --ui5_upload_collection_drop_overlay_background_opacity: 0.8; --ui5_upload_collection_progress_indicator_background: var(--sapHighlightColor); --ui5_upload_collection_progress_indicator_error_background: var(--sapHighlightColor); } \ No newline at end of file From a1f709932bb1e306d33ae851a27b2b186e32a5bd Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Thu, 2 Apr 2020 17:50:24 +0300 Subject: [PATCH 36/42] set correct opacities --- packages/fiori/src/themes/UploadCollection.css | 12 ++++++------ .../src/themes/base/UploadCollection-parameters.css | 3 +-- .../sap_belize_hcb/UploadCollection-parameters.css | 3 +-- .../sap_belize_hcw/UploadCollection-parameters.css | 2 -- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css index 384f8077d454..d20f3ba3b02b 100644 --- a/packages/fiori/src/themes/UploadCollection.css +++ b/packages/fiori/src/themes/UploadCollection.css @@ -70,8 +70,12 @@ border: var(--ui5_upload_collection_drag_overlay_border); } +.uc-drop-overlay { + border: var(--ui5_upload_collection_drop_overlay_border); +} + /* use pseudo element to set opacity only for the content and not on the border */ -.uc-drag-overlay::after { +.uc-dnd-overlay::before { content: ""; position: absolute; top: 0; @@ -82,10 +86,6 @@ opacity: 0.8; } -.uc-drop-overlay { - border: var(--ui5_upload_collection_drop_overlay_border); -} - /* use pseudo element to set opacity only for the content and not on the border */ .uc-drop-overlay::after { content: ""; @@ -95,7 +95,7 @@ left: 0; right: 0; background-color: var(--ui5_upload_collection_drop_overlay_background); - opacity: var(--ui5_upload_collection_drop_overlay_background_opacity); + opacity: 0.05; } .uc-dnd-overlay ui5-icon { diff --git a/packages/fiori/src/themes/base/UploadCollection-parameters.css b/packages/fiori/src/themes/base/UploadCollection-parameters.css index 3e3a2d778cee..b6bc8657d551 100644 --- a/packages/fiori/src/themes/base/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/base/UploadCollection-parameters.css @@ -3,8 +3,7 @@ --ui5_upload_collection_level_5Size: 1rem; --ui5_upload_collection_drag_overlay_border: 0.125rem dashed var(--sapContent_ForegroundBorderColor); --ui5_upload_collection_drop_overlay_border: 0.125rem solid var(--sapContent_DragAndDropActiveColor); - --ui5_upload_collection_drop_overlay_background: var(--sapContent_DragAndDropActiveColor); - --ui5_upload_collection_drop_overlay_background_opacity: 0.05; + --ui5_upload_collection_drop_overlay_background: transparent; --ui5_upload_collection_progress_indicator_background: var(--sapInformativeElementColor); --ui5_upload_collection_progress_indicator_error_background: var(--sapNegativeElementColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css index a95c7c39ff72..a8a841cacc59 100644 --- a/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/sap_belize_hcb/UploadCollection-parameters.css @@ -3,8 +3,7 @@ :root { --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapContent_HelpColor); - --ui5_upload_collection_drop_overlay_background: var(--sapGroup_ContentBackground); - --ui5_upload_collection_drop_overlay_background_opacity: 0.8; + --ui5_upload_collection_drop_overlay_background: transparent; --ui5_upload_collection_progress_indicator_background: var(--sapHighlightColor); --ui5_upload_collection_progress_indicator_error_background: var(--sapHighlightColor); } \ No newline at end of file diff --git a/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css index a95c7c39ff72..f34277975a57 100644 --- a/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css +++ b/packages/fiori/src/themes/sap_belize_hcw/UploadCollection-parameters.css @@ -3,8 +3,6 @@ :root { --ui5_upload_collection_drag_overlay_border: 0.1875rem dashed var(--sapContent_ForegroundBorderColor); --ui5_upload_collection_drop_overlay_border: 0.1875rem solid var(--sapContent_HelpColor); - --ui5_upload_collection_drop_overlay_background: var(--sapGroup_ContentBackground); - --ui5_upload_collection_drop_overlay_background_opacity: 0.8; --ui5_upload_collection_progress_indicator_background: var(--sapHighlightColor); --ui5_upload_collection_progress_indicator_error_background: var(--sapHighlightColor); } \ No newline at end of file From e6edcdff3ca942289d0af36f1a2ec8fe04294a38 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 3 Apr 2020 10:52:19 +0300 Subject: [PATCH 37/42] add missing jsdoc tags - defaultvalue, type, public --- packages/fiori/src/UploadCollection.js | 8 +++++- packages/fiori/src/UploadCollectionItem.js | 26 ++++++++++++++++--- .../src/types/UploadCollectionDnDMode.js | 26 ++++++++++++++++--- packages/fiori/src/types/UploadState.js | 10 +++++++ 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index b774880068bb..242e7c8e2396 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -39,7 +39,7 @@ const metadata = { * Note: Available options are None, SingleSelect, * MultiSelect, and Delete. * - * @type {string} + * @type {ListMode} * @defaultvalue "None" * @public */ @@ -52,6 +52,7 @@ const metadata = { * Allows you to set your own text for the 'No data' description. * * @type {string} + * @defaultvalue "" * @public */ noDataDescription: { @@ -62,6 +63,7 @@ const metadata = { * Allows you to set your own text for the 'No data' text. * * @type {string} + * @defaultvalue "" * @public */ noDataText: { @@ -76,6 +78,7 @@ const metadata = { * ui5-upload-collection only shows an overlay. * * @type {boolean} + * @defaultvalue false * @public */ noDnd: { @@ -85,6 +88,8 @@ const metadata = { /** * Indicates what overlay to show when files are being dragged. * + * @type {UploadCollectionDnDOverlayMode} + * @defaultvalue "None" * @private */ _dndOverlayMode: { @@ -167,6 +172,7 @@ const metadata = { * @tagname ui5-upload-collection * @appenddocs UploadCollectionItem * @public + * @since 1.0.0-rc.7 */ class UploadCollection extends UI5Element { static get metadata() { diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 7976615a6267..56412d1c5a78 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -1,7 +1,6 @@ import litRender from "@ui5/webcomponents-base/dist/renderer/LitRenderer.js"; import { fetchI18nBundle, getI18nBundle } from "@ui5/webcomponents-base/dist/i18nBundle.js"; import Button from "@ui5/webcomponents/dist/Button.js"; -import Icon from "@ui5/webcomponents/dist/Icon.js"; import Input from "@ui5/webcomponents/dist/Input.js"; import Label from "@ui5/webcomponents/dist/Label.js"; import Link from "@ui5/webcomponents/dist/Link.js"; @@ -48,6 +47,7 @@ const metadata = { * The name of the file. * * @type {string} + * @defaultvalue "" * @public */ fileName: { @@ -58,6 +58,7 @@ const metadata = { * If set to true the file name will be clickable and it will fire fileNameClick event upon click. * * @type {boolean} + * @defaultvalue false * @public */ fileNameClickable: { @@ -68,16 +69,31 @@ const metadata = { * Removes delete option from ui5-upload-collection with mode Delete for this item. * * @type {boolean} + * @defaultvalue false * @public */ noDelete: { type: Boolean, }, + /** + * Hides the retry button when uploadState property is Error. + * + * @type {boolean} + * @defaultvalue false + * @public + */ noRetry: { type: Boolean, }, + /** + * Hides the terminate button when uploadState property is Uploading. + * + * @type {boolean} + * @defaultvalue false + * @public + */ noTerminate: { type: Boolean, }, @@ -98,8 +114,10 @@ const metadata = { /** * If set to Uploading or Error, a progress indicator showing the progress is displayed. + * Also if set to Error, a refresh button is shown. When this icon is pressed retry event is fired. + * If set to Uploading, a terminate button is shown. When this icon is pressed terminate event is fired. * - * @type {string} + * @type {UploadState} * @defaultvalue "Ready" * @public */ @@ -111,6 +129,8 @@ const metadata = { /** * Indicates if editing. * + * @type {boolean} + * @defaultvalue false * @private */ _editing: { @@ -201,6 +221,7 @@ const metadata = { * @extends UI5Element * @tagname ui5-upload-collection-item * @public + * @since 1.0.0-rc.7 */ class UploadCollectionItem extends ListItem { static get metadata() { @@ -222,7 +243,6 @@ class UploadCollectionItem extends ListItem { static async onDefine() { await Promise.all([ Button.define(), - Icon.define(), Input.define(), Link.define(), Label.define(), diff --git a/packages/fiori/src/types/UploadCollectionDnDMode.js b/packages/fiori/src/types/UploadCollectionDnDMode.js index 471010276222..669492fe4db1 100644 --- a/packages/fiori/src/types/UploadCollectionDnDMode.js +++ b/packages/fiori/src/types/UploadCollectionDnDMode.js @@ -2,11 +2,30 @@ import DataType from "@ui5/webcomponents-base/dist/types/DataType.js"; /** * Different drag and drop overlay modes of UploadCollection. + * + * @lends sap.ui.webcomponents.fiori.types.UploadCollectionDnDOverlayMode.prototype * @private */ -const DndOverlayMode = { +const DndOverlayModes = { + /** + * No drag or drop indication. + * @private + * @type {None} + */ None: "None", + + /** + * Indication that drag can be performed. + * @private + * @type {Drag} + */ Drag: "Drag", + + /** + * Indication that drop can be performed. + * @private + * @type {Drop} + */ Drop: "Drop", }; @@ -15,15 +34,16 @@ const DndOverlayMode = { * Different types of drag and drop overlay modes. * @constructor * @author SAP SE + * @alias sap.ui.webcomponents.fiori.types.UploadCollectionDnDOverlayMode * @private * @enum {string} */ class UploadCollectionDnDOverlayMode extends DataType { static isValid(value) { - return !!DndOverlayMode[value]; + return !!DndOverlayModes[value]; } } -UploadCollectionDnDOverlayMode.generataTypeAcessors(DndOverlayMode); +UploadCollectionDnDOverlayMode.generataTypeAcessors(DndOverlayModes); export default UploadCollectionDnDOverlayMode; diff --git a/packages/fiori/src/types/UploadState.js b/packages/fiori/src/types/UploadState.js index 33bb4c8eef6a..3cd0220779f1 100644 --- a/packages/fiori/src/types/UploadState.js +++ b/packages/fiori/src/types/UploadState.js @@ -1,27 +1,36 @@ import DataType from "@ui5/webcomponents-base/dist/types/DataType.js"; +/** + * Different types of AvatarShape. + * @lends sap.ui.webcomponents.fiori.types.UploadState.prototype + * @public + */ const UploadStates = { /** * The file has been uploaded successfully. * @public + * @type {Complete} */ Complete: "Complete", /** * The file cannot be uploaded due to an error. * @public + * @type {Error} */ Error: "Error", /** * The file is awaiting an explicit command to start being uploaded. * @public + * @type {Ready} */ Ready: "Ready", /** * The file is currently being uploaded. * @public + * @type {Uploading} */ Uploading: "Uploading", }; @@ -32,6 +41,7 @@ const UploadStates = { * @class * @constructor * @author SAP SE + * @alias sap.ui.webcomponents.fiori.types.UploadState * @public * @enum {string} */ From db596a85d2c83b34c842e073adb046d386f68ec8 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 3 Apr 2020 11:25:52 +0300 Subject: [PATCH 38/42] consider hidden attribute --- packages/fiori/src/themes/UploadCollection.css | 2 +- packages/fiori/test/pages/Components.html | 3 ++- packages/fiori/test/specs/Components.spec.js | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/fiori/src/themes/UploadCollection.css b/packages/fiori/src/themes/UploadCollection.css index d20f3ba3b02b..025b4f63d9fa 100644 --- a/packages/fiori/src/themes/UploadCollection.css +++ b/packages/fiori/src/themes/UploadCollection.css @@ -1,4 +1,4 @@ -:host { +:host(:not([hidden])) { display: block; } diff --git a/packages/fiori/test/pages/Components.html b/packages/fiori/test/pages/Components.html index 1bc8d9db87f8..6e6c19bec58b 100644 --- a/packages/fiori/test/pages/Components.html +++ b/packages/fiori/test/pages/Components.html @@ -21,7 +21,8 @@ - + + diff --git a/packages/fiori/test/specs/Components.spec.js b/packages/fiori/test/specs/Components.spec.js index be19635024b8..c5675c371ba4 100644 --- a/packages/fiori/test/specs/Components.spec.js +++ b/packages/fiori/test/specs/Components.spec.js @@ -13,7 +13,8 @@ describe("General assertions", () => { it("tests components with 'hidden' property are not visible", () => { [ - browser.$("#shellbar2") + browser.$("#shellbar2"), + browser.$("#uploadCollection") ].forEach(assertHidden); }); }); From 2eb644a254e9cd428834d51ec1bd594a3ae4c291 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 3 Apr 2020 13:07:19 +0300 Subject: [PATCH 39/42] introduce base/util/getFileExtension and consider hidden files --- packages/base/src/util/getFileExtension.js | 21 +++++++++++++++++++ packages/fiori/src/UploadCollectionItem.js | 15 ++++++++----- .../fiori/test/pages/UploadCollection.html | 4 ++-- .../fiori/test/specs/UploadCollection.spec.js | 10 +++++++++ 4 files changed, 43 insertions(+), 7 deletions(-) create mode 100644 packages/base/src/util/getFileExtension.js diff --git a/packages/base/src/util/getFileExtension.js b/packages/base/src/util/getFileExtension.js new file mode 100644 index 000000000000..955d24cd9fcc --- /dev/null +++ b/packages/base/src/util/getFileExtension.js @@ -0,0 +1,21 @@ +/** + * "" -> "" + * "noExtension" -> "" + * "file.txt" -> ".txt" + * "file.with.many.dots.doc" -> ".doc" + * ".gitignore" -> "" + * + * @param fileName - the file name + * @returns {string} + */ +const getFileExtension = fileName => { + const dotPos = fileName.lastIndexOf("."); + + if (dotPos < 1) { + return ""; + } + + return fileName.slice(dotPos); +}; + +export default getFileExtension; diff --git a/packages/fiori/src/UploadCollectionItem.js b/packages/fiori/src/UploadCollectionItem.js index 56412d1c5a78..92871413ba6b 100644 --- a/packages/fiori/src/UploadCollectionItem.js +++ b/packages/fiori/src/UploadCollectionItem.js @@ -6,6 +6,7 @@ import Label from "@ui5/webcomponents/dist/Label.js"; import Link from "@ui5/webcomponents/dist/Link.js"; import ListItem from "@ui5/webcomponents/dist/ListItem.js"; import Integer from "@ui5/webcomponents-base/dist/types/Integer.js"; +import getFileExtension from "@ui5/webcomponents-base/dist/util/getFileExtension.js"; import UploadState from "./types/UploadState.js"; import "@ui5/webcomponents-icons/dist/icons/refresh.js"; import "@ui5/webcomponents-icons/dist/icons/stop.js"; @@ -355,7 +356,7 @@ class UploadCollectionItem extends ListItem { } get _fileExtension() { - return this.fileName.includes(".") ? `.${this.fileName.split(".").pop()}` : ""; + return getFileExtension(this.fileName); } get _renameBtnText() { @@ -371,11 +372,15 @@ class UploadCollectionItem extends ListItem { } get _progressText() { - switch (this.uploadState) { - case UploadState.Error: return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_ERROR_STATE); - case UploadState.Uploading: return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_UPLOADING_STATE); - default: return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_READY_STATE); + if (this.uploadState === UploadState.Uploading) { + return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_UPLOADING_STATE); } + + if (this.uploadState === UploadState.Error) { + return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_ERROR_STATE); + } + + return this.i18nBundle.getText(UPLOADCOLLECTIONITEM_READY_STATE); } get _showRetry() { diff --git a/packages/fiori/test/pages/UploadCollection.html b/packages/fiori/test/pages/UploadCollection.html index 3521e8cc7cd3..d4a387791330 100644 --- a/packages/fiori/test/pages/UploadCollection.html +++ b/packages/fiori/test/pages/UploadCollection.html @@ -76,12 +76,12 @@ - + You cannot delete this file. { assert.strictEqual(noFileExtensionItem.getProperty("fileName"), newFileName2 + ".newExtension", "the string after the last dot is considered as extension"); }); + + it("should NOT consider hidden file name as extension", () => { + const secondItem = browser.$("#secondItem"); + const editButton = secondItem.shadow$(".ui5-li-detailbtn"); + + editButton.click(); + + assert.notOk(secondItem.shadow$(".ui5-uci-file-extension").getText(), "no extension is calculated for .gitignore."); + + }); }); describe("Drag and Drop", () => { From 43d2dfc95d9522b4e2461bda1ba20e9c9545a18f Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 3 Apr 2020 15:56:28 +0300 Subject: [PATCH 40/42] fix jsdoc typos and add new badge --- packages/fiori/src/UploadCollection.js | 4 ++-- packages/fiori/src/types/UploadState.js | 2 +- packages/playground/build-scripts/samples-prepare.js | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/fiori/src/UploadCollection.js b/packages/fiori/src/UploadCollection.js index 242e7c8e2396..9659f0712267 100644 --- a/packages/fiori/src/UploadCollection.js +++ b/packages/fiori/src/UploadCollection.js @@ -63,7 +63,7 @@ const metadata = { * Allows you to set your own text for the 'No data' text. * * @type {string} - * @defaultvalue "" + * @defaultvalue "" * @public */ noDataText: { @@ -78,7 +78,7 @@ const metadata = { * ui5-upload-collection only shows an overlay. * * @type {boolean} - * @defaultvalue false + * @defaultvalue false * @public */ noDnd: { diff --git a/packages/fiori/src/types/UploadState.js b/packages/fiori/src/types/UploadState.js index 3cd0220779f1..d8b086235701 100644 --- a/packages/fiori/src/types/UploadState.js +++ b/packages/fiori/src/types/UploadState.js @@ -1,7 +1,7 @@ import DataType from "@ui5/webcomponents-base/dist/types/DataType.js"; /** - * Different types of AvatarShape. + * Different types of UploadState. * @lends sap.ui.webcomponents.fiori.types.UploadState.prototype * @public */ diff --git a/packages/playground/build-scripts/samples-prepare.js b/packages/playground/build-scripts/samples-prepare.js index 71a07cc0754f..d082c1b35ffc 100644 --- a/packages/playground/build-scripts/samples-prepare.js +++ b/packages/playground/build-scripts/samples-prepare.js @@ -20,6 +20,7 @@ const newComponents = [ "SegmentedButton", "TimePicker", "Toast", + "UploadCollection" ]; packages.forEach(package => { From ef5cd45047fb38513612659b90a30a46a6dbdc57 Mon Sep 17 00:00:00 2001 From: Petar Dimov Date: Fri, 3 Apr 2020 16:45:06 +0300 Subject: [PATCH 41/42] simplify playground sample --- .../test/samples/UploadCollection.sample.html | 190 +++--------------- 1 file changed, 33 insertions(+), 157 deletions(-) diff --git a/packages/fiori/test/samples/UploadCollection.sample.html b/packages/fiori/test/samples/UploadCollection.sample.html index a9939ca217cd..e2337a0990ff 100644 --- a/packages/fiori/test/samples/UploadCollection.sample.html +++ b/packages/fiori/test/samples/UploadCollection.sample.html @@ -57,34 +57,15 @@

UploadCollection


-<style>
-	.header {
-		display: flex;
-		align-items: center;
-		overflow: hidden;
-	}
-
-	.spacer {
-		flex: 1 1 auto;
-	}
-
-	.header > * {
-		margin: 4px;
-	}
-</style>
-
 <ui5-upload-collection id="uploadCollection">
 	<div slot="header" class="header">
 		<ui5-title>Uploaded (2)</ui5-title>
@@ -165,34 +131,15 @@ <h3>UploadCollection</h3>
 </ui5-upload-collection>	
 
 <script>
-	function fileExtensionToIconName(fileName) {
-		var extension = fileName.split(".").pop();
-
-		switch (extension) {
-			case "bmp":
-			case "jpg":
-			case "jpeg":
-			case "png":
-				return "card";
-			case "docx":
-			case "pdf":
-				return "pdf-attachment";
-			case "txt":
-				return "document-text";
-			default:
-				return "document";
-		}
-	}
-
 	function createThumbnail(fileName) {
-		var icon = document.createElement("ui5-icon");
-		icon.name = fileExtensionToIconName(fileName);
+		const icon = document.createElement("ui5-icon");
+		icon.name = "document";
 		icon.slot = "thumbnail";
 		return icon;
 	}
 
 	function createUCI(file) {
-		var uci = document.createElement("ui5-upload-collection-item");
+		const uci = document.createElement("ui5-upload-collection-item");
 			description = document.createTextNode("Last modified: " + file.lastModifiedDate + ", size: " + file.size);
 
 		uci.appendChild(createThumbnail(file.name));
@@ -202,18 +149,19 @@ <h3>UploadCollection</h3>
 		return uci;
 	}
 
-	fileUploader.addEventListener("ui5-change", function(event) {
-		var files = event.detail.files;
+	fileUploader.addEventListener("ui5-change", event => {
+		const files = event.detail.files;
 
 		for (var i = 0; i < files.length; i++) {
 			uploadCollection.appendChild(createUCI(files[i]));
 		}
 	});
 
-	startUploading.addEventListener("click", function(event) {
-		uploadCollection.items.forEach(function (item) {
+	startUploading.addEventListener("click", event => {
+		uploadCollection.items.forEach(item => {
+			// if there is a file ready to be uploaded send request
 			if (item.uploadState === "Ready" && item.file) {
-				var oXHR = new XMLHttpRequest();
+				const oXHR = new XMLHttpRequest();
 				
 				oXHR.open("POST", "/upload", true);
 				oXHR.onreadystatechange  = function () {
@@ -258,7 +206,7 @@ <h3>UploadCollection With File Renaming Enabled</h3>
 		</ui5-upload-collection>	
 
 		<script>
-			uploadCollectionWithRenaming.addEventListener("ui5-rename", function (event) {
+			uploadCollectionWithRenaming.addEventListener("ui5-rename", event => {
 				alert("Rename event:" + event.target.fileName)
 			});
 		</script>
@@ -289,7 +237,7 @@ <h3>UploadCollection With File Renaming Enabled</h3>
 </ui5-upload-collection>	
 
 <script>
-	uploadCollectionWithRenaming.addEventListener("ui5-rename", function (event) {
+	uploadCollectionWithRenaming.addEventListener("ui5-rename", event => {
 		alert("Rename event:" + event.target.fileName)
 	});
 </script>
@@ -336,11 +284,11 @@ <h3>UploadCollection With Different Uploading States of Items</h3>
 		</ui5-upload-collection>
 
 		<script>
-			uploadCollectionStates.addEventListener("ui5-retry", function (event) {
+			uploadCollectionStates.addEventListener("ui5-retry", event => {
 				alert("Retry uploading: " + event.target.fileName);
 			});
 		
-			uploadCollectionStates.addEventListener("ui5-terminate", function (event) {
+			uploadCollectionStates.addEventListener("ui5-terminate", event => {
 				alert("Terminate uploading of: " + event.target.fileName);
 			});
 		</script>
@@ -383,11 +331,11 @@ <h3>UploadCollection With Different Uploading States of Items</h3>
 </ui5-upload-collection>
 
 <script>
-	uploadCollectionStates.addEventListener("ui5-retry", function (event) {
+	uploadCollectionStates.addEventListener("ui5-retry", event => {
 		alert("Retry uploading: " + event.target.fileName);
 	});
 
-	uploadCollectionStates.addEventListener("ui5-terminate", function (event) {
+	uploadCollectionStates.addEventListener("ui5-terminate", event => {
 		alert("Terminate uploading of: " + event.target.fileName);
 	});
 </script>
@@ -405,49 +353,13 @@ <h3>UploadCollection With Drag and Drop and No Initial Data</h3>
 		</ui5-upload-collection>
 
 		<script>
-			function fileExtensionToIconName(fileName) {
-				var extension = fileName.split(".").pop();
-
-				switch (extension) {
-					case "bmp":
-					case "jpg":
-					case "jpeg":
-					case "png":
-						return "card";
-					case "docx":
-					case "pdf":
-						return "pdf-attachment";
-					case "txt":
-						return "document-text";
-					default:
-						return "document";
-				}
-			}
-
-			function createThumbnail(fileName) {
-				var icon = document.createElement("ui5-icon");
-				icon.name = fileExtensionToIconName(fileName);
-				icon.slot = "thumbnail";
-				return icon;
-			}
-
-			function createUCI(file) {
-				var uci = document.createElement("ui5-upload-collection-item");
-					description = document.createTextNode("Last modified: " + file.lastModifiedDate + ", size: " + file.size);
-
-				uci.appendChild(createThumbnail(file.name));
-				uci.appendChild(description);
-				uci.file = file;
-				uci.fileName = file.name;
-				return uci;
-			}
-
-			uploadCollectionDnD.addEventListener("drop", function(event) {
+			uploadCollectionDnD.addEventListener("drop", event => {
 				event.preventDefault();
 
-				var files = event.dataTransfer.files;
+				const files = event.dataTransfer.files;
 
-				for (var i = 0; i < files.length; i++) {
+				// Take the files from the drop event and create <ui5-upload-collection-item> from them
+				for (let i = 0; i < files.length; i++) {
 					uci = createUCI(files[i]);
 					uploadCollectionDnD.appendChild(uci)
 				}
@@ -463,49 +375,13 @@ <h3>UploadCollection With Drag and Drop and No Initial Data</h3>
 </ui5-upload-collection>
 
 <script>
-	function fileExtensionToIconName(fileName) {
-		var extension = fileName.split(".").pop();
-
-		switch (extension) {
-			case "bmp":
-			case "jpg":
-			case "jpeg":
-			case "png":
-				return "card";
-			case "docx":
-			case "pdf":
-				return "pdf-attachment";
-			case "txt":
-				return "document-text";
-			default:
-				return "document";
-		}
-	}
-
-	function createThumbnail(fileName) {
-		var icon = document.createElement("ui5-icon");
-		icon.name = fileExtensionToIconName(fileName);
-		icon.slot = "thumbnail";
-		return icon;
-	}
-
-	function createUCI(file) {
-		var uci = document.createElement("ui5-upload-collection-item");
-			description = document.createTextNode("Last modified: " + file.lastModifiedDate + ", size: " + file.size);
-
-		uci.appendChild(createThumbnail(file.name));
-		uci.appendChild(description);
-		uci.file = file;
-		uci.fileName = file.name;
-		return uci;
-	}
-
-	uploadCollectionDnD.addEventListener("drop", function(event) {
+	uploadCollectionDnD.addEventListener("drop", event => {
 		event.preventDefault();
 
-		var files = event.dataTransfer.files;
+		const files = event.dataTransfer.files;
 
-		for (var i = 0; i < files.length; i++) {
+		// Take the files from the drop event and create <ui5-upload-collection-item> from them
+		for (let i = 0; i < files.length; i++) {
 			uci = createUCI(files[i]);
 			uploadCollectionDnD.appendChild(uci)
 		}

From a1d29185e3ebed4c339ea72e91689caf13b3c06d Mon Sep 17 00:00:00 2001
From: Petar Dimov <petar.dimov@sap.com>
Date: Fri, 3 Apr 2020 17:09:27 +0300
Subject: [PATCH 42/42] remove es6 from snippets in the playground

---
 .../test/samples/UploadCollection.sample.html | 38 +++++++++----------
 1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/packages/fiori/test/samples/UploadCollection.sample.html b/packages/fiori/test/samples/UploadCollection.sample.html
index e2337a0990ff..532a1b8f2033 100644
--- a/packages/fiori/test/samples/UploadCollection.sample.html
+++ b/packages/fiori/test/samples/UploadCollection.sample.html
@@ -54,18 +54,18 @@ <h3>UploadCollection</h3>
 				<ui5-icon name="document-text" slot="thumbnail"></ui5-icon>
 				Uploaded By: John Smith · Uploaded On: 2014-09-02 · File Size: 226.6 KB ·
 			</ui5-upload-collection-item>
-		</ui5-upload-collection>	
+		</ui5-upload-collection>
 
 		<script>
 			function createThumbnail(fileName) {
-				const icon = document.createElement("ui5-icon");
+				var icon = document.createElement("ui5-icon");
 				icon.name = "document";
 				icon.slot = "thumbnail";
 				return icon;
 			}
 
 			function createUCI(file) {
-				const uci = document.createElement("ui5-upload-collection-item");
+				var uci = document.createElement("ui5-upload-collection-item");
 					description = document.createTextNode("Last modified: " + file.lastModifiedDate + ", size: " + file.size);
 
 				uci.appendChild(createThumbnail(file.name));
@@ -75,19 +75,19 @@ <h3>UploadCollection</h3>
 				return uci;
 			}
 
-			fileUploader.addEventListener("ui5-change", event => {
-				const files = event.detail.files;
+			fileUploader.addEventListener("ui5-change", function(event) {
+				var files = event.detail.files;
 
 				for (var i = 0; i < files.length; i++) {
 					uploadCollection.appendChild(createUCI(files[i]));
 				}
 			});
 
-			startUploading.addEventListener("click", event => {
-				uploadCollection.items.forEach(item => {
+			startUploading.addEventListener("click", function(event) {
+				uploadCollection.items.forEach(function(item) {
 					// if there is a file ready to be uploaded send request
 					if (item.uploadState === "Ready" && item.file) {
-						const oXHR = new XMLHttpRequest();
+						var oXHR = new XMLHttpRequest();
 						
 						oXHR.open("POST", "/upload", true);
 						oXHR.onreadystatechange = function () {
@@ -131,14 +131,14 @@ <h3>UploadCollection</h3>
 </ui5-upload-collection>	
 
 <script>
-	function createThumbnail(fileName) {
+	const createThumbnail = fileName => {
 		const icon = document.createElement("ui5-icon");
 		icon.name = "document";
 		icon.slot = "thumbnail";
 		return icon;
-	}
+	};
 
-	function createUCI(file) {
+	const createUCI  = file => {
 		const uci = document.createElement("ui5-upload-collection-item");
 			description = document.createTextNode("Last modified: " + file.lastModifiedDate + ", size: " + file.size);
 
@@ -152,7 +152,7 @@ <h3>UploadCollection</h3>
 	fileUploader.addEventListener("ui5-change", event => {
 		const files = event.detail.files;
 
-		for (var i = 0; i < files.length; i++) {
+		for (let i = 0; i < files.length; i++) {
 			uploadCollection.appendChild(createUCI(files[i]));
 		}
 	});
@@ -206,7 +206,7 @@ <h3>UploadCollection With File Renaming Enabled</h3>
 		</ui5-upload-collection>	
 
 		<script>
-			uploadCollectionWithRenaming.addEventListener("ui5-rename", event => {
+			uploadCollectionWithRenaming.addEventListener("ui5-rename", function(event) {
 				alert("Rename event:" + event.target.fileName)
 			});
 		</script>
@@ -238,7 +238,7 @@ <h3>UploadCollection With File Renaming Enabled</h3>
 
 <script>
 	uploadCollectionWithRenaming.addEventListener("ui5-rename", event => {
-		alert("Rename event:" + event.target.fileName)
+		alert("Rename event:" + event.target.fileName);
 	});
 </script>
 	
@@ -284,11 +284,11 @@

UploadCollection With Different Uploading States of Items

@@ -353,13 +353,13 @@

UploadCollection With Drag and Drop and No Initial Data