UNPKG

@progress/kendo-ui

Version:

This package is part of the [Kendo UI for jQuery](http://www.telerik.com/kendo-ui) suite.

1,341 lines 75 kB
//#region ../src/kendo.upload.js const __meta__ = { id: "upload", name: "Upload", category: "web", description: "The Upload widget uses progressive enhancement to deliver the best possible uploading experience to users.", depends: [ "core", "progressbar", "icons", "html.button" ] }; (function($, undefined) { var kendo = window.kendo, Widget = kendo.ui.Widget, antiForgeryTokens = kendo.antiForgeryTokens, logToConsole = kendo.logToConsole, rFileExtension = /\.([^\.]+)$/, NS = ".kendoUpload", SELECT = "select", UPLOAD = "upload", SUCCESS = "success", ERROR = "error", COMPLETE = "complete", CANCEL = "cancel", CLEAR = "clear", PAUSE = "pause", RESUME = "resume", PROGRESS = "progress", REMOVE = "remove", VALIDATIONERRORS = "validationErrors", INVALIDMAXFILESIZE = "invalidMaxFileSize", INVALIDMINFILESIZE = "invalidMinFileSize", INVALIDFILEEXTENSION = "invalidFileExtension", PROGRESSHIDEDELAY = 1e3, PROGRESSHIDEDURATION = 2e3, HOVER_STATE = "k-hover", FOCUS_STATE = "k-focus", PROGRESSBAR_CLASS = "k-progressbar", PROGRESSBAR_SELECTOR = "." + PROGRESSBAR_CLASS, PROGRESSBAR_TEMPLATE_SELECTOR = ".k-progress", TABINDEX = "tabindex", WARNINGICON_SELECTOR = `.k-i-exclamation-circle,.k-svg-i-exclamation-circle`; var headerStatusIconName = { loading: "upload", warning: "exclamation-circle", success: "check" }; var Upload = Widget.extend({ init: function(element, options) { var that = this; that.progressbars = []; Widget.fn.init.call(that, element, options); that.name = element.name; that.multiple = that.options.multiple; that.directory = that.options.directory; that.localization = that.options.localization; var activeInput = that.element; that.wrapper = activeInput.closest(".k-upload"); if (that.wrapper.length === 0) { that.wrapper = that._wrapInput(activeInput); } that._activeInput(activeInput); that.element.addClass("k-hidden"); that.toggle(that.options.enabled); var ns = that._ns = NS + "-" + kendo.guid(); activeInput.closest("form").on("submit" + ns, that._onParentFormSubmit.bind(that)).on("reset" + ns, that._onParentFormReset.bind(that)); that._initUploadModule(); that._toggleDropZone(); that.wrapper.on("keydown", ".k-upload-button", that._onUploadButtonKeydown.bind(that)).on("click", ".k-upload-action", that._onFileAction.bind(that)).on("click", ".k-clear-selected", that._onClearSelected.bind(that)).on("click", ".k-upload-button", function(e) { e.preventDefault(); that.element.click(); }).on("click", ".k-upload-selected", that._onUploadSelected.bind(that)).on("keydown", that._onKeyDown.bind(that)).on("focusout", that._focusout.bind(that)); if (that.element.val()) { that._onInputChange({ target: that.element }); } }, events: [ SELECT, UPLOAD, SUCCESS, ERROR, COMPLETE, CANCEL, CLEAR, PROGRESS, REMOVE, PAUSE, RESUME ], options: { name: "Upload", enabled: true, multiple: true, directory: false, showFileList: true, uniqueFileUids: false, template: "", files: [], async: { autoRetryAfter: 0, bufferChunkSize: 1e7, maxAutoRetries: 1, removeVerb: "POST", autoUpload: true, withCredentials: true, accept: "*/*; q=0.5, application/json", useArrayBuffer: false }, localization: { "select": "Select files...", "cancel": "Cancel", "retry": "Retry", "remove": "Remove", "pause": "Pause", "resume": "Resume", "clearSelectedFiles": "Clear", "uploadSelectedFiles": "Upload", "dropFilesHere": "Drop files here to upload", "invalidFiles": "Invalid file(s). Please check file upload requirements.", "statusUploading": "uploading", "statusUploaded": "uploaded", "statusWarning": "warning", "statusFailed": "failed", "headerStatusUploading": "Uploading...", "headerStatusPaused": "Paused", "headerStatusUploaded": "Done", "uploadSuccess": "File(s) uploaded successfully.", "uploadFail": "File(s) failed to upload.", "invalidMaxFileSize": "File size too large.", "invalidMinFileSize": "File size too small.", "invalidFileExtension": "File type not allowed." }, validation: { allowedExtensions: [], maxFileSize: 0, minFileSize: 0 }, dropZone: "" }, _initUploadModule: function() { var that = this, options = that.options; if (options.async.saveUrl) { that._module = that._supportsFormData() ? new formDataUploadModule(that) : new iframeUploadModule(that); that._async = true; var initialFiles = options.files; if (initialFiles.length > 0) { that._renderInitialFiles(initialFiles); } } else { that._module = new syncUploadModule(that); } }, setOptions: function(options) { var that = this, activeInput = that.element; $(that.options.dropZone).off(that._ns); Widget.fn.setOptions.call(that, options); that.multiple = that.options.multiple; that.directory = that.options.directory; activeInput.attr("multiple", that._supportsMultiple() ? that.multiple : false); if (that.directory) { activeInput.attr("webkitdirectory", that.directory); activeInput.attr("directory", that.directory); } that.toggle(that.options.enabled); that._initUploadModule(); that._toggleDropZone(); }, enable: function(enable) { enable = typeof enable === "undefined" ? true : enable; this.toggle(enable); }, disable: function() { this.toggle(false); }, toggle: function(enable) { enable = typeof enable === "undefined" ? enable : !enable; this.wrapper.toggleClass("k-disabled", enable); this.element.prop("disabled", enable); }, focus: function() { this.wrapper.find(".k-upload-button").trigger("focus"); }, destroy: function() { var that = this; var customDropZone = $(that.options.dropZone); $(document).add($(".k-dropzone", that.wrapper)).add(that.wrapper.closest("form")).off(that._ns); if (customDropZone.length > 0) { customDropZone.off(that._ns); } $(that.element).off(NS); if (that.progressbars) { that.progressbars.forEach((progressbar) => { progressbar.destroy(); }); } Widget.fn.destroy.call(that); }, pause: function(fileEntry) { this._module.onPause({ target: $(fileEntry, this.wrapper) }); var pauseIcon = fileEntry.find(".k-i-pause-sm,.k-svg-i-pause-sm"); var resume = kendo.htmlEncode(this.localization.resume); kendo.ui.icon(pauseIcon, { icon: "play-sm" }); pauseIcon.attr("title", resume); $(pauseIcon).parent().attr("aria-label", resume); }, resume: function(fileEntry) { this._module.onResume({ target: $(fileEntry, this.wrapper) }); var playIcon = fileEntry.find(".k-i-play-sm,.k-svg-i-play-sm"); var pause = kendo.htmlEncode(this.localization.pause); kendo.ui.icon(playIcon, { icon: "pause-sm" }); playIcon.attr("title", pause); $(playIcon).parent().attr("aria-label", pause); }, upload: function() { var that = this; that._module.onSaveSelected(); }, getFiles: function() { var that = this; var filesData; var allFiles = []; var listItems = that.wrapper.find(".k-file"); for (var i = 0; i < listItems.length; i++) { filesData = $(listItems[i]).data("fileNames"); if (filesData) { for (var j = 0; j < filesData.length; j++) { allFiles.push(filesData[j]); } } } return allFiles; }, clearAllFiles: function() { var that = this; var files = that.wrapper.find(".k-file"); files.each(function(index, file) { that._removeFileByDomElement(file, false); }); }, removeAllFiles: function() { var that = this; var files = that.wrapper.find(".k-file"); files.each(function(index, file) { that._removeFileByDomElement(file, true); }); }, removeFileByUid: function(uid) { this._removeFileByUid(uid, true); }, clearFileByUid: function(uid) { this._removeFileByUid(uid, false); }, _removeFileByUid: function(uid, shouldSendRemoveRequest) { var that = this; var fileEntry; if (typeof uid !== "string") { return; } fileEntry = $(".k-file[" + kendo.attr("uid") + "=\"" + uid + "\"]", that.wrapper); if (fileEntry.length > 0) { that._removeFileByDomElement(fileEntry, shouldSendRemoveRequest); } }, clearFile: function(callback) { this._removeFile(callback, false); }, removeFile: function(callback) { this._removeFile(callback, true); }, _removeFile: function(callback, shouldSendRemoveRequest) { var that = this; var files = that.wrapper.find(".k-file"); var fileData; if (typeof callback === "function") { files.each(function(index, file) { fileData = $(file).data("fileNames"); if (callback(fileData)) { that._removeFileByDomElement(file, shouldSendRemoveRequest); } }); } }, _removeFileByDomElement: function(fileEntry, shouldSendRemoveRequest) { var that = this; var fileData = { target: $(fileEntry, that.wrapper) }; var allFiles; if (that.options.async.saveUrl) { if ($(fileEntry).hasClass("k-file-progress")) { that._module.onCancel(fileData); } else { that._module.onRemove(fileData, {}, shouldSendRemoveRequest); } allFiles = $(".k-file", that.wrapper); if (allFiles.length === 0) { that._hideHeaderUploadstatus(); } else { that._updateHeaderUploadStatus(); } } else { that._module.onRemove(fileData, {}, shouldSendRemoveRequest); } }, _addInput: function(sourceInput) { if (!sourceInput[0].nodeType) { return; } var that = this, input = sourceInput.clone().val(""); input.insertAfter(that.element).data("kendo" + that.options.prefix + that.options.name, that); $(that.element).attr(TABINDEX, "-1").removeAttr("id").off(NS); that._activeInput(input); that.wrapper.find(".k-upload-button").trigger("focus"); }, _activeInput: function(input) { var that = this, wrapper = that.wrapper; that.element = input; if (that.directory) { input.attr("webkitdirectory", that.directory); input.attr("directory", that.directory); } input.attr("multiple", that._supportsMultiple() ? that.multiple : false).attr("autocomplete", "off").on("click" + NS, function(e) { if (wrapper.hasClass("k-disabled")) { e.preventDefault(); } }).on("change" + NS, that._onInputChange.bind(that)); }, _adjustFocusState: function(focusedItem, toFocus) { focusedItem.removeClass(FOCUS_STATE); focusedItem.attr(TABINDEX, -1); toFocus.addClass(FOCUS_STATE); toFocus.attr(TABINDEX, 0); }, _arrowKeyNavigation: function(e, key, focusedItem) { var that = this, kendoKeys = kendo.keys, toFocus; if (key === kendoKeys.DOWN) { e.preventDefault(); e.stopPropagation(); toFocus = that.wrapper.find(".k-upload-files .k-file").first(); if (focusedItem.length > 0) { if (focusedItem.hasClass("k-upload-action")) { focusedItem.removeClass(FOCUS_STATE); focusedItem = focusedItem.closest(".k-file"); } toFocus = focusedItem.next(); } that._adjustFocusState(focusedItem, toFocus); if (!toFocus || toFocus.length === 0) { toFocus = that.wrapper.find(".k-clear-selected"); } } else if (key === kendoKeys.UP) { e.preventDefault(); e.stopPropagation(); toFocus = that.wrapper.find(".k-upload-files .k-file:last"); if (focusedItem.length > 0) { if (focusedItem.hasClass("k-upload-action")) { focusedItem.removeClass(FOCUS_STATE); focusedItem = focusedItem.closest(".k-file"); } toFocus = focusedItem.prev(); } that._adjustFocusState(focusedItem, toFocus); } else if (key === kendoKeys.RIGHT) { if (focusedItem.hasClass("k-upload-action")) { toFocus = focusedItem.next(".k-upload-action"); if (!toFocus || toFocus.length === 0) { toFocus = focusedItem.parent().find(".k-upload-action:first"); } } else if (focusedItem.length > 0) { toFocus = focusedItem.find(".k-upload-action:first"); } if (toFocus && toFocus.length > 0) { focusedItem.removeClass(FOCUS_STATE); toFocus.addClass(FOCUS_STATE); } } else if (key === kendoKeys.LEFT) { if (focusedItem.hasClass("k-upload-action")) { toFocus = focusedItem.prev(".k-upload-action"); if (!toFocus || toFocus.length === 0) { toFocus = focusedItem.parent().find(".k-upload-action:last"); } } else if (focusedItem.length > 0) { toFocus = focusedItem.find(".k-upload-action:last"); } if (toFocus && toFocus.length > 0) { focusedItem.removeClass(FOCUS_STATE); toFocus.addClass(FOCUS_STATE); } } if ((!toFocus || toFocus.length === 0) && (key === kendoKeys.UP || key === kendoKeys.DOWN)) { toFocus = that.wrapper.find(".k-upload-button"); } if (toFocus && toFocus.length > 0) { that._preventFocusRemove = true; toFocus.trigger("focus"); } }, _asyncCommandKeyNavigation: function(key, focusedItem, eventArgs) { var that = this, kendoKeys = kendo.keys, fileEntry = $(focusedItem, that.wrapper); that._retryClicked = false; if (key === kendoKeys.ESC && focusedItem.find(".k-i-cancel,.k-svg-i-cancel").length > 0) { that.trigger(CANCEL, eventArgs); that._module.onCancel({ target: fileEntry }); that._checkAllComplete(); that._updateHeaderUploadStatus(); that._preventFocusRemove = true; that.wrapper.find(".k-upload-button").trigger("focus"); } else if (key === kendoKeys.SPACEBAR) { if (focusedItem.find(".k-i-pause-sm,.k-svg-i-pause-sm").length > 0) { that.trigger(PAUSE, eventArgs); that.pause(focusedItem); that._updateHeaderUploadStatus(); } else if (focusedItem.find(".k-i-play-sm,.k-svg-i-play-sm").length > 0) { that.trigger(RESUME, eventArgs); that.resume(focusedItem); } } else if (key === kendoKeys.ENTER && !focusedItem.is(".k-file-progress, .k-file-success, .k-file-invalid")) { if (that.options.async.chunkSize && !that.options.async.concurrent && $(".k-file-progress", that.wrapper).length > 0) { return; } $(WARNINGICON_SELECTOR, focusedItem).remove(); $(PROGRESSBAR_SELECTOR, focusedItem).finish().show(); if (!that._module.metaData[fileEntry.data("uid")]) { that._module.prepareChunk(fileEntry); } that._module.onRetry({ target: fileEntry }); that._retryClicked = true; } }, _commandKeyNavigation: function(key, focusedItem) { var that = this, kendoKeys = kendo.keys, files = focusedItem.data("fileNames"), hasValidationErrors = that._filesContainValidationErrors(files), eventArgs = { files, headers: {} }; if (key === kendoKeys.DELETE) { if (!that.trigger(REMOVE, eventArgs)) { that._module.onRemove({ target: $(focusedItem, that.wrapper) }, eventArgs, !hasValidationErrors); that._preventFocusRemove = true; that.wrapper.find(".k-upload-button").trigger("focus"); } } else if (key === kendoKeys.TAB) { focusedItem.removeClass(FOCUS_STATE); focusedItem.attr(TABINDEX, -1); } else if (!!that.options.async.saveUrl) { that._asyncCommandKeyNavigation(key, focusedItem, eventArgs); } }, _focusout: function() { var focusedItem = this.wrapper.find(".k-upload-files .k-file." + FOCUS_STATE); if (!this._preventFocusRemove) { focusedItem.removeClass(FOCUS_STATE); focusedItem.attr(TABINDEX, -1); } else { this._preventFocusRemove = false; } }, _onKeyDown: function(e) { var that = this, focusedItem = that.wrapper.find(".k-upload-files .k-file." + FOCUS_STATE + "," + ".k-upload-action." + FOCUS_STATE), kendoKeys = kendo.keys, commandKeys = [ kendoKeys.DELETE, kendoKeys.ESC, kendoKeys.ENTER, kendoKeys.SPACEBAR, kendoKeys.TAB ], key = e.keyCode; if (key === kendoKeys.DOWN || key === kendoKeys.UP || key === kendoKeys.LEFT || key === kendoKeys.RIGHT) { that._arrowKeyNavigation(e, key, focusedItem); } else if (focusedItem.length > 0 && focusedItem.hasClass("k-file") && commandKeys.indexOf(key) > -1 && !that.wrapper.hasClass("k-disabled")) { if (key === kendoKeys.SPACEBAR) { e.preventDefault(); e.stopPropagation(); } that._commandKeyNavigation(key, focusedItem); } }, _onInputChange: function(e) { var that = this; var input = $(e.target); var files = assignGuidToFiles(that._inputFiles(input), that._isAsyncNonBatch() || that.options.uniqueFileUids); validateFiles(files, that.options.validation); var prevented = that.trigger(SELECT, { files }); if (prevented) { that._addInput(input); input.remove(); } else { that._module.onSelect({ target: input }, files); } that.focus(); }, _onUploadButtonKeydown: function(e) { var key = e.keyCode, kendoKeys = kendo.keys; if (key === kendoKeys.ENTER || key === kendoKeys.SPACEBAR) { this.wrapper.find(".k-upload-button-wrap input").last().trigger("click"); } }, _readDirectory: function(item) { var deferred = new $.Deferred(); var dirReader = item.createReader(); var allFolderFiles = []; var readEntries = function() { dirReader.readEntries(function(entries) { if (!entries.length) { deferred.resolve(allFolderFiles); } else { allFolderFiles = allFolderFiles.concat(entries); readEntries(); } }, deferred.reject); }; readEntries(); return deferred.promise(); }, _readFile: function(item) { var that = this; var fullpath = item.fullPath; item.file(function(file) { file.relativePath = fullpath.slice(1); that.droppedFolderFiles.push(file); that.droppedFolderCounter--; if (that.droppedFolderCounter === 0) { setTimeout(function() { if (that.droppedFolderCounter === 0) { if (that.droppedFolderFiles.length) { that._proceedDroppedItems(that.droppedFolderFiles); that.droppedFolderFiles = []; } } }, 0); } }, function() { logToConsole("File error."); }); }, _traverseFileTree: function(item, skipCounter) { var that = this; if (!skipCounter) { that.droppedFolderCounter--; } this._readDirectory(item).then(function(items) { that.droppedFolderCounter += items.length; for (var i = 0; i < items.length; i++) { if (items[i].isFile) { that._readFile(items[i]); } else if (items[i].isDirectory) { that._traverseFileTree(items[i]); } } }); }, _onDrop: function(e) { var dt = e.originalEvent.dataTransfer; var that = this; var droppedFiles = dt.files; var length; stopEvent(e); if (that.options.directoryDrop && dt.items) { length = dt.items.length; that.droppedFolderCounter = 0; that.droppedFolderFiles = []; for (var i = 0; i < length; i++) { if (dt.items[i].webkitGetAsEntry) { var entry = dt.items[i].webkitGetAsEntry(); if (entry.isDirectory) { that._traverseFileTree(entry, true); } else if (entry.isFile) { that.droppedFolderFiles.push(dt.files[i]); } } else { that._proceedDroppedItems(droppedFiles); } } } else { that._proceedDroppedItems(droppedFiles); } }, _proceedDroppedItems: function(droppedFiles) { var that = this; var files = assignGuidToFiles(getAllFileInfo(droppedFiles), that._isAsyncNonBatch() || that.options.uniqueFileUids); if (droppedFiles.length > 0 && !that.wrapper.hasClass("k-disabled")) { if (!that.multiple && files.length > 1) { files.splice(1, files.length - 1); } validateFiles(files, that.options.validation); var prevented = that.trigger(SELECT, { files }); if (!prevented) { that._module.onSelect({ target: $(".k-dropzone", that.wrapper) }, files); } } }, _filesContainValidationErrors: function(files) { var hasErrors = false; $(files).each(function(index, file) { if (file[VALIDATIONERRORS] && file[VALIDATIONERRORS].length > 0) { hasErrors = true; return false; } }); return hasErrors; }, _isAsyncNonBatch: function() { return this._async && !this.options.async.batch || false; }, _renderInitialFiles: function(files) { var that = this; var idx = 0; files = assignGuidToFiles(files, true); for (idx = 0; idx < files.length; idx++) { var currentFile = files[idx]; var fileEntry = that._enqueueFile(currentFile.name, { fileNames: [currentFile] }); fileEntry.addClass("k-file-success").data("files", [files[idx]]); if (that._supportsRemove()) { that._fileAction(fileEntry, REMOVE); } } }, _prepareTemplateData: function(name, data) { var filesData = data.fileNames, templateData = {}, totalSize = 0, idx = 0; for (idx = 0; idx < filesData.length; idx++) { totalSize += filesData[idx].size; } templateData.name = name; templateData.size = totalSize; templateData.files = data.fileNames; return templateData; }, _createProgressbarWapper: function() { return "<div class='" + PROGRESSBAR_CLASS + " k-hidden'></div>"; }, _createFileIconWrapper: function(fileTypeIcon) { return "<span class='k-file-icon-wrapper'>" + kendo.ui.icon({ icon: fileTypeIcon, iconClass: "k-file-icon", size: "xxlarge" }) + "<span class='k-file-state'></span>" + "</span>"; }, _progressbarInit: function(wrapper) { let progressbar = wrapper.kendoProgressBar({ animation: false, showStatus: false }).data("kendoProgressBar"); this.progressbars.push(progressbar); }, _prepareDefaultSingleFileEntryTemplate: function(data) { var that = this; var file = data.fileNames[0]; var fileSize = getTotalFilesSizeMessage(data.fileNames); var fileGroup = kendo.getFileGroup(file.extension, true); var errors = file[VALIDATIONERRORS]; var isError = errors && errors.length > 0; var invalidClass = isError ? " k-file-invalid k-file-error" : ""; var fileDetails = isError ? "<span class='k-file-validation-message' aria-live='polite'>" + kendo.htmlEncode(that.localization[errors[0]]) + "</span>" : "<span class='k-file-size'>" + fileSize + "</span>"; let encodedFileName = kendo.htmlEncode(file.name, true); var template = ""; template += "<li class='k-file" + invalidClass + "'><div class='k-file-single'>" + this._createProgressbarWapper() + this._createFileIconWrapper(fileGroup) + "<span class='k-file-info'>" + "<span class='k-file-name' title='" + encodedFileName + "'>" + encodedFileName + "</span>" + fileDetails + "</span>"; template += "<span class='k-upload-actions'></span></div>"; return $(template); }, _prepareDefaultMultipleFileEntriesTemplate: function(data) { var that = this; var files = data.fileNames; var filesHaveValidationErrors = that._filesContainValidationErrors(files); var totalFileSize = getTotalFilesSizeMessage(files); var template = ""; var i, currentFile; var invalidClass = filesHaveValidationErrors ? " k-file-invalid k-file-error" : ""; template += "<li class='k-file" + invalidClass + "'><div class='k-file-multiple'>" + this._createProgressbarWapper() + this._createFileIconWrapper("copy"); files.sort(function(a, b) { if (a[VALIDATIONERRORS]) { return -1; } if (b[VALIDATIONERRORS]) { return 1; } return 0; }); template += "<span class='k-multiple-files-wrapper'>"; for (i = 0; i < files.length; i++) { currentFile = files[i]; var fileSize = getTotalFilesSizeMessage([currentFile]); let encodedFileName = kendo.htmlEncode(currentFile.name, true); template += "<span class='k-file-info'>"; if (currentFile[VALIDATIONERRORS] && currentFile[VALIDATIONERRORS].length > 0) { template += "<span class='k-file-name k-file-name-invalid' title='" + encodedFileName + "'>" + encodedFileName + "</span>"; } else { template += "<span class='k-file-name' title='" + encodedFileName + "'>" + encodedFileName + "</span>"; } template += "<span class='k-file-size'>" + fileSize + "</span></span>"; } if (filesHaveValidationErrors) { template += "<span class='k-file-validation-message' aria-live='polite'>" + kendo.htmlEncode(that.localization.invalidFiles) + "</span>"; } else { template += "<span class='k-file-summary'>Total: " + files.length + " files, " + totalFileSize + "</span>"; } template += "</span><span class='k-upload-actions'></span></div>"; return $(template); }, _enqueueFile: function(name, data) { var that = this; var existingFileEntries; var fileEntry; var fileUid = data.fileNames[0].uid; var fileList = $(".k-upload-files", that.wrapper); var options = that.options; var template = options.template; var templateData; var removeEventArgs; var progressbarSelector = template ? PROGRESSBAR_TEMPLATE_SELECTOR : PROGRESSBAR_SELECTOR; var progressbar; var isProgressbar; if (fileList.length === 0) { fileList = $("<ul class='k-upload-files'></ul>").appendTo(that.wrapper); if (!that.options.showFileList) { fileList.hide(); } that.wrapper.removeClass("k-upload-empty"); } existingFileEntries = $(".k-file", fileList); if (!template) { if (data.fileNames.length === 1) { fileEntry = that._prepareDefaultSingleFileEntryTemplate(data); } else { fileEntry = that._prepareDefaultMultipleFileEntriesTemplate(data); } } else { templateData = that._prepareTemplateData(name, data); template = kendo.template(template); fileEntry = $("<li class='k-file'>" + template(templateData) + "</li>"); fileEntry.find(".k-upload-action").addClass("k-button k-icon-button k-button-flat"); } progressbar = $(progressbarSelector, fileEntry[0]); isProgressbar = progressbar.length > 0; if (isProgressbar) { that._progressbarInit(progressbar); } fileEntry.attr(kendo.attr("uid"), fileUid).appendTo(fileList).data(data); if (!that._async && isProgressbar) { progressbar.data("kendoProgressBar").value(100); } if (!that.multiple && existingFileEntries.length > 0) { removeEventArgs = { files: existingFileEntries.data("fileNames"), headers: {} }; if (!that.trigger(REMOVE, removeEventArgs)) { that._module.onRemove({ target: $(existingFileEntries, that.wrapper) }, removeEventArgs); } } return fileEntry; }, _removeFileEntry: function(fileEntry) { var that = this; var fileList = fileEntry.closest(".k-upload-files"); var allFiles, allCompletedFiles, allInvalidFiles; fileEntry.remove(); allFiles = $(".k-file", fileList); allCompletedFiles = $(".k-file-success, .k-file-error", fileList); if (allCompletedFiles.length === allFiles.length) { this._hideActionButtons(); } if (allFiles.length === 0) { fileList.remove(); that.wrapper.addClass("k-upload-empty"); that._hideHeaderUploadstatus(); } else { that._updateHeaderUploadStatus(); } }, _fileAction: function(fileElement, actionKey, skipClear) { var iconsNameDictionary = { remove: "x", cancel: "cancel", retry: "arrow-rotate-cw-small", pause: "pause-sm" }; var firstActionButton; let actionKeyText = kendo.htmlEncode(this.localization[actionKey]); if (!iconsNameDictionary.hasOwnProperty(actionKey)) { return; } if (!skipClear) { this._clearFileAction(fileElement); } if (!this.options.template) { if (!skipClear) { fileElement.find(".k-upload-action").remove(); } fileElement.find(".k-upload-actions").append(this._renderAction(iconsNameDictionary[actionKey], actionKeyText, actionKey == "retry" ? "k-i-retry" : "")); } else { firstActionButton = fileElement.find(".k-upload-action").first(); if (!firstActionButton.find(".k-icon,.k-svg-icon").length) { let firstActionIcon = kendo.ui.icon($(`<span title="${actionKeyText}" aria-label="${actionKeyText}"></span>`), { icon: iconsNameDictionary[actionKey], iconClass: "k-button-icon" + (actionKey == "retry" ? " k-i-retry" : "") }); firstActionButton.addClass("k-button k-icon-button").append(firstActionIcon).show(); } else if (firstActionButton.next(".k-upload-action").length) { let firstActionIcon = kendo.ui.icon($(`<span title="${actionKeyText}" aria-label="${actionKeyText}"></span>`), { icon: iconsNameDictionary[actionKey], iconClass: "k-button-icon" + (actionKey == "retry" ? " k-i-retry" : "") }); firstActionButton.next(".k-upload-action").addClass("k-button k-icon-button").append(firstActionIcon).show(); } } }, _fileState: function(fileEntry, stateKey) { var localization = this.localization, states = { uploading: { text: localization.statusUploading }, uploaded: { text: localization.statusUploaded }, failed: { text: localization.statusFailed } }, currentState = states[stateKey]; if (currentState) { $("span.k-file-state", fileEntry).text(kendo.htmlEncode(currentState.text)); } }, _renderAction: function(iconName, actionText, iconClass) { if (iconName !== "") { return $("<button type='button' class='k-button k-icon-button k-button-flat k-upload-action' aria-hidden='true' aria-label='" + actionText + "' tabindex='-1'>" + kendo.ui.icon($(`<span title="${actionText}"></span>`), { icon: iconName, iconClass: "k-button-icon" + (iconClass ? ` ${iconClass}` : "") }) + "</button>").on("focus", function() { $(this).addClass(FOCUS_STATE); }).on("blur", function() { $(this).removeClass(FOCUS_STATE); }); } else { return $("<button type='button' class='k-button'>" + "<span class=\"k-button-text\">" + actionText + "</span>" + "</button>"); } }, _clearFileAction: function(fileElement) { $(".k-upload-action", fileElement).empty().hide(); }, _onFileAction: function(e) { var that = this; if (!that.wrapper.hasClass("k-disabled")) { var button = $(e.target).closest(".k-upload-action"); var icon = button.find(".k-icon,.k-svg-icon"); var fileEntry = button.closest(".k-file"); var files = fileEntry.data("fileNames"); var hasValidationErrors = that._filesContainValidationErrors(files); var eventArgs = { files, headers: {} }; that._retryClicked = false; if (icon.is(".k-i-x,.k-svg-i-x")) { if (!that.trigger(REMOVE, eventArgs)) { that._module.onRemove({ target: $(fileEntry, that.wrapper) }, eventArgs, !hasValidationErrors); that.wrapper.find(".k-upload-button").trigger("focus"); } } else if (icon.is(".k-i-cancel,.k-svg-i-cancel")) { that.trigger(CANCEL, eventArgs); that._module.onCancel({ target: $(fileEntry, that.wrapper) }); that._checkAllComplete(); that._updateHeaderUploadStatus(); that.wrapper.find(".k-upload-button").trigger("focus"); } else if (icon.is(".k-i-pause-sm,.k-svg-i-pause-sm")) { that.trigger(PAUSE, eventArgs); that.pause(fileEntry); that._updateHeaderUploadStatus(); } else if (icon.is(".k-i-play-sm,.k-svg-i-play-sm")) { that.trigger(RESUME, eventArgs); that.resume(fileEntry); } else if (icon.hasClass("k-i-retry")) { $(".k-i-exclamation-circle", fileEntry).remove(); $(PROGRESSBAR_SELECTOR, fileEntry).finish().show(); that._module.onRetry({ target: $(fileEntry, that.wrapper) }); that._retryClicked = true; } fileEntry.addClass(FOCUS_STATE); } return false; }, _onUploadSelected: function() { var that = this; var wrapper = that.wrapper; if (!wrapper.hasClass("k-disabled")) { this._module.onSaveSelected(); } return false; }, _onClearSelected: function() { var that = this; var wrapper = that.wrapper; var clearEventArgs = {}; if (!wrapper.hasClass("k-disabled") && !that.trigger(CLEAR, clearEventArgs)) { that.clearAllFiles(); } return false; }, _onFileProgress: function(e, percentComplete) { var progressPct; var progressBar = $(PROGRESSBAR_SELECTOR, e.target).data("kendoProgressBar"); if (percentComplete > 100) { percentComplete = 100; } $(PROGRESSBAR_SELECTOR, e.target).removeClass("k-hidden"); if (!this.options.template) { progressPct = $(".k-upload-pct", e.target); if (progressPct.length === 0) { $(".k-upload-actions", e.target).prepend("<span class='k-upload-pct'></span>"); } if (percentComplete !== 100) { $(".k-upload-pct", e.target).text(percentComplete + "%"); } else { $(".k-upload-pct", e.target).remove(); } } if (progressBar) { progressBar.value(percentComplete); } this.trigger(PROGRESS, { files: getFileEntry(e).data("fileNames"), percentComplete }); }, _onUploadSuccess: function(e, response, xhr) { var that = this; var fileEntry = getFileEntry(e); var files = fileEntry.data("fileNames"); var fileInfo = fileEntry.find(".k-file-summary"); var fileSize = fileEntry.find(".k-file-size"); var prevented = that.trigger(SUCCESS, { files: fileEntry.data("fileNames"), response, operation: "upload", XMLHttpRequest: xhr }); if (prevented) { that._setUploadErrorState(fileEntry); } else { that._fileState(fileEntry, "uploaded"); fileEntry.removeClass("k-file-progress").addClass("k-file-success"); if (fileInfo.length > 0) { fileInfo.addClass("k-hidden").after("<span class=\"k-file-validation-message\" aria-live=\"polite\">" + files.length + " " + kendo.htmlEncode(that.localization.uploadSuccess) + "</span>"); } else if (fileSize.length > 0) { fileSize.addClass("k-hidden").after("<span class=\"k-file-validation-message\" aria-live=\"polite\">" + kendo.htmlEncode(that.localization.uploadSuccess) + "</span>"); } that._updateHeaderUploadStatus(); if (that._supportsRemove()) { that._fileAction(fileEntry, REMOVE); } else { that._clearFileAction(fileEntry); } } that._hideUploadProgress(fileEntry); that._checkAllComplete(); }, _onUploadError: function(e, xhr) { var that = this; var module = that._module; var fileEntry = getFileEntry(e); var fileUid = fileEntry.data("uid"); that._setUploadErrorState(fileEntry); that.trigger(ERROR, { operation: "upload", files: fileEntry.data("fileNames"), XMLHttpRequest: xhr }); logToConsole("Server response: " + xhr.responseText); if (!that.options.async.chunkSize) { that._hideUploadProgress(fileEntry); } else { if (module._decreasePosition) { module._decreasePosition(fileUid); } } that._checkAllComplete(); if (this.options.async.autoRetryAfter) { this._autoRetryAfter(fileEntry); } }, _autoRetryAfter: function(fileEntry) { var that = this; var retries = this._module.retries; if (!retries) { return; } if (!retries[fileEntry.data("uid")]) { retries[fileEntry.data("uid")] = 1; } if (retries[fileEntry.data("uid")] <= this.options.async.maxAutoRetries) { retries[fileEntry.data("uid")]++; setTimeout(function() { that._module.performUpload(fileEntry); }, this.options.async.autoRetryAfter); } }, _setUploadErrorState: function(fileEntry) { var that = this, uploadPercentage, files = fileEntry.data("fileNames"), fileInfo = fileEntry.find(".k-file-summary"), fileSize = fileEntry.find(".k-file-size"); that._fileState(fileEntry, "failed"); fileEntry.removeClass("k-file-progress").addClass("k-file-error"); if (fileInfo.length > 0) { fileInfo.addClass("k-hidden").after("<span class=\"k-file-validation-message\" aria-live=\"polite\">" + files.length + " " + kendo.htmlEncode(that.localization.uploadFail) + "</span>"); } else if (fileSize.length > 0) { fileSize.addClass("k-hidden").after("<span class=\"k-file-validation-message\" aria-live=\"polite\">" + kendo.htmlEncode(that.localization.uploadFail) + "</span>"); } that._updateUploadProgress(fileEntry); uploadPercentage = $(".k-upload-pct", fileEntry); if (uploadPercentage.length > 0) { uploadPercentage.remove(); } this._updateHeaderUploadStatus(); this._fileAction(fileEntry, "retry"); this._fileAction(fileEntry, REMOVE, true); if (that._retryClicked) { fileEntry.trigger("focus"); } }, _updateUploadProgress: function(fileEntry) { var that = this; var progressbar = $(PROGRESSBAR_SELECTOR, fileEntry); var isProgressbar = progressbar.length > 0; if (!that.options.async.chunkSize && isProgressbar) { progressbar.data("kendoProgressBar").value(100); } else { var fileUid = fileEntry.data("uid"); if (that._module.metaData) { var fileMetaData = that._module.metaData[fileUid]; if (fileMetaData) { var percentComplete = fileMetaData.totalChunks ? Math.round(fileMetaData.chunkIndex / fileMetaData.totalChunks * 100) : 100; that._onFileProgress({ target: $(fileEntry, that.wrapper) }, percentComplete); } } } }, _hideUploadProgress: function(fileEntry) { $(PROGRESSBAR_SELECTOR, fileEntry).delay(PROGRESSHIDEDELAY).fadeOut(PROGRESSHIDEDURATION, function() { if ($(this).data("kendoProgressBar")) { $(this).data("kendoProgressBar").value(0); } }); }, _showActionButtons: function() { var that = this; var actionsWrapper = $(".k-actions", that.wrapper); var uploadButton = $(".k-upload-selected", that.wrapper); var clearButton = $(".k-clear-selected", that.wrapper); if (uploadButton.length === 0) { uploadButton = $(kendo.html.renderButton(`<button class='k-upload-selected'>${kendo.htmlEncode(this.localization.uploadSelectedFiles)}</button>`, { icon: "upload", themeColor: "primary" })); clearButton = $(kendo.html.renderButton(`<button class='k-clear-selected'>${kendo.htmlEncode(this.localization.clearSelectedFiles)}</button>`, { icon: "x" })); } if (!actionsWrapper.length) { actionsWrapper = $("<div />").addClass("k-actions").append(uploadButton, clearButton); } this.wrapper.append(actionsWrapper); }, _hideActionButtons: function() { $(".k-actions", this.wrapper).remove(); }, _showHeaderUploadStatus: function(isUploading) { var that = this; var localization = that.localization; var dropZone = $(".k-dropzone", that.wrapper); var headerUploadStatus = $(".k-upload-status", that.wrapper); if (headerUploadStatus.length !== 0) { headerUploadStatus.remove(); } $(".k-dropzone-hint", that.wrapper).addClass("k-hidden"); headerUploadStatus = "<span class=\"k-upload-status\"><span class=\"k-icon\"></span></span>"; if (isUploading) { headerUploadStatus = $(headerUploadStatus).append(kendo.htmlEncode(localization.headerStatusUploading)); kendo.ui.icon(headerUploadStatus.find(".k-icon,.k-svg-icon"), { icon: headerStatusIconName.loading }); } else { headerUploadStatus = $(headerUploadStatus).append(kendo.htmlEncode(localization.headerStatusUploaded)); kendo.ui.icon(headerUploadStatus.find(".k-icon,.k-svg-icon"), { icon: headerStatusIconName.warning }); } if (dropZone.length > 0) { dropZone.append(headerUploadStatus); } else { $(".k-upload-button", that.wrapper).after(headerUploadStatus); } }, _updateHeaderUploadStatus: function() { var that = this; var headerUploadStatus = $(".k-upload-status", this.wrapper); var currentlyUploading = $(".k-file", that.wrapper).not(".k-file-success, .k-file-error"); var currentlyFailed = $(".k-file-error", that.wrapper); var currentlyPaused = $(".k-file", that.wrapper).find(".k-i-play-sm,.k-svg-i-play-sm"); var headerUploadStatusIcon; if (currentlyPaused.length && (currentlyPaused.length === currentlyUploading.length || !that.options.async.concurrent)) { headerUploadStatusIcon = $(".k-icon,.k-svg-icon", headerUploadStatus).removeClass(); if (headerUploadStatusIcon.length) { kendo.ui.icon(headerUploadStatusIcon, { icon: "pause-sm" }); headerUploadStatus.html(headerUploadStatusIcon).append(kendo.htmlEncode(that.localization.headerStatusPaused)); } } else if (currentlyUploading.length === 0 || currentlyFailed.length > 0) { headerUploadStatus = $(".k-upload-status", that.wrapper); headerUploadStatusIcon = $(".k-icon,.k-svg-icon", headerUploadStatus).removeClass(); if (headerUploadStatusIcon.length) { kendo.ui.icon(headerUploadStatusIcon, { icon: currentlyFailed.length !== 0 ? headerStatusIconName.warning : headerStatusIconName.success }); headerUploadStatus.html(headerUploadStatusIcon).append(kendo.htmlEncode(that.localization.headerStatusUploaded)); } } }, _hideHeaderUploadstatus: function() { var that = this, dropZone = that.options.dropZone; $(".k-upload-status", this.wrapper).remove(); if (dropZone === "") { $(".k-dropzone-hint", that.wrapper).removeClass("k-hidden"); } }, _onParentFormSubmit: function() { var upload = this, element = upload.element; if (typeof this._module.onAbort !== "undefined") { this._module.onAbort(); } if (!element.value) { var input = $(element); input.attr("disabled", "disabled"); window.setTimeout(function() { input.prop("disabled", false); }, 0); } }, _onParentFormReset: function() { $(".k-upload-files", this.wrapper).remove(); }, _supportsFormData: function() { return typeof FormData != "undefined"; }, _supportsMultiple: function() { var windows = this._userAgent().indexOf("Windows") > -1; return !kendo.support.browser.opera && !(kendo.support.browser.safari && windows); }, _supportsDrop: function() { var userAgent = this._userAgent().toLowerCase(); var isChrome = /chrome/.test(userAgent); var isSafari = !isChrome && /safari/.test(userAgent); var isWindowsSafari = isSafari && /windows/.test(userAgent); return !isWindowsSafari && this._supportsFormData() && this.options.async.saveUrl; }, _userAgent: function() { return navigator.userAgent; }, _setupDropZone: function() { var that = this; var ns = that._ns; var dropZone = $(".k-dropzone", that.wrapper).on("dragenter" + ns, stopEvent).on("dragover" + ns, function(e) { if (e.originalEvent) { e.originalEvent.dataTransfer.dropEffect = "copy"; } e.preventDefault(); }).on("drop" + ns, that._onDrop.bind(that)); if (!dropZone.find(".k-dropzone-hint").length) { dropZone.append($("<span class='k-dropzone-hint'>" + kendo.htmlEncode(that.localization.dropFilesHere) + "</span>")); } bindDragEventWrappers(dropZone, ns, function() { if (!dropZone.closest(".k-upload").hasClass("k-disabled")) { dropZone.addClass(HOVER_STATE); } }, function() { dropZone.removeClass(HOVER_STATE); }); that._bindDocumentDragEventWrappers(dropZone); }, _setupCustomDropZone: function() { var that = this; var dropZone = $(that.options.dropZone); if (!that.wrapper.find(".k-dropzone-hint").length) { $(".k-dropzone", that.wrapper).append($("<span class='k-dropzone-hint k-hidden'>" + kendo.htmlEncode(that.localization.dropFilesHere) + "</span>")); } else { $(".k-dropzone-hint", that.wrapper).addClass("k-hidden"); } var ns = that._ns; dropZone.on("dragenter" + ns, stopEvent).on("dragover" + ns, function(e) { if (e.originalEvent) { e.originalEvent.dataTransfer.dropEffect = "copy"; } e.preventDefault(); }).on("drop" + ns, that._onDrop.bind(that)); bindDragEventWrappers(dropZone, ns, function(e) { if (!that.wrapper.hasClass("k-disabled")) { dropZone.removeClass(HOVER_STATE); dropZone.addClass(HOVER_STATE); $(e.target).addClass(HOVER_STATE); } }, function() { dropZone.removeClass(HOVER_STATE); }); that._bindDocumentDragEventWrappers(dropZone); }, _bindDocumentDragEventWrappers: function(dropZone) { var that = this; var ns = that._ns; bindDragEventWrappers($(document), ns, function() { if (!that.wrapper.hasClass("k-disabled")) { dropZone.addClass("k-dropzone-active"); dropZone.closest(".k-upload").removeClass("k-upload-empty"); dropZone.find(".k-dropzone-hint").removeClass("k-hidden"); } }, function() { dropZone.removeClass("k-dropzone-active"); if ($("li.k-file", dropZone.closest(".k-upload")).length === 0) { dropZone.closest(".k-upload").addClass("k-upload-empty"); } }); }, _toggleDropZone: function() { var that = this, dropZone = that.options.dropZone; if (!that._supportsDrop()) { return; } $(dropZone).off(that._ns); $(".k-dropzone", that.wrapper).off(that._ns); if (dropZone !== "") { that._setupCustomDropZone(); } else { that._setupDropZone(); } }, _supportsRemove: function() { return !!this.options.async.removeUrl; }, _submitRemove: function(fileNames, eventArgs, onSuccess, onError) { var upload = this, removeField = upload.options.async.removeField || "fileNames", params = $.extend(eventArgs.data, antiForgeryTokens()); params[removeField] = fileNames; jQuery.ajax({ type: this.options.async.removeVerb, dataType: "json", dataFilter: normalizeJSON, url: this.options.async.removeUrl, traditional: true, data: params, headers: eventArgs.headers, success: onSuccess, error: onError, xhrFields: { withCredentials: this.options.async.withCredentials } }); }, _wrapInput: function(input) { var that = this; var options = that.options; var hasLabel = !!input.attr("id") && $("[for='" + input.attr("id") + "']").length > 0; var selectText = kendo.htmlEncode(that.localization.select); var uploadButton = $("<div class='k-button k-upload-button' tabindex='0' role='button'><span class='k-button-text'></span></div>"); uploadButton.find(".k-button-text").text(selectText); input.wrap("<div class='k-upload' role='application'><div class='k-dropzone k-upload-dropzone'><div class='k-upload-button-wrap'></div></div></div>"); uploadButton.prependTo(input.parent()); if (!options.async.saveUrl) { input.closest(".k-upload").addClass("k-upload-sync"); } else { input.closest(".k-upload").addClass("k-upload-async"); } input.closest(".k-upload").addClass("k-upload-empty"); if (!hasLabel && !input.attr("aria-label")) { input.attr("aria-label", selectText); } input.attr({ tabindex: -1, "aria-hidden": true }); return input.closest(".k-upload"); }, _checkAllComplete: function() { if ($(".k-file.k-file-progress", this.wrapper).length === 0) { this.trigger(COMPLETE); } }, _inputFiles: function(sourceInput) { return inputFiles(sourceInput); } }); var syncUploadModule = function(upload) { this.name = "syncUploadModule"; this.element = upload.wrapper; this.upload = upload; this.element.closest("form").attr("enctype", "multipart/form-data").attr("encoding", "multipart/form-data"); }; syncUploadModule.prototype = { onSelect: function(e, files) { var upload = this.upload; var sourceInput = $(e.target); var filesContainErrors = upload._filesContainValidationErrors(files); upload._addInput(sourceInput); var fileData = { "fileNames": files }; if (filesContainErrors) { sourceInput.remove(); } else { fileData.relatedInput = sourceInput; } var file = upload._enqueueFile(getFileName(sourceInput), fileData); if (filesContainErrors) { upload._hideUploadProgress(file); } upload._fileAction(file, REMOVE); }, onRemove: function(e) { var fileEntry = getFileEntry(e); var relatedInput = fileEntry.data("relatedInput"); if (relatedInput) { relatedInput.remove(); } this.upload._removeFileEntry(fileEntry); } }; var iframeUploadModule = function(upload) { this.name = "iframeUploadModule"; this.element = upload.wrapper; this.upload = upload; this.iframes = []; }; Upload._frameId = 0; iframeUploadModule.prototype = { onSelect: function(e, files) { var upload = this.upload; var sourceInput = $(e.target); var hasValidationErrors = upload._filesContainValidationErrors(files); var fileEntry = this.prepareUpload(sourceInput, files, hasValidationErrors); if (upload.options.async.autoUpload) { if (!hasValidationErrors) { this.performUpload(fileEntry); } else { upload._fileAction(fileEntry, REMOVE); upload._showHeaderUploadStatus(false); } } else { upload._fileAction(fileEntry, REMOVE); if (!hasValidationErrors) { upload._showActionButtons(); } else { upload._updateHeaderUploadStatus(); } } if (hasValidationErrors) { upload._hideUploadProgress(fileEntry); } }, prepareUpload: function(sourceInput, files, hasValidationErrors) { var upload = this.upload; var activeInput = $(upload.element); var name = upload.options.async.saveField || sourceInput.attr("name"); var fileEntry, fileData, iframe, form; upload._addInput(sourceInput); sourceInput.attr("name", name); if (!hasValidationErrors) { iframe = this.createFrame(upload.name + "_" + Upload._frameId++); this.registerFrame(iframe); form = this.createForm(upload.options.async.saveUrl, iframe.attr("name")).append(activeInput); fileData = { "frame": iframe, "relatedInput": activeInput, "fileNames": files }; } else { sourceInput.remove(); fileData = { "fileNames": files }; } fileEntry = upload._enqueueFile(getFileName(sourceInput), fileData); if (iframe) { iframe.data({ "form": form, "file": fileEntry }); } return fileEntry; }, performUpload: function(fileEntry) { var e = { files: fileEntry.data("fileNames") }; var iframe = fileEntry.data("frame"); var upload = this.upload; var fileValidation = fileEntry.find(".k-file-validation-message"); var fileInfo = fileEntry.find(".k-file-summary"); var fileSize = fileEntry.find(".k-file-size"); if (!upload.trigger(UPLOAD, e)) { upload._hideActionButtons(); upload._showHeaderUploadStatus(true); iframe.appendTo(document.body); var form = iframe.data("f