From 1802dda136a56a29849bb2f6240ae6c8af2ec62f Mon Sep 17 00:00:00 2001 From: djmaze Date: Tue, 1 Sep 2020 16:57:14 +0200 Subject: [PATCH] Removed jQuery dependencies from Jua.js --- README.md | 15 +- dev/Settings/User/Themes.js | 13 +- dev/View/Popup/Compose.js | 12 +- dev/View/Popup/Contacts.js | 15 +- vendors/jua/jua.js | 658 +++++++++++------------------------- vendors/jua/jua.min.js | 2 +- 6 files changed, 224 insertions(+), 491 deletions(-) diff --git a/README.md b/README.md index a527493de..9fc16828e 100644 --- a/README.md +++ b/README.md @@ -80,26 +80,27 @@ Things might work in Edge 18, Firefox 50-62 and Chrome 54-68 due to one polyfill * Removed momentjs (localization still used) * Removed opentip (use CSS) * Removed non-community (aka Prem/Premium/License) code +* Modified Jua.js to be without jQuery |js/* |1.14.0 |native | |----------- |--------: |--------: | |admin.js |2.130.942 | 963.702 | -|app.js |4.184.455 |2.626.779 | +|app.js |4.184.455 |2.626.733 | |boot.js | 671.522 | 43.824 | -|libs.js | 647.614 | 315.759 | +|libs.js | 647.614 | 313.912 | |polyfills.js | 325.834 | 0 | -|TOTAL |7.960.367 |3.950.064 | +|TOTAL |7.960.367 |3.948.171 | |js/min/* |1.14.0 |native |gzip 1.14 |gzip |brotli | |--------------- |--------: |--------: |--------: |--------: |--------: | |admin.min.js | 252.147 | 130.802 | 73.657 | 37.916 | 32.474 | -|app.min.js | 511.202 | 354.515 |140.462 | 93.408 | 74.849 | +|app.min.js | 511.202 | 354.471 |140.462 | 93.386 | 74.944 | |boot.min.js | 66.007 | 5.564 | 22.567 | 2.327 | 1.989 | -|libs.min.js | 572.545 | 299.283 |176.720 | 92.510 | 81.659 | +|libs.min.js | 572.545 | 297.403 |176.720 | 92.006 | 81.186 | |polyfills.min.js | 32.452 | 0 | 11.312 | 0 | 0 | -|TOTAL |1.434.353 | 790.164 |424.718 |226.161 |190.971 | +|TOTAL |1.434.353 | 788.240 |424.718 |225.635 |190.593 | -644.189 bytes (198.557 gzip) is not much, but it feels faster. +646.113 bytes (199.083 gzip) is not much, but it feels faster. ### CSS changes diff --git a/dev/Settings/User/Themes.js b/dev/Settings/User/Themes.js index 1d5f1f72d..01beb9285 100644 --- a/dev/Settings/User/Themes.js +++ b/dev/Settings/User/Themes.js @@ -86,13 +86,12 @@ class ThemesUserSettings { initUploader() { if (this.background.uploaderButton() && this.capaUserBackground()) { const oJua = new Jua({ - 'action': uploadBackground(), - 'name': 'uploader', - 'queueSize': 1, - 'multipleSizeLimit': 1, - 'disableDragAndDrop': true, - 'disableMultiple': true, - 'clickElement': this.background.uploaderButton() + action: uploadBackground(), + name: 'uploader', + queueSize: 1, + multipleSizeLimit: 1, + disableMultiple: true, + clickElement: this.background.uploaderButton() }); oJua diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index 157b20b66..1c6ae7fcf 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -1182,12 +1182,12 @@ class ComposePopupView extends AbstractViewNext { const uploadCache = {}, attachmentSizeLimit = pInt(Settings.settingsGet('AttachmentLimit')), oJua = new Jua({ - 'action': upload(), - 'name': 'uploader', - 'queueSize': 2, - 'multipleSizeLimit': 50, - 'clickElement': this.composeUploaderButton(), - 'dragAndDropElement': this.composeUploaderDropPlace() + action: upload(), + name: 'uploader', + queueSize: 2, + multipleSizeLimit: 50, + clickElement: this.composeUploaderButton(), + dragAndDropElement: this.composeUploaderDropPlace() }); if (oJua) { diff --git a/dev/View/Popup/Contacts.js b/dev/View/Popup/Contacts.js index 589bd1b3f..b44faeb95 100644 --- a/dev/View/Popup/Contacts.js +++ b/dev/View/Popup/Contacts.js @@ -416,14 +416,13 @@ class ContactsPopupView extends AbstractViewNext { initUploader() { if (this.importUploaderButton()) { const j = new Jua({ - 'action': uploadContacts(), - 'name': 'uploader', - 'queueSize': 1, - 'multipleSizeLimit': 1, - 'disableDragAndDrop': true, - 'disableMultiple': true, - 'disableDocumentDropPrevent': true, - 'clickElement': this.importUploaderButton() + action: uploadContacts(), + name: 'uploader', + queueSize: 1, + multipleSizeLimit: 1, + disableMultiple: true, + disableDocumentDropPrevent: true, + clickElement: this.importUploaderButton() }); if (j) { diff --git a/vendors/jua/jua.js b/vendors/jua/jua.js index e4127dc25..316e45a20 100644 --- a/vendors/jua/jua.js +++ b/vendors/jua/jua.js @@ -2,11 +2,9 @@ (()=>{ 'use strict'; - var - iDefLimit = 20, - $ = jQuery; - const + doc = document, + iDefLimit = 20, defined = v => undefined !== v, /** * @param {*} aItems @@ -18,16 +16,14 @@ { if (aItems && aItems.length) { - var - iInputLimit = 0, + iLimit = defined(iLimit) ? parseInt(iLimit || 0, 10) : iDefLimit; + let + iInputLimit = iLimit, oFile = null, - bUseLimit = false, + bUseLimit = 0 < iLimit, bCallLimit = false ; - iLimit = defined(iLimit) ? parseInt(iLimit || 0, 10) : iDefLimit; - iInputLimit = iLimit; - bUseLimit = 0 < iLimit; Array.from(aItems).forEach(oItem => { if (oItem) { @@ -45,75 +41,12 @@ }); } }, - /** - * @param {number=} iLen - * @return {string} - */ - fakeMd5 = iLen => - { - var - sResult = '', - sLine = '0123456789abcdefghijklmnopqrstuvwxyz' - ; - iLen = defined(iLen) ? parseInt(iLen || 0, 10) : 32; - - while (iLen--) - sResult += sLine.substr(Math.round(Math.random() * 36), 1); - - return sResult; - }; - - var Utils = { - /** - * @param {*} oParent - * @param {*} oDescendant - * - * @return {boolean} - */ - contains : (oParent, oDescendant) => - { - if (oParent && oDescendant) - { - if (oParent === oDescendant) - { - return true; - } - if (oParent.contains) - { - return oParent.contains(oDescendant); - } - /*jshint bitwise: false*/ - return oDescendant.compareDocumentPosition ? - !!(oDescendant.compareDocumentPosition(oParent) & 8) : false; - /*jshint bitwise: true*/ - } - - return false; - }, - - mainClearTimeout : iTimer => - { - if (0 < iTimer) - { - clearTimeout(iTimer); - } - - iTimer = 0; - }, - - /** - * @param {Event} oEvent - * @return {?Event} - */ - getEvent : oEvent => - { - oEvent = (oEvent && (oEvent.originalEvent ? - oEvent.originalEvent : oEvent)) || window.event; - - return oEvent.dataTransfer ? oEvent : null; + addEventListeners = (element, obj) => { + Object.entries(obj).forEach(([key, value]) => element.addEventListener(key, value)); }, + Utils = { /** * @param {Object} oValues * @param {string} sKey @@ -122,28 +55,13 @@ */ getValue : (oValues, sKey, mDefault) => (!oValues || !sKey || !defined(oValues[sKey])) ? mDefault : oValues[sKey], - /** - * @param {Function} fFunction - * @param {Object=} oScope - * @return {Function} - */ - scopeBind : (fFunction, oScope) => (...args) => { - return fFunction.apply(defined(oScope) ? oScope : null, - Array.prototype.slice.call(args)); - }, - - /** - * @return {string} - */ - getNewUid : () => 'jua-uid-' + fakeMd5(16) + '-' + (new Date()).getTime().toString(), - /** * @param {*} oFile * @return {Object} */ getDataFromFile : oFile => { - var + let sFileName = defined(oFile.fileName) ? oFile.fileName : (defined(oFile.name) ? oFile.name : null), iSize = defined(oFile.fileSize) ? oFile.fileSize : (defined(oFile.size) ? oFile.size : null), sType = defined(oFile.type) ? oFile.type : null @@ -168,116 +86,18 @@ }; }, - /** - * @param {*} oInput - * @param {Function} fFileCallback - * @param {number=} iLimit = 20 - * @param {Function=} fLimitCallback - */ - getDataFromInput : (oInput, fFileCallback, iLimit, fLimitCallback) => - { - var aFiles = oInput && 0 < oInput.files.length ? oInput.files : null; - if (aFiles) - { - getDataFromFiles(aFiles, fFileCallback, iLimit, fLimitCallback); - } - else - { - fFileCallback({ - 'FileName': oInput.value.split('\\').pop().split('/').pop(), - 'Size': null, - 'Type': null, - 'Folder': '', - 'File' : null - }); - } - }, - eventContainsFiles : oEvent => { - var bResult = false; - if (oEvent && oEvent.dataTransfer && oEvent.dataTransfer.types && oEvent.dataTransfer.types.length) - { - var - iIindex = 0, - iLen = oEvent.dataTransfer.types.length - ; - - for (; iIindex < iLen; iIindex++) - { - if (oEvent.dataTransfer.types[iIindex].toLowerCase() === 'files') - { - bResult = true; - break; + if (oEvent.dataTransfer && oEvent.dataTransfer.types && oEvent.dataTransfer.types.length) { + let index = oEvent.dataTransfer.types.length; + while (index--) { + if (oEvent.dataTransfer.types[index].toLowerCase() === 'files') { + return true; } } } - - return bResult; - }, - - /** - * @param {Event} oEvent - * @param {Function} fFileCallback - * @param {number=} iLimit = 20 - * @param {Function=} fLimitCallback - */ - getDataFromDragEvent : (oEvent, fFileCallback, iLimit, fLimitCallback) => - { - var aFiles = null; - - oEvent = Utils.getEvent(oEvent); - if (oEvent && Utils.eventContainsFiles(oEvent)) - { - aFiles = (Utils.getValue(oEvent, 'files', null) || (oEvent.dataTransfer ? - Utils.getValue(oEvent.dataTransfer, 'files', null) : null)); - - getDataFromFiles(aFiles, fFileCallback, iLimit, fLimitCallback); - } - }, - - createNextLabel : () => - { - return $('').css({ - 'opacity': 0 - }); - }, - - createNextInput : () => $(''), - - /** - * @param {string=} sName - * @param {boolean=} bMultiple = true - * @return {?Object} - */ - getNewInput : (sName, bMultiple) => - { - sName = defined(sName) ? sName.toString() : ''; - - var oLocal = Utils.createNextInput(); - if (0 < sName.length) - { - oLocal.attr('name', sName); - } - - if (defined(bMultiple) ? bMultiple : true) - { - oLocal.prop('multiple', true); - } - - return oLocal; - }, - - /** - * @param {?} mStringOrFunction - * @param {Array=} aFunctionParams - * @return {string} - */ - getStringOrCallFunction : (mStringOrFunction, aFunctionParams) => $.isFunction(mStringOrFunction) ? - mStringOrFunction.apply(null, Array.isArray(aFunctionParams) ? aFunctionParams : []).toString() : - mStringOrFunction.toString() + return false; + } }; @@ -319,7 +139,7 @@ try { - var + const self = this, oXhr = new XMLHttpRequest(), oFormData = new FormData(), @@ -347,7 +167,7 @@ { if (fCompleteFunction) { - var + let bResult = false, oResult = null ; @@ -389,9 +209,9 @@ oFormData.append('jua-post-type', 'ajax'); oFormData.append(Utils.getValue(this.oOptions, 'name', 'juaFile'), oFileInfo['File']); - $.each(aHidden, function (sKey, sValue) { - oFormData.append(sKey, Utils.getStringOrCallFunction(sValue, [oFileInfo])); - }); + Object.entries(aHidden).forEach(([key, value]) => + oFormData.append(key, (typeof value === "function" ? value(oFileInfo) : value).toString()) + ); oXhr.send(oFormData); @@ -408,40 +228,43 @@ generateNewInput(oClickElement) { - var - self = this, - oLabel = null, - oInput = null - ; - if (oClickElement) { - oInput = Utils.getNewInput('', !Utils.getValue(this.oOptions, 'disableMultiple', false)); - oLabel = Utils.createNextLabel(); - oLabel.append(oInput); + const self = this, + oLabel = doc.createElement('label'), + oInput = oLabel.appendChild(doc.createElement('input')); - $(oClickElement).append(oLabel); + oInput.type = 'file'; + oInput.tabIndex = -1; + oInput.style.cssText = 'position:absolute;left:-9999px;'; + oInput.multiple = !Utils.getValue(self.oOptions, 'disableMultiple', false); - oInput - .on('click', function () { - var fOn = self.oJua.getEvent('onDialog'); - if (fOn) - { - fOn(); - } - }) - .on('change', function () { - Utils.getDataFromInput(this, oFile => { - self.oJua.addNewFile(oFile); - self.generateNewInput(oClickElement); + oLabel.style.cssText = 'position:absolute;background-color:#fff;right:0;top:0;left:0;bottom:0;margin:0;padding:0;cursor:pointer;opacity:0'; - setTimeout(() => oLabel.remove(), 10); - }, + oClickElement.append(oLabel); + + oInput.addEventListener('input', () => { + const fFileCallback = oFile => { + self.oJua.addNewFile(oFile); + self.generateNewInput(oClickElement); + + setTimeout(() => oLabel.remove(), 10); + }; + if (oInput.files && oInput.files.length) { + getDataFromFiles(oInput.files, fFileCallback, Utils.getValue(self.oOptions, 'multipleSizeLimit', iDefLimit), self.oJua.getEvent('onLimitReached') ); - }) - ; + } else { + fFileCallback({ + 'FileName': oInput.value.split('\\').pop().split('/').pop(), + 'Size': null, + 'Type': null, + 'Folder': '', + 'File' : null + }); + } + }); } } @@ -490,7 +313,7 @@ function queue(a) { function l() { if (g && d < a) { - var b = g, + let b = g, c = b[0], f = Array.prototype.slice.call(b, 1), m = b.index; @@ -502,7 +325,7 @@ c.apply(null, f) } } - var c = {}, + let c = {}, d = 0, e = 0, f = -1, @@ -511,7 +334,7 @@ k = ()=>{}; return arguments.length < 1 && (a = Infinity), c.defer = function () { if (!i) { - var a = arguments; + let a = arguments; a.index = ++f, h ? (h.next = a, h = h.next) : g = h = a, ++e, l() } return c @@ -530,251 +353,159 @@ { oOptions = defined(oOptions) ? oOptions : {}; - var - self = this, - - $ = jQuery - ; - - self.bEnableDnD = true; + const self = this; self.oEvents = { - 'onDialog': null, - 'onSelect': null, - 'onStart': null, - 'onComplete': null, - 'onCompleteAll': null, - 'onProgress': null, - 'onDragEnter': null, - 'onDragLeave': null, - 'onDrop': null, - 'onBodyDragEnter': null, - 'onBodyDragLeave': null, - 'onLimitReached': null + onSelect: null, + onStart: null, + onComplete: null, + onProgress: null, + onDragEnter: null, + onDragLeave: null, + onBodyDragEnter: null, + onBodyDragLeave: null, + onLimitReached: null }; self.oOptions = { - 'action': '', - 'name': '', - 'hidden': {}, - 'queueSize': 10, - 'clickElement': false, - 'dragAndDropElement': false, - 'dragAndDropBodyElement': false, - 'disableDragAndDrop': false, - 'disableMultiple': false, - 'disableDocumentDropPrevent': false, - 'multipleSizeLimit': 50 + action: '', + name: '', + hidden: {}, + queueSize: 10, + clickElement: false, + dragAndDropElement: false, + dragAndDropBodyElement: false, + disableMultiple: false, + disableDocumentDropPrevent: false, + multipleSizeLimit: 50 }; - Object.entries(oOptions).forEach(([key, value])=>self.oOptions[key]=value); + Object.entries(oOptions).forEach(([key, value]) => self.oOptions[key] = value); self.oQueue = queue(parseInt(Utils.getValue(self.oOptions, 'queueSize', 10) || 0, 10)); - if (self.runEvent('onCompleteAll')) - { - self.oQueue.await(function () { - self.runEvent('onCompleteAll'); - }); - } self.oDriver = new AjaxDriver(self, self.oOptions); - self.oClickElement = Utils.getValue(self.oOptions, 'clickElement', null); - - if (self.oClickElement) - { - $(self.oClickElement).css({ - 'position': 'relative', - 'overflow': 'hidden' - }); - - if ('inline' === $(this.oClickElement).css('display')) - { - $(this.oClickElement).css('display', 'inline-block'); + const el = Utils.getValue(self.oOptions, 'clickElement', null); + if (el) { + el.style.position = 'relative'; + el.style.overflow = 'hidden'; + if ('inline' === el.style.display) { + el.style.display = 'inline-block'; } - this.oDriver.generateNewInput(this.oClickElement); + this.oDriver.generateNewInput(el); } if (Utils.getValue(this.oOptions, 'dragAndDropElement', false)) { - (function (self) { - var - $doc = $(document), - oBigDropZone = $(Utils.getValue(self.oOptions, 'dragAndDropBodyElement', false) || $doc), - oDragAndDropElement = Utils.getValue(self.oOptions, 'dragAndDropElement', false), - fHandleDragOver = function (oEvent) { - if (self.bEnableDnD && oEvent) + let + oBigDropZone = Utils.getValue(self.oOptions, 'dragAndDropBodyElement', false) || doc, + oDragAndDropElement = Utils.getValue(self.oOptions, 'dragAndDropElement', false); + + if (oDragAndDropElement) + { + if (!Utils.getValue(self.oOptions, 'disableDocumentDropPrevent', false)) + { + doc.addEventListener('dragover', oEvent => { + if (Utils.eventContainsFiles(oEvent)) { - oEvent = Utils.getEvent(oEvent); - if (oEvent && oEvent.dataTransfer && Utils.eventContainsFiles(oEvent)) + try { - try - { - var sEffect = oEvent.dataTransfer.effectAllowed; + oEvent.dataTransfer.dropEffect = 'none'; + oEvent.preventDefault(); + } + catch (oExc) {} + } + }); + } - Utils.mainClearTimeout(self.iDocTimer); + if (oBigDropZone) + { + addEventListeners(oBigDropZone, { + dragover: () => self.docTimer.clear(), + dragenter: oEvent => { + if (Utils.eventContainsFiles(oEvent)) + { + self.docTimer.clear(); + oEvent.preventDefault(); - oEvent.dataTransfer.dropEffect = (sEffect === 'move' || sEffect === 'linkMove') ? 'move' : 'copy'; + self.runEvent('onBodyDragEnter', [oEvent]); + } + }, + dragleave: oEvent => + oEvent.dataTransfer && self.docTimer.start(() => self.runEvent('onBodyDragLeave', [oEvent])), + drop: oEvent => { + if (oEvent.dataTransfer) { + let bFiles = Utils.eventContainsFiles(oEvent); + bFiles && oEvent.preventDefault(); - oEvent.stopPropagation(); - oEvent.preventDefault(); + self.runEvent('onBodyDragLeave', [oEvent]); - oBigDropZone.trigger('dragover', oEvent); - } - catch (oExc) {} + return !bFiles; + } + + return false; + } + }); + } + + addEventListeners(oDragAndDropElement, { + dragenter: oEvent => { + if (Utils.eventContainsFiles(oEvent)) { + self.docTimer.clear(); + + oEvent.preventDefault(); + self.runEvent('onDragEnter', [oDragAndDropElement, oEvent]); + } + }, + dragover: oEvent => { + if (Utils.eventContainsFiles(oEvent)) { + try + { + let sEffect = oEvent.dataTransfer.effectAllowed; + + self.docTimer.clear(); + + oEvent.dataTransfer.dropEffect = (sEffect === 'move' || sEffect === 'linkMove') ? 'move' : 'copy'; + + oEvent.stopPropagation(); + oEvent.preventDefault(); + + oBigDropZone && oBigDropZone.dispatchEvent(oEvent); + } + catch (oExc) {} + } + }, + dragleave: oEvent => { + if (oEvent.dataTransfer) { + let oRelatedTarget = doc.elementFromPoint(oEvent.clientX, oEvent.clientY); + if (!oRelatedTarget || !oDragAndDropElement.contains(oRelatedTarget)) { + self.docTimer.clear(); + self.runEvent('onDragLeave', [oDragAndDropElement, oEvent]); } } }, - fHandleDrop = function (oEvent) { - if (self.bEnableDnD && oEvent) - { - oEvent = Utils.getEvent(oEvent); - if (oEvent && Utils.eventContainsFiles(oEvent)) - { - oEvent.preventDefault(); + drop: oEvent => { + if (Utils.eventContainsFiles(oEvent)) { + oEvent.preventDefault(); - Utils.getDataFromDragEvent(oEvent, function (oFile) { - if (oFile) - { - self.runEvent('onDrop', [oFile, oEvent]); - self.addNewFile(oFile); - Utils.mainClearTimeout(self.iDocTimer); - } - }, - Utils.getValue(self.oOptions, 'multipleSizeLimit', iDefLimit), - self.getEvent('onLimitReached') - ); - } + getDataFromFiles( + Utils.getValue(oEvent, 'files', null) || Utils.getValue(oEvent.dataTransfer, 'files', null), + oFile => { + if (oFile) { + self.addNewFile(oFile); + self.docTimer.clear(); + } + }, + Utils.getValue(self.oOptions, 'multipleSizeLimit', iDefLimit), + self.getEvent('onLimitReached') + ); } self.runEvent('onDragLeave', [oEvent]); - }, - fHandleDragEnter = function (oEvent) { - if (self.bEnableDnD && oEvent) - { - oEvent = Utils.getEvent(oEvent); - if (oEvent && Utils.eventContainsFiles(oEvent)) - { - Utils.mainClearTimeout(self.iDocTimer); - - oEvent.preventDefault(); - self.runEvent('onDragEnter', [oDragAndDropElement, oEvent]); - } - } - }, - fHandleDragLeave = function (oEvent) { - if (self.bEnableDnD && oEvent) - { - oEvent = Utils.getEvent(oEvent); - if (oEvent) - { - var oRelatedTarget = document['elementFromPoint'] ? document['elementFromPoint'](oEvent['clientX'], oEvent['clientY']) : null; - if (oRelatedTarget && Utils.contains(this, oRelatedTarget)) - { - return; - } - - Utils.mainClearTimeout(self.iDocTimer); - self.runEvent('onDragLeave', [oDragAndDropElement, oEvent]); - } - - return; - } } - ; - - if (oDragAndDropElement) - { - if (!Utils.getValue(self.oOptions, 'disableDocumentDropPrevent', false)) - { - $doc.on('dragover', function (oEvent) { - if (self.bEnableDnD && oEvent) - { - oEvent = Utils.getEvent(oEvent); - if (oEvent && oEvent.dataTransfer && Utils.eventContainsFiles(oEvent)) - { - try - { - oEvent.dataTransfer.dropEffect = 'none'; - oEvent.preventDefault(); - } - catch (oExc) {} - } - } - }); - } - - if (oBigDropZone && oBigDropZone[0]) - { - oBigDropZone - .on('dragover', function (oEvent) { - if (self.bEnableDnD && oEvent) - { - Utils.mainClearTimeout(self.iDocTimer); - } - }) - .on('dragenter', function (oEvent) { - if (self.bEnableDnD && oEvent) - { - oEvent = Utils.getEvent(oEvent); - if (oEvent && Utils.eventContainsFiles(oEvent)) - { - Utils.mainClearTimeout(self.iDocTimer); - oEvent.preventDefault(); - - self.runEvent('onBodyDragEnter', [oEvent]); - } - } - }) - .on('dragleave', function (oEvent) { - if (self.bEnableDnD && oEvent) - { - oEvent = Utils.getEvent(oEvent); - if (oEvent) - { - Utils.mainClearTimeout(self.iDocTimer); - self.iDocTimer = setTimeout(function () { - self.runEvent('onBodyDragLeave', [oEvent]); - }, 200); - } - } - }) - .on('drop', function (oEvent) { - if (self.bEnableDnD && oEvent) - { - oEvent = Utils.getEvent(oEvent); - if (oEvent) - { - var bFiles = Utils.eventContainsFiles(oEvent); - if (bFiles) - { - oEvent.preventDefault(); - } - - self.runEvent('onBodyDragLeave', [oEvent]); - - return !bFiles; - } - } - - return false; - }) - ; - } - - $(oDragAndDropElement) - .on('dragenter', fHandleDragEnter) - .on('dragover', fHandleDragOver) - .on('dragleave', fHandleDragLeave) - .on('drop', fHandleDrop) - ; - } - - }(self)); - } - else - { - self.bEnableDnD = false; + }); + } } } @@ -816,20 +547,19 @@ this.oDriver.cancel(sUid); } - /** - * @param {boolean} bEnabled - */ - setDragAndDropEnabledStatus(bEnabled) - { - this.bEnableDnD = !!bEnabled; - } - /** * @param {Object} oFileInfo */ addNewFile(oFileInfo) { - this.addFile(Utils.getNewUid(), oFileInfo); + let iLen = 16, + fakeMd5 = '', + sLine = '0123456789abcdefghijklmnopqrstuvwxyz'; + + while (iLen--) + fakeMd5 += sLine.substr(Math.round(Math.random() * 36), 1); + + this.addFile('jua-uid-' + fakeMd5 + '-' + (new Date()).getTime().toString(), oFileInfo); } /** @@ -838,11 +568,11 @@ */ addFile(sUid, oFileInfo) { - var fOnSelect = this.getEvent('onSelect'); + const fOnSelect = this.getEvent('onSelect'); if (oFileInfo && (!fOnSelect || (false !== fOnSelect(sUid, oFileInfo)))) { this.oDriver.regTaskUid(sUid); - this.oQueue.defer(Utils.scopeBind(this.oDriver.uploadTask, this.oDriver), sUid, oFileInfo); + this.oQueue.defer((...args) => this.oDriver.uploadTask(...args), sUid, oFileInfo); } else { @@ -851,15 +581,19 @@ } } - /** - * @type {boolean} - */ - Jua.prototype.bEnableDnD = true; - /** * @type {number} */ - Jua.prototype.iDocTimer = 0; + Jua.prototype.docTimer = { + start: function(fn){ + this.clear(); + this.timer = setTimeout(fn, 200); + }, + clear: function(){ + this.timer && clearTimeout(this.timer); + this.timer = 0; + } + }; /** * @type {Object} diff --git a/vendors/jua/jua.min.js b/vendors/jua/jua.min.js index 45e1022fb..54fc3fef9 100644 --- a/vendors/jua/jua.min.js +++ b/vendors/jua/jua.min.js @@ -1,2 +1,2 @@ /* RainLoop Webmail (c) RainLoop Team | MIT */ -(()=>{"use strict";var e=20,t=jQuery;const n=e=>void 0!==e,o=(t,o,i,r)=>{if(t&&t.length){var l,u,s=null,p=!1;i=n(i)?parseInt(i||0,10):e,l=i,u=0{e&&(!u||0<=--i?(s=a.getDataFromFile(e))&&o(s):u&&!p&&0>i&&r&&(p=!0,r(l)))})}};var a={contains:(e,t)=>!(!e||!t)&&(e===t||(e.contains?e.contains(t):!!t.compareDocumentPosition&&!!(8&t.compareDocumentPosition(e)))),mainClearTimeout:e=>{0(e=e&&(e.originalEvent?e.originalEvent:e)||window.event).dataTransfer?e:null,getValue:(e,t,o)=>e&&t&&n(e[t])?e[t]:o,scopeBind:(e,t)=>(...o)=>e.apply(n(t)?t:null,Array.prototype.slice.call(o)),getNewUid:()=>"jua-uid-"+(e=>{var t="";for(e=n(e)?parseInt(e||0,10):32;e--;)t+="0123456789abcdefghijklmnopqrstuvwxyz".substr(Math.round(36*Math.random()),1);return t})(16)+"-"+(new Date).getTime().toString(),getDataFromFile:e=>{var t=n(e.fileName)?e.fileName:n(e.name)?e.name:null,o=n(e.fileSize)?e.fileSize:n(e.size)?e.size:null,a=n(e.type)?e.type:null;return"/"===t.charAt(0)&&(t=t.substr(1)),a||0!==o?{FileName:t,Size:o,Type:a,Folder:"",File:e}:null},getDataFromInput:(e,t,n,a)=>{var i=e&&0{var t=!1;if(e&&e.dataTransfer&&e.dataTransfer.types&&e.dataTransfer.types.length)for(var n=0,o=e.dataTransfer.types.length;n{var r=null;(e=a.getEvent(e))&&a.eventContainsFiles(e)&&(r=a.getValue(e,"files",null)||(e.dataTransfer?a.getValue(e.dataTransfer,"files",null):null),o(r,t,n,i))},createNextLabel:()=>t('').css({opacity:0}),createNextInput:()=>t(''),getNewInput:(e,t)=>{e=n(e)?e.toString():"";var o=a.createNextInput();return 0t.isFunction(e)?e.apply(null,Array.isArray(n)?n:[]).toString():e.toString()};class i{constructor(e,t){this.oXhrs={},this.oUids={},this.oJua=e,this.oOptions=t}regTaskUid(e){this.oUids[e]=!0}uploadTask(e,o,i){if(!1===this.oUids[e]||!o||!o.File)return i(null,e),!1;try{var r=this,l=new XMLHttpRequest,u=new FormData,s=a.getValue(this.oOptions,"action",""),p=a.getValue(this.oOptions,"hidden",{}),c=this.oJua.getEvent("onStart"),d=this.oJua.getEvent("onComplete"),g=this.oJua.getEvent("onProgress");return l.open("POST",s,!0),g&&l.upload&&(l.upload.onprogress=function(t){t&&t.lengthComputable&&n(t.loaded)&&n(t.total)&&g(e,t.loaded,t.total)}),l.onreadystatechange=function(){if(4===l.readyState&&200===l.status){if(d){var t=!1,o=null;try{o=JSON.parse(l.responseText),t=!0}catch(e){o=null}d(e,t,o)}n(r.oXhrs[e])&&(r.oXhrs[e]=null),i(null,e)}else 4===l.readyState&&(d(e,!1,null),i(null,e))},c&&c(e),u.append("jua-post-type","ajax"),u.append(a.getValue(this.oOptions,"name","juaFile"),o.File),t.each(p,function(e,t){u.append(e,a.getStringOrCallFunction(t,[o]))}),l.send(u),this.oXhrs[e]=l,!0}catch(e){}return i(null,e),!1}generateNewInput(n){var o=this,i=null,r=null;n&&(r=a.getNewInput("",!a.getValue(this.oOptions,"disableMultiple",!1)),(i=a.createNextLabel()).append(r),t(n).append(i),r.on("click",function(){var e=o.oJua.getEvent("onDialog");e&&e()}).on("change",function(){a.getDataFromInput(this,e=>{o.oJua.addNewFile(e),o.generateNewInput(n),setTimeout(()=>i.remove(),10)},a.getValue(o.oOptions,"multipleSizeLimit",e),o.oJua.getEvent("onLimitReached"))}))}cancel(e){if(this.oUids[e]=!1,this.oXhrs[e]){try{this.oXhrs[e].abort&&this.oXhrs[e].abort()}catch(e){}this.oXhrs[e]=null}}}i.prototype.oXhrs={},i.prototype.oUids={},i.prototype.oJua=null,i.prototype.oOptions={};class r{constructor(t){t=n(t)?t:{};var o=this,r=jQuery;o.bEnableDnD=!0,o.oEvents={onDialog:null,onSelect:null,onStart:null,onComplete:null,onCompleteAll:null,onProgress:null,onDragEnter:null,onDragLeave:null,onDrop:null,onBodyDragEnter:null,onBodyDragLeave:null,onLimitReached:null},o.oOptions={action:"",name:"",hidden:{},queueSize:10,clickElement:!1,dragAndDropElement:!1,dragAndDropBodyElement:!1,disableDragAndDrop:!1,disableMultiple:!1,disableDocumentDropPrevent:!1,multipleSizeLimit:50},Object.entries(t).forEach(([e,t])=>o.oOptions[e]=t),o.oQueue=function(e){function t(){if(n&&i{};return arguments.length<1&&(e=1/0),a.defer=function(){if(!u){var e=arguments;e.index=++l,o?(o.next=e,o=o.next):n=o=e,++r,t()}return a},a.await=function(e){return p=e,r||p(u,s),a},a}(parseInt(a.getValue(o.oOptions,"queueSize",10)||0,10)),o.runEvent("onCompleteAll")&&o.oQueue.await(function(){o.runEvent("onCompleteAll")}),o.oDriver=new i(o,o.oOptions),o.oClickElement=a.getValue(o.oOptions,"clickElement",null),o.oClickElement&&(r(o.oClickElement).css({position:"relative",overflow:"hidden"}),"inline"===r(this.oClickElement).css("display")&&r(this.oClickElement).css("display","inline-block"),this.oDriver.generateNewInput(this.oClickElement)),a.getValue(this.oOptions,"dragAndDropElement",!1)?function(t){var n=r(document),o=r(a.getValue(t.oOptions,"dragAndDropBodyElement",!1)||n),i=a.getValue(t.oOptions,"dragAndDropElement",!1);i&&(a.getValue(t.oOptions,"disableDocumentDropPrevent",!1)||n.on("dragover",function(e){if(t.bEnableDnD&&e&&(e=a.getEvent(e))&&e.dataTransfer&&a.eventContainsFiles(e))try{e.dataTransfer.dropEffect="none",e.preventDefault()}catch(e){}}),o&&o[0]&&o.on("dragover",function(e){t.bEnableDnD&&e&&a.mainClearTimeout(t.iDocTimer)}).on("dragenter",function(e){t.bEnableDnD&&e&&(e=a.getEvent(e))&&a.eventContainsFiles(e)&&(a.mainClearTimeout(t.iDocTimer),e.preventDefault(),t.runEvent("onBodyDragEnter",[e]))}).on("dragleave",function(e){t.bEnableDnD&&e&&(e=a.getEvent(e))&&(a.mainClearTimeout(t.iDocTimer),t.iDocTimer=setTimeout(function(){t.runEvent("onBodyDragLeave",[e])},200))}).on("drop",function(e){if(t.bEnableDnD&&e&&(e=a.getEvent(e))){var n=a.eventContainsFiles(e);return n&&e.preventDefault(),t.runEvent("onBodyDragLeave",[e]),!n}return!1}),r(i).on("dragenter",function(e){t.bEnableDnD&&e&&(e=a.getEvent(e))&&a.eventContainsFiles(e)&&(a.mainClearTimeout(t.iDocTimer),e.preventDefault(),t.runEvent("onDragEnter",[i,e]))}).on("dragover",function(e){if(t.bEnableDnD&&e&&(e=a.getEvent(e))&&e.dataTransfer&&a.eventContainsFiles(e))try{var n=e.dataTransfer.effectAllowed;a.mainClearTimeout(t.iDocTimer),e.dataTransfer.dropEffect="move"===n||"linkMove"===n?"move":"copy",e.stopPropagation(),e.preventDefault(),o.trigger("dragover",e)}catch(e){}}).on("dragleave",function(e){if(t.bEnableDnD&&e&&(e=a.getEvent(e))){var n=document.elementFromPoint?document.elementFromPoint(e.clientX,e.clientY):null;if(n&&a.contains(this,n))return;a.mainClearTimeout(t.iDocTimer),t.runEvent("onDragLeave",[i,e])}}).on("drop",function(n){t.bEnableDnD&&n&&(n=a.getEvent(n))&&a.eventContainsFiles(n)&&(n.preventDefault(),a.getDataFromDragEvent(n,function(e){e&&(t.runEvent("onDrop",[e,n]),t.addNewFile(e),a.mainClearTimeout(t.iDocTimer))},a.getValue(t.oOptions,"multipleSizeLimit",e),t.getEvent("onLimitReached"))),t.runEvent("onDragLeave",[n])}))}(o):o.bEnableDnD=!1}on(e,t){return this.oEvents[e]=t,this}runEvent(e,t){this.oEvents[e]&&this.oEvents[e].apply(null,t||[])}getEvent(e){return this.oEvents[e]||null}cancel(e){this.oDriver.cancel(e)}setDragAndDropEnabledStatus(e){this.bEnableDnD=!!e}addNewFile(e){this.addFile(a.getNewUid(),e)}addFile(e,t){var n=this.getEvent("onSelect");!t||n&&!1===n(e,t)?this.oDriver.cancel(e):(this.oDriver.regTaskUid(e),this.oQueue.defer(a.scopeBind(this.oDriver.uploadTask,this.oDriver),e,t))}}r.prototype.bEnableDnD=!0,r.prototype.iDocTimer=0,r.prototype.oOptions={},r.prototype.oEvents={},r.prototype.oQueue=null,r.prototype.oDriver=null,window.Jua=r})(); +(()=>{"use strict";const e=document,t=20,n=e=>void 0!==e,o=(e,o,l,i)=>{if(e&&e.length){let a=l=n(l)?parseInt(l||0,10):t,s=null,u=0{e&&(!u||0<=--l?(s=r.getDataFromFile(e))&&o(s):u&&!p&&0>l&&i&&(p=!0,i(a)))})}},l=(e,t)=>{Object.entries(t).forEach(([t,n])=>e.addEventListener(t,n))},r={getValue:(e,t,o)=>e&&t&&n(e[t])?e[t]:o,getDataFromFile:e=>{let t=n(e.fileName)?e.fileName:n(e.name)?e.name:null,o=n(e.fileSize)?e.fileSize:n(e.size)?e.size:null,l=n(e.type)?e.type:null;return"/"===t.charAt(0)&&(t=t.substr(1)),l||0!==o?{FileName:t,Size:o,Type:l,Folder:"",File:e}:null},eventContainsFiles:e=>{if(e.dataTransfer&&e.dataTransfer.types&&e.dataTransfer.types.length){let t=e.dataTransfer.types.length;for(;t--;)if("files"===e.dataTransfer.types[t].toLowerCase())return!0}return!1}};class i{constructor(e,t){this.oXhrs={},this.oUids={},this.oJua=e,this.oOptions=t}regTaskUid(e){this.oUids[e]=!0}uploadTask(e,t,o){if(!1===this.oUids[e]||!t||!t.File)return o(null,e),!1;try{const l=this,i=new XMLHttpRequest,a=new FormData,s=r.getValue(this.oOptions,"action",""),u=r.getValue(this.oOptions,"hidden",{}),p=this.oJua.getEvent("onStart"),d=this.oJua.getEvent("onComplete"),c=this.oJua.getEvent("onProgress");return i.open("POST",s,!0),c&&i.upload&&(i.upload.onprogress=function(t){t&&t.lengthComputable&&n(t.loaded)&&n(t.total)&&c(e,t.loaded,t.total)}),i.onreadystatechange=function(){if(4===i.readyState&&200===i.status){if(d){let t=!1,n=null;try{n=JSON.parse(i.responseText),t=!0}catch(e){n=null}d(e,t,n)}n(l.oXhrs[e])&&(l.oXhrs[e]=null),o(null,e)}else 4===i.readyState&&(d(e,!1,null),o(null,e))},p&&p(e),a.append("jua-post-type","ajax"),a.append(r.getValue(this.oOptions,"name","juaFile"),t.File),Object.entries(u).forEach(([e,n])=>a.append(e,("function"==typeof n?n(t):n).toString())),i.send(a),this.oXhrs[e]=i,!0}catch(e){}return o(null,e),!1}generateNewInput(n){if(n){const l=this,i=e.createElement("label"),a=i.appendChild(e.createElement("input"));a.type="file",a.tabIndex=-1,a.style.cssText="position:absolute;left:-9999px;",a.multiple=!r.getValue(l.oOptions,"disableMultiple",!1),i.style.cssText="position:absolute;background-color:#fff;right:0;top:0;left:0;bottom:0;margin:0;padding:0;cursor:pointer;opacity:0",n.append(i),a.addEventListener("input",()=>{const e=e=>{l.oJua.addNewFile(e),l.generateNewInput(n),setTimeout(()=>i.remove(),10)};a.files&&a.files.length?o(a.files,e,r.getValue(l.oOptions,"multipleSizeLimit",t),l.oJua.getEvent("onLimitReached")):e({FileName:a.value.split("\\").pop().split("/").pop(),Size:null,Type:null,Folder:"",File:null})})}}cancel(e){if(this.oUids[e]=!1,this.oXhrs[e]){try{this.oXhrs[e].abort&&this.oXhrs[e].abort()}catch(e){}this.oXhrs[e]=null}}}function a(e){let t,n,o={},l=0,r=0,i=-1,a=null,s=[],u=()=>{};return arguments.length<1&&(e=1/0),o.defer=function(){if(!a){let e=arguments;e.index=++i,n?(n.next=e,n=n.next):t=n=e,++r,function o(){if(t&&lu.oOptions[e]=t),u.oQueue=a(parseInt(r.getValue(u.oOptions,"queueSize",10)||0,10)),u.oDriver=new i(u,u.oOptions);const p=r.getValue(u.oOptions,"clickElement",null);if(p&&(p.style.position="relative",p.style.overflow="hidden","inline"===p.style.display&&(p.style.display="inline-block"),this.oDriver.generateNewInput(p)),r.getValue(this.oOptions,"dragAndDropElement",!1)){let n=r.getValue(u.oOptions,"dragAndDropBodyElement",!1)||e,i=r.getValue(u.oOptions,"dragAndDropElement",!1);i&&(r.getValue(u.oOptions,"disableDocumentDropPrevent",!1)||e.addEventListener("dragover",e=>{if(r.eventContainsFiles(e))try{e.dataTransfer.dropEffect="none",e.preventDefault()}catch(e){}}),n&&l(n,{dragover:()=>u.docTimer.clear(),dragenter:e=>{r.eventContainsFiles(e)&&(u.docTimer.clear(),e.preventDefault(),u.runEvent("onBodyDragEnter",[e]))},dragleave:e=>e.dataTransfer&&u.docTimer.start(()=>u.runEvent("onBodyDragLeave",[e])),drop:e=>{if(e.dataTransfer){let t=r.eventContainsFiles(e);return t&&e.preventDefault(),u.runEvent("onBodyDragLeave",[e]),!t}return!1}}),l(i,{dragenter:e=>{r.eventContainsFiles(e)&&(u.docTimer.clear(),e.preventDefault(),u.runEvent("onDragEnter",[i,e]))},dragover:e=>{if(r.eventContainsFiles(e))try{let t=e.dataTransfer.effectAllowed;u.docTimer.clear(),e.dataTransfer.dropEffect="move"===t||"linkMove"===t?"move":"copy",e.stopPropagation(),e.preventDefault(),n&&n.dispatchEvent(e)}catch(e){}},dragleave:t=>{if(t.dataTransfer){let n=e.elementFromPoint(t.clientX,t.clientY);n&&i.contains(n)||(u.docTimer.clear(),u.runEvent("onDragLeave",[i,t]))}},drop:e=>{r.eventContainsFiles(e)&&(e.preventDefault(),o(r.getValue(e,"files",null)||r.getValue(e.dataTransfer,"files",null),e=>{e&&(u.addNewFile(e),u.docTimer.clear())},r.getValue(u.oOptions,"multipleSizeLimit",t),u.getEvent("onLimitReached"))),u.runEvent("onDragLeave",[e])}}))}}on(e,t){return this.oEvents[e]=t,this}runEvent(e,t){this.oEvents[e]&&this.oEvents[e].apply(null,t||[])}getEvent(e){return this.oEvents[e]||null}cancel(e){this.oDriver.cancel(e)}addNewFile(e){let t=16,n="";for(;t--;)n+="0123456789abcdefghijklmnopqrstuvwxyz".substr(Math.round(36*Math.random()),1);this.addFile("jua-uid-"+n+"-"+(new Date).getTime().toString(),e)}addFile(e,t){const n=this.getEvent("onSelect");!t||n&&!1===n(e,t)?this.oDriver.cancel(e):(this.oDriver.regTaskUid(e),this.oQueue.defer((...e)=>this.oDriver.uploadTask(...e),e,t))}}s.prototype.docTimer={start:function(e){this.clear(),this.timer=setTimeout(e,200)},clear:function(){this.timer&&clearTimeout(this.timer),this.timer=0}},s.prototype.oOptions={},s.prototype.oEvents={},s.prototype.oQueue=null,s.prototype.oDriver=null,window.Jua=s})();