diff --git a/README.md b/README.md
index b5397166f..96f23bfd6 100644
--- a/README.md
+++ b/README.md
@@ -106,22 +106,22 @@ RainLoop 1.14 vs SnappyMail
|js/* |RainLoop |Snappy |
|----------- |--------: |--------: |
-|admin.js |2.130.942 | 798.252 |
-|app.js |4.184.455 |2.450.286 |
+|admin.js |2.130.942 | 776.615 |
+|app.js |4.184.455 |2.430.639 |
|boot.js | 671.522 | 5.285 |
-|libs.js | 647.614 | 254.910 |
+|libs.js | 647.614 | 255.041 |
|polyfills.js | 325.834 | 0 |
-|TOTAL |7.960.367 |3.508.733 |
+|TOTAL |7.960.367 |3.467.580 |
|js/min/* |RainLoop |Snappy |Rain gzip |gzip |brotli |
|--------------- |--------: |--------: |--------: |--------: |--------: |
-|admin.min.js | 252.147 | 106.871 | 73.657 | 28.834 | 25.063 |
-|app.min.js | 511.202 | 332.055 |140.462 | 85.613 | 69.336 |
+|admin.min.js | 252.147 | 104.046 | 73.657 | 27.739 | 24.058 |
+|app.min.js | 511.202 | 329.887 |140.462 | 84.844 | 68.843 |
|boot.min.js | 66.007 | 2.935 | 22.567 | 1.510 | 1.285 |
-|libs.min.js | 572.545 | 149.580 |176.720 | 52.695 | 46.823 |
+|libs.min.js | 572.545 | 149.712 |176.720 | 52.703 | 46.853 |
|polyfills.min.js | 32.452 | 0 | 11.312 | 0 | 0 |
-|TOTAL |1.434.353 | 591.441 |424.718 |168.652 |142.507 |
-|TOTAL (no admin) |1.182.206 | 484.570 |351.061 |139.818 |117.444 |
+|TOTAL |1.434.353 | 586.580 |424.718 |166.796 |141.039 |
+|TOTAL (no admin) |1.182.206 | 482.534 |351.061 |139.057 |116.981 |
For a user its around 60% smaller and faster than traditional RainLoop.
diff --git a/dev/App/Admin.js b/dev/App/Admin.js
index 5ae00477b..f54b4ab47 100644
--- a/dev/App/Admin.js
+++ b/dev/App/Admin.js
@@ -82,7 +82,7 @@ class AdminApp extends AbstractApp {
return 'core' === item.type && !item.canBeInstalled ? null : item;
}
return null;
- }).filter(value => !!value);
+ }).filter(v => v);
}
PackageStore.packages(list);
diff --git a/dev/App/User.js b/dev/App/User.js
index f66ff4a2f..c45557e76 100644
--- a/dev/App/User.js
+++ b/dev/App/User.js
@@ -255,8 +255,7 @@ class AppUser extends AbstractApp {
};
}
- this.moveCache[hash].Uid = this.moveCache[hash].Uid.concat(uidsForMove)
- .filter((value, index, self) => self.indexOf(value) == index);
+ this.moveCache[hash].Uid = this.moveCache[hash].Uid.concat(uidsForMove).unique();
this.messagesMoveTrigger();
}
@@ -457,7 +456,7 @@ class AppUser extends AbstractApp {
.toLowerCase(),
oItem.getKeyIds()
.map(item => (item && item.toHex ? item.toHex() : null))
- .filter((value, index, self) => !!value && self.indexOf(value) == index),
+ .validUnique(),
aUsers,
aEmails,
oItem.isPrivate(),
@@ -537,7 +536,7 @@ class AppUser extends AbstractApp {
data.Result.Templates.map(templateData => {
const template = new TemplateModel();
return template.parse(templateData) ? template : null;
- }).filter(value => !!value)
+ }).filter(v => v)
);
}
});
@@ -718,7 +717,7 @@ class AppUser extends AbstractApp {
}
rootUids = messages.map(oMessage => oMessage && oMessage.uid ? oMessage.uid : null)
- .filter((value, index, self) => !!value && self.indexOf(value) == index);
+ .validUnique();
if (sFolderFullNameRaw && rootUids.length) {
switch (iSetAction) {
@@ -779,7 +778,7 @@ class AppUser extends AbstractApp {
Remote.suggestions((result, data) => {
if (StorageResultType.Success === result && data && Array.isArray(data.Result)) {
autocompleteCallback(
- data.Result.map(item => (item && item[0] ? new EmailModel(item[0], item[1]) : null)).filter(value => !!value)
+ data.Result.map(item => (item && item[0] ? new EmailModel(item[0], item[1]) : null)).filter(v => v)
);
} else if (StorageResultType.Abort !== result) {
autocompleteCallback([]);
diff --git a/dev/Common/File.js b/dev/Common/File.js
index e7b45a835..2e41449a0 100644
--- a/dev/Common/File.js
+++ b/dev/Common/File.js
@@ -301,7 +301,7 @@ export const File = {
if (Array.isNotEmpty(data)) {
let icons = data
.map(item => item ? File.getIconClass(File.getExtension(item[0]), item[1])[0] : '')
- .filter((value, index, self) => value && self.indexOf(value) == index);
+ .validUnique();
return (icons && 1 === icons.length && 'icon-file' !== icons[0])
? icons[0]
diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js
index 484279fe9..9e9f5ef82 100644
--- a/dev/Common/Utils.js
+++ b/dev/Common/Utils.js
@@ -40,38 +40,6 @@ export function pString(value) {
return null != value ? '' + value : '';
}
-/**
- * @param {string} queryString
- * @returns {Object}
- */
-export function simpleQueryParser(queryString) {
- const queries = queryString.split('&'),
- params = {};
-
- queries.forEach(temp => {
- temp = temp.split('=');
- params[decodeURIComponent(temp[0])] = decodeURIComponent(temp[1]);
- });
-
- return params;
-}
-
-/**
- * @param {number=} len = 32
- * @returns {string}
- */
-export function fakeMd5(len = 32) {
- const line = '0123456789abcdefghijklmnopqrstuvwxyz';
-
- len = pInt(len);
-
- let result = '';
- while (len--)
- result += line.substr(Math.round(Math.random() * 36), 1);
-
- return result;
-}
-
/**
* @param {string} text
* @returns {string}
@@ -85,7 +53,7 @@ export function encodeHtml(text) {
* @param {number=} len = 100
* @returns {string}
*/
-export function splitPlainText(text, len = 100) {
+function splitPlainText(text, len = 100) {
let prefix = '',
subText = '',
result = text,
@@ -139,72 +107,6 @@ export function inFocus() {
return false;
}
-/**
- * @param {boolean} force
- * @returns {void}
- */
-export function removeInFocus(force) {
- if (doc.activeElement && doc.activeElement.blur) {
- try {
- if (force || doc.activeElement.matches('input,textarea')) {
- doc.activeElement.blur();
- }
- } catch (e) {} // eslint-disable-line no-empty
- }
-}
-
-/**
- * @returns {void}
- */
-export function removeSelection() {
- try {
- getSelection().removeAllRanges();
- } catch (e) {} // eslint-disable-line no-empty
-}
-
-/**
- * @param {string} prefix
- * @param {string} subject
- * @returns {string}
- */
-export function replySubjectAdd(prefix, subject) {
- prefix = prefix.toUpperCase().trim();
- subject = subject.replace(/[\s]+/g, ' ').trim();
-
- let drop = false,
- re = 'RE' === prefix,
- fwd = 'FWD' === prefix;
-
- const parts = [],
- prefixIsRe = !fwd;
-
- if (subject) {
- subject.split(':').forEach(part => {
- const trimmedPart = part.trim();
- if (!drop && (/^(RE|FWD)$/i.test(trimmedPart) || /^(RE|FWD)[[(][\d]+[\])]$/i.test(trimmedPart))) {
- if (!re) {
- re = !!/^RE/i.test(trimmedPart);
- }
-
- if (!fwd) {
- fwd = !!/^FWD/i.test(trimmedPart);
- }
- } else {
- parts.push(part);
- drop = true;
- }
- });
- }
-
- if (prefixIsRe) {
- re = false;
- } else {
- fwd = false;
- }
-
- return ((prefixIsRe ? 'Re: ' : 'Fwd: ') + (re ? 'Re: ' : '') + (fwd ? 'Fwd: ' : '') + parts.join(':').trim()).trim();
-}
-
/**
* @param {(number|string)} sizeInBytes
* @returns {string}
@@ -256,88 +158,18 @@ export function defautOptionsAfterRender(domItem, item) {
}
}
-/**
- * @param {Function} fCallback
- * @param {?} koTrigger
- * @param {?} context = null
- * @param {number=} timer = 1000
- * @returns {Function}
- */
-export function settingsSaveHelperFunction(fCallback, koTrigger, context = null, timer = 1000) {
- timer = pInt(timer);
- return (type, data, cached, requestAction, requestParameters) => {
- koTrigger.call(context, data && data.Result ? SaveSettingsStep.TrueResult : SaveSettingsStep.FalseResult);
- if (fCallback) {
- fCallback.call(context, type, data, cached, requestAction, requestParameters);
- }
- setTimeout(() => {
- koTrigger.call(context, SaveSettingsStep.Idle);
- }, timer);
- };
-}
-
/**
* @param {object} koTrigger
* @param {mixed} context
* @returns {mixed}
*/
export function settingsSaveHelperSimpleFunction(koTrigger, context) {
- return settingsSaveHelperFunction(null, koTrigger, context, 1000);
-}
-
-/**
- * @param {object} remote
- * @param {string} settingName
- * @param {string} type
- * @param {function} fTriggerFunction
- * @returns {function}
- */
-export function settingsSaveHelperSubscribeFunction(remote, settingName, type, fTriggerFunction) {
- return (value) => {
- if (remote) {
- switch (type) {
- case 'bool':
- case 'boolean':
- value = value ? '1' : '0';
- break;
- case 'int':
- case 'integer':
- case 'number':
- value = pInt(value);
- break;
- case 'trim':
- value = value.trim();
- break;
- default:
- value = pString(value);
- break;
- }
-
- const data = {};
- data[settingName] = value;
-
- if (remote.saveAdminConfig) {
- remote.saveAdminConfig(fTriggerFunction || null, data);
- } else if (remote.saveSettings) {
- remote.saveSettings(fTriggerFunction || null, data);
- }
- }
+ return (type, data) => {
+ koTrigger.call(context, data && data.Result ? SaveSettingsStep.TrueResult : SaveSettingsStep.FalseResult);
+ setTimeout(() => koTrigger.call(context, SaveSettingsStep.Idle), 1000);
};
}
-/**
- * @param {string} html
- * @returns {string}
- */
-/*eslint-disable max-len*/
-const url = /(^|[\s\n]|\/?>)(https:\/\/[-A-Z0-9+\u0026\u2019#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026#/%=~()_|])/gi,
- email = /(^|[\s\n]|\/?>)((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x21\x23-\x5b\x5d-\x7f]|\\[\x21\x23-\x5b\x5d-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x21-\x5a\x53-\x7f]|\\[\x21\x23-\x5b\x5d-\x7f])+)\]))/gi;
-export function findEmailAndLinks(html) {
- return html
- .replace(url, '$1$2')
- .replace(email, '$1$2');
-}
-
/**
* @param {string} html
* @returns {string}
@@ -644,18 +476,6 @@ export function folderListOptionsBuilder(
return aResult;
}
-/**
- * @param {object} element
- * @returns {void}
- */
-export function selectElement(element) {
- let sel = getSelection(),
- range = doc.createRange();
- sel.removeAllRanges();
- range.selectNodeContents(element);
- sel.addRange(range);
-}
-
/**
* @param {Object|Array} objectOrObjects
* @returns {void}
@@ -827,38 +647,6 @@ export function isTransparent(color) {
return 'rgba(0, 0, 0, 0)' === color || 'transparent' === color;
}
-/**
- * @param {string} url
- * @param {number} value
- * @param {Function} fCallback
- */
-export function resizeAndCrop(url, value, fCallback) {
- const img = new Image();
- img.onload = function() {
- let diff = [0, 0];
-
- const canvas = doc.createElement('canvas'),
- ctx = canvas.getContext('2d');
-
- canvas.width = value;
- canvas.height = value;
-
- if (this.width > this.height) {
- diff = [this.width - this.height, 0];
- } else {
- diff = [0, this.height - this.width];
- }
-
- ctx.fillStyle = '#fff';
- ctx.fillRect(0, 0, value, value);
- ctx.drawImage(this, diff[0] / 2, diff[1] / 2, this.width - diff[0], this.height - diff[1], 0, 0, value, value);
-
- fCallback(canvas.toDataURL('image/jpeg'));
- };
-
- img.src = url;
-}
-
/**
* @param {string} mailToUrl
* @param {Function} PopupComposeViewModel
@@ -888,7 +676,10 @@ export function mailToHelper(mailToUrl, PopupComposeViewModel) {
query = mailToUrl.replace(/^[^?]*\?/, ''),
EmailModel = require('Model/Email').default;
- params = simpleQueryParser(query);
+ query.split('&').forEach(temp => {
+ temp = temp.split('=');
+ params[decodeURIComponent(temp[0])] = decodeURIComponent(temp[1]);
+ });
if (undefined !== params.to) {
to = EmailModel.parseEmailLine(decodeURIComponent(email + ',' + params.to));
diff --git a/dev/Model/Email.js b/dev/Model/Email.js
index 115cbe353..634dc2dda 100644
--- a/dev/Model/Email.js
+++ b/dev/Model/Email.js
@@ -440,7 +440,7 @@ class EmailModel {
if (parsedResult.length) {
return parsedResult.map(item =>
item.address ? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '') : null
- ).filter(value => !!value);
+ ).filter(v => v);
}
return [];
diff --git a/dev/Model/Filter.js b/dev/Model/Filter.js
index 381281f6b..e2a3cee78 100644
--- a/dev/Model/Filter.js
+++ b/dev/Model/Filter.js
@@ -1,7 +1,7 @@
import ko from 'ko';
import { FilterRulesType, FiltersAction } from 'Common/Enums';
-import { pString, fakeMd5, delegateRunOnDestroy } from 'Common/Utils';
+import { pString, delegateRunOnDestroy } from 'Common/Utils';
import { i18n } from 'Common/Translator';
import { getFolderFromCacheList } from 'Common/Cache';
@@ -133,7 +133,7 @@ class FilterModel extends AbstractModel {
}
generateID() {
- this.id = fakeMd5();
+ this.id = Jua.randomId();
}
verify() {
@@ -230,7 +230,7 @@ class FilterModel extends AbstractModel {
json.Conditions.map(aData => {
const filterCondition = new FilterConditionModel();
return filterCondition && filterCondition.parse(aData) ? filterCondition : null;
- }).filter(value => !!value)
+ }).filter(v => v)
);
}
diff --git a/dev/Model/Message.js b/dev/Model/Message.js
index ead03274b..b03e2c109 100644
--- a/dev/Model/Message.js
+++ b/dev/Model/Message.js
@@ -182,7 +182,7 @@ class MessageModel extends AbstractModel {
getEmails(properties) {
return properties.reduce((carry, property) => carry.concat(this[property]), []).map(
oItem => oItem ? oItem.email : ''
- ).filter((value, index, self) => !!value && self.indexOf(value) == index);
+ ).validUnique();
}
/**
diff --git a/dev/Settings/User/Filters.js b/dev/Settings/User/Filters.js
index 35585d6b1..54c4a0498 100644
--- a/dev/Settings/User/Filters.js
+++ b/dev/Settings/User/Filters.js
@@ -105,7 +105,7 @@ class FiltersUserSettings {
data.Result.Filters.map(aItem => {
const filter = new FilterModel();
return filter && filter.parse(aItem) ? filter : null;
- }).filter(value => !!value)
+ }).filter(v => v)
);
this.modules(data.Result.Modules ? data.Result.Modules : {});
diff --git a/dev/Stores/User/Account.js b/dev/Stores/User/Account.js
index d70b51776..7d362cd9e 100644
--- a/dev/Stores/User/Account.js
+++ b/dev/Stores/User/Account.js
@@ -10,7 +10,7 @@ class AccountUserStore {
this.accounts = ko.observableArray([]);
this.accounts.loading = ko.observable(false).extend({ throttle: 100 });
- this.getEmailAddresses = () => this.accounts().map(item => item ? item.email : null).filter(value => !!value);
+ this.getEmailAddresses = () => this.accounts().map(item => item ? item.email : null).filter(v => v);
this.accountsUnreadCount = ko.computed(() => 0);
// this.accountsUnreadCount = ko.computed(() => {
diff --git a/dev/Stores/User/Folder.js b/dev/Stores/User/Folder.js
index 2331577d6..59fdcbf9e 100644
--- a/dev/Stores/User/Folder.js
+++ b/dev/Stores/User/Folder.js
@@ -85,7 +85,7 @@ class FolderUserStore {
});
this.folderListSystem = ko.computed(() =>
- this.folderListSystemNames().map(name => getFolderFromCacheList(name)).filter(value => !!value)
+ this.folderListSystemNames().map(name => getFolderFromCacheList(name)).filter(v => v)
);
this.folderMenuForMove = ko.computed(() =>
diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js
index 11faf255a..17f57d1a0 100644
--- a/dev/Stores/User/Message.js
+++ b/dev/Stores/User/Message.js
@@ -5,8 +5,7 @@ import { Layout, Focused, MessageSetAction, StorageResultType, Notification } fr
import {
pInt,
pString,
- plainToHtml,
- findEmailAndLinks
+ plainToHtml
} from 'Common/Utils';
import {
@@ -44,6 +43,14 @@ const
const result = hcont.clientHeight;
hcont.innerHTML = '';
return result;
+ },
+ /*eslint-disable max-len*/
+ url = /(^|[\s\n]|\/?>)(https:\/\/[-A-Z0-9+\u0026\u2019#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026#/%=~()_|])/gi,
+ email = /(^|[\s\n]|\/?>)((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x21\x23-\x5b\x5d-\x7f]|\\[\x21\x23-\x5b\x5d-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x21-\x5a\x53-\x7f]|\\[\x21\x23-\x5b\x5d-\x7f])+)\]))/gi,
+ findEmailAndLinks = html => {
+ return html
+ .replace(url, '$1$2')
+ .replace(email, '$1$2');
};
let iMessageBodyCacheCount = 0;
@@ -142,7 +149,7 @@ class MessageUserStore {
if (checked.length) {
return selectedMessage
- ? checked.concat([selectedMessage]).filter((value, index, self) => self.indexOf(value) == index)
+ ? checked.concat([selectedMessage]).unique()
: checked;
}
@@ -155,7 +162,7 @@ class MessageUserStore {
if (message) {
result.push(message.uid);
if (1 < message.threadsLen()) {
- result = result.concat(message.threads()).filter((value, index, self) => self.indexOf(value) == index);
+ result = result.concat(message.threads()).unique();
}
}
});
diff --git a/dev/Stores/User/Pgp.js b/dev/Stores/User/Pgp.js
index 5b5dc2b65..516dc8e6f 100644
--- a/dev/Stores/User/Pgp.js
+++ b/dev/Stores/User/Pgp.js
@@ -53,7 +53,7 @@ function domControlEncryptedClickHelper(store, dom, armoredMessage, recipients)
} else if (validPrivateKey) {
const keyIds = Array.isNotEmpty(signingKeyIds) ? signingKeyIds : null,
additional = keyIds
- ? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(value => !!value).join(', ')
+ ? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(v => v).join(', ')
: '';
controlsHelper(
@@ -109,7 +109,7 @@ function domControlSignedClickHelper(store, dom, armoredMessage) {
} else {
const keyIds = Array.isNotEmpty(signingKeyIds) ? signingKeyIds : null,
additional = keyIds
- ? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(value => !!value).join(', ')
+ ? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(v => v).join(', ')
: '';
controlsHelper(
@@ -138,8 +138,8 @@ class PgpUserStore {
this.openpgpkeys = ko.observableArray([]);
this.openpgpKeyring = null;
- this.openpgpkeysPublic = ko.computed(() => this.openpgpkeys().filter(item => !!(item && !item.isPrivate)));
- this.openpgpkeysPrivate = ko.computed(() => this.openpgpkeys().filter(item => !!(item && item.isPrivate)));
+ this.openpgpkeysPublic = ko.computed(() => this.openpgpkeys().filter(item => item && !item.isPrivate));
+ this.openpgpkeysPrivate = ko.computed(() => this.openpgpkeys().filter(item => item && item.isPrivate));
}
/**
@@ -165,14 +165,14 @@ class PgpUserStore {
return this.openpgpkeysPublic().map(item => {
const key = item && item.emails.includes(email) ? item : null;
return key ? key.getNativeKeys() : [null];
- }).flat().filter(value => !!value);
+ }).flat().filter(v => v);
}
findPublicKeysBySigningKeyIds(signingKeyIds) {
return signingKeyIds.map(id => {
const key = id && id.toHex ? this.findPublicKeyByHex(id.toHex()) : null;
return key ? key.getNativeKeys() : [null];
- }).flat().filter(value => !!value);
+ }).flat().filter(v => v);
}
findPrivateKeysByEncryptionKeyIds(encryptionKeyIds, recipients, returnWrapKeys) {
@@ -180,7 +180,7 @@ class PgpUserStore {
? encryptionKeyIds.map(id => {
const key = id && id.toHex ? this.findPrivateKeyByHex(id.toHex()) : null;
return key ? (returnWrapKeys ? [key] : key.getNativeKeys()) : [null];
- }).flat().filter(value => !!value)
+ }).flat().filter(v => v)
: [];
if (!result.length && Array.isNotEmpty(recipients)) {
@@ -191,7 +191,7 @@ class PgpUserStore {
? keys
: keys.map(key => key.getNativeKeys()).flat()
: [null];
- }).flat().filter((key, index, self) => key => !!key.id && self.indexOf(key) == index);
+ }).flat().validUnique(key => key.id);
}
return result;
diff --git a/dev/Stores/User/Template.js b/dev/Stores/User/Template.js
index 8d392312f..21fc7bf15 100644
--- a/dev/Stores/User/Template.js
+++ b/dev/Stores/User/Template.js
@@ -15,7 +15,7 @@ class TemplateUserStore {
subscribers() {
this.templates.subscribe((list) => {
- this.templatesNames(list.map(item => (item ? item.name : null)).filter(value => !!value));
+ this.templatesNames(list.map(item => (item ? item.name : null)).filter(v => v));
});
// this.templatesNames.subscribe((aList) => {
diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js
index 832dcf995..280e71a6a 100644
--- a/dev/View/Popup/Compose.js
+++ b/dev/View/Popup/Compose.js
@@ -12,7 +12,6 @@ import {
} from 'Common/Enums';
import {
- replySubjectAdd,
encodeHtml,
inFocus,
delegateRunOnDestroy,
@@ -42,7 +41,50 @@ import { ComposeAttachmentModel } from 'Model/ComposeAttachment';
import { popup, command, isPopupVisible, showScreenPopup, hideScreenPopup } from 'Knoin/Knoin';
import { AbstractViewNext } from 'Knoin/AbstractViewNext';
-const Settings = rl.settings;
+const Settings = rl.settings,
+ /**
+ * @param {string} prefix
+ * @param {string} subject
+ * @returns {string}
+ */
+ replySubjectAdd = (prefix, subject) => {
+ prefix = prefix.toUpperCase().trim();
+ subject = subject.replace(/[\s]+/g, ' ').trim();
+
+ let drop = false,
+ re = 'RE' === prefix,
+ fwd = 'FWD' === prefix;
+
+ const parts = [],
+ prefixIsRe = !fwd;
+
+ if (subject) {
+ subject.split(':').forEach(part => {
+ const trimmedPart = part.trim();
+ if (!drop && (/^(RE|FWD)$/i.test(trimmedPart) || /^(RE|FWD)[[(][\d]+[\])]$/i.test(trimmedPart))) {
+ if (!re) {
+ re = !!/^RE/i.test(trimmedPart);
+ }
+
+ if (!fwd) {
+ fwd = !!/^FWD/i.test(trimmedPart);
+ }
+ } else {
+ parts.push(part);
+ drop = true;
+ }
+ });
+ }
+
+ if (prefixIsRe) {
+ re = false;
+ } else {
+ fwd = false;
+ }
+
+ return ((prefixIsRe ? 'Re: ' : 'Fwd: ') + (re ? 'Re: ' : '')
+ + (fwd ? 'Fwd: ' : '') + parts.join(':').trim()).trim();
+ };
ko.extenders.toggleSubscribe = (target, options) => {
target.subscribe(options[1], options[0], 'beforeChange');
@@ -773,7 +815,7 @@ class ComposePopupView extends AbstractViewNext {
if (Array.isNotEmpty(emails)) {
const value = fKoValue().trim(),
values = emails.map(item => item ? item.toLine(false) : null)
- .filter((value, index, self) => !!value && self.indexOf(value) == index);
+ .validUnique();
fKoValue(value + (value ? ', ' : '') + values.join(', ').trim());
}
diff --git a/dev/View/Popup/ComposeOpenPgp.js b/dev/View/Popup/ComposeOpenPgp.js
index 26168b2e2..77158bb04 100644
--- a/dev/View/Popup/ComposeOpenPgp.js
+++ b/dev/View/Popup/ComposeOpenPgp.js
@@ -40,7 +40,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
this.encryptKeys = ko.observableArray([]);
this.encryptKeysView = ko.computed(
- () => this.encryptKeys().map(oKey => (oKey ? oKey.key : null)).filter(value => !!value)
+ () => this.encryptKeys().map(oKey => (oKey ? oKey.key : null)).filter(v => v)
);
this.privateKeysOptions = ko.computed(() => {
@@ -56,7 +56,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
}));
});
- return opts.flat().filter(value => !!value);
+ return opts.flat().filter(v => v);
});
this.publicKeysOptions = ko.computed(() => {
@@ -71,7 +71,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
'class': index % 2 ? 'odd' : 'even'
}));
});
- return opts.flat().filter(value => !!value);
+ return opts.flat().filter(v => v);
});
this.submitRequest = ko.observable(false);
@@ -156,7 +156,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
this.encryptKeys().forEach(oKey => {
if (oKey && oKey.key) {
- aPublicKeys = aPublicKeys.concat(oKey.key.getNativeKeys().flat(Infinity).filter(value => !!value));
+ aPublicKeys = aPublicKeys.concat(oKey.key.getNativeKeys().flat(Infinity).filter(v => v));
} else if (oKey && oKey.email) {
this.notification(
i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', {
@@ -349,7 +349,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
email.clear();
email.parse(value.trim());
return email.email || false;
- }).filter(value => !!value);
+ }).filter(v => v);
if (identity && identity.email()) {
emailLine = identity.email();
@@ -385,9 +385,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
'key': publicKey
}))
: [];
- }).flat().filter(
- (encryptKey, index, self) => encryptKey => !!encryptKey.hash && self.indexOf(encryptKey) == index
- )
+ }).flat().validUnique(encryptKey => encryptKey.hash)
);
if (this.encryptKeys().length) {
diff --git a/dev/View/Popup/Contacts.js b/dev/View/Popup/Contacts.js
index 3140adc3f..2e549aac2 100644
--- a/dev/View/Popup/Contacts.js
+++ b/dev/View/Popup/Contacts.js
@@ -13,7 +13,6 @@ import {
import {
delegateRunOnDestroy,
computedPagenatorHelper,
- fakeMd5,
pInt
} from 'Common/Utils';
@@ -154,7 +153,7 @@ class ContactsPopupView extends AbstractViewNext {
selected = this.currentContact();
return selected
- ? checked.concat([selected]).filter((value, index, self) => self.indexOf(value) == index)
+ ? checked.concat([selected]).unique()
: checked;
});
@@ -282,7 +281,7 @@ class ContactsPopupView extends AbstractViewNext {
this.viewSaving(true);
this.viewSaveTrigger(SaveSettingsStep.Animate);
- const requestUid = fakeMd5(),
+ const requestUid = Jua.randomId(),
properties = [];
this.viewProperties().forEach(oItem => {
@@ -579,7 +578,7 @@ class ContactsPopupView extends AbstractViewNext {
return contact.parse(item) ? contact : null;
});
- list = list.filter(value => !!value);
+ list = list.filter(v => v);
count = pInt(data.Result.Count);
count = 0 < count ? count : 0;
diff --git a/dev/View/Popup/Identity.js b/dev/View/Popup/Identity.js
index cee7d3083..ab98e11e2 100644
--- a/dev/View/Popup/Identity.js
+++ b/dev/View/Popup/Identity.js
@@ -1,7 +1,6 @@
import ko from 'ko';
import { StorageResultType, Notification } from 'Common/Enums';
-import { fakeMd5 } from 'Common/Utils';
import { getNotification } from 'Common/Translator';
import Remote from 'Remote/User/Fetch';
@@ -158,7 +157,7 @@ class IdentityPopupView extends AbstractViewNext {
this.owner(!this.id);
} else {
- this.id = fakeMd5();
+ this.id = Jua.randomId();
}
}
diff --git a/dev/View/Popup/ViewOpenPgpKey.js b/dev/View/Popup/ViewOpenPgpKey.js
index 1d2ab94cb..aa3bf8230 100644
--- a/dev/View/Popup/ViewOpenPgpKey.js
+++ b/dev/View/Popup/ViewOpenPgpKey.js
@@ -1,7 +1,6 @@
import ko from 'ko';
import { KeyState } from 'Common/Enums';
-import { selectElement } from 'Common/Utils';
import { popup } from 'Knoin/Knoin';
import { AbstractViewNext } from 'Knoin/AbstractViewNext';
@@ -27,7 +26,11 @@ class ViewOpenPgpKeyPopupView extends AbstractViewNext {
selectKey() {
const el = this.keyDom();
if (el) {
- selectElement(el);
+ let sel = getSelection(),
+ range = document.createRange();
+ sel.removeAllRanges();
+ range.selectNodeContents(el);
+ sel.addRange(range);
}
}
diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js
index bafed6799..0a4d9095e 100644
--- a/dev/View/User/MailBox/MessageView.js
+++ b/dev/View/User/MailBox/MessageView.js
@@ -17,7 +17,6 @@ import { $htmlCL, leftPanelDisabled, keyScopeReal, moveAction } from 'Common/Glo
import {
inFocus,
- removeSelection,
mailToHelper,
isTransparent
} from 'Common/Utils';
@@ -336,7 +335,9 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
}
toggleFullScreen() {
- removeSelection();
+ try {
+ getSelection().removeAllRanges();
+ } catch (e) {} // eslint-disable-line no-empty
this.fullScreenMode(!this.fullScreenMode());
}
@@ -365,7 +366,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
// var oEmailModel = new EmailModel();
// oEmailModel.parse(sItem);
// return oEmailModel.email ? oEmailModel : null;
- // }).filter(value => !!value) : null;
+ // }).filter(v => v) : null;
// }
// ;
//
@@ -395,7 +396,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
};
}
return null;
- }).filter(value => !!value);
+ }).filter(v => v);
if (items.length) {
}
@@ -712,7 +713,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
getAttachmentsHashes() {
const atts = this.message() ? this.message().attachments() : [];
- return atts.map(item => (item && !item.isLinked && item.checked() ? item.download : '')).filter(value => !!value);
+ return atts.map(item => (item && !item.isLinked && item.checked() ? item.download : '')).filter(v => v);
}
downloadAsZip() {
diff --git a/dev/prototype.js b/dev/prototype.js
index 0b2057486..e14f1fa7a 100644
--- a/dev/prototype.js
+++ b/dev/prototype.js
@@ -2,6 +2,9 @@
(w=>{
Array.isNotEmpty = array => Array.isArray(array) && array.length;
Array.prototype.unique = function() { return this.filter((v, i, a) => a.indexOf(v) === i); };
+ Array.prototype.validUnique = function(fn) {
+ return this.filter((v, i, a) => (fn ? fn(v) : v) && a.indexOf(v) === i);
+ };
// Import momentjs locales function
w.moment = {
@@ -45,7 +48,6 @@
}
},
pad2 = v => 10 > v ? '0' + v : v,
- pad3 = v => 10 > v ? '00' + v : (100 > v ? '0' + v : v),
getISODay = x => x.getDay() || 7,
getDayOfYear = x => Math.floor((Date.UTC(x.getFullYear(),x.getMonth(),x.getDate())
- Date.UTC(x.getFullYear(),0,1)) / 86400000),
@@ -149,7 +151,7 @@
case 'H': return pad2(d.H);
case 'i': return pad2(UTC?x.getUTCMinutes():x.getMinutes());
case 's': return pad2(UTC?x.getUTCSeconds():x.getSeconds());
- case 'u': return pad3(UTC?x.getUTCMilliseconds():x.getMilliseconds());
+ case 'u': return (UTC?x.getUTCMilliseconds():x.getMilliseconds()).toString().padStart(3,'0');
// Timezone
case 'I': return UTC ? 0 : isDST(x) ? 1 : 0;
case 'O': return UTC ? 'Z' : (d.Z > 0 ? '+' : '-') + pad2(Math.abs(d.Z / 60)) + '00';
diff --git a/vendors/jua/jua.js b/vendors/jua/jua.js
index 19e1f3b58..81caef030 100644
--- a/vendors/jua/jua.js
+++ b/vendors/jua/jua.js
@@ -488,13 +488,7 @@
*/
addNewFile(oFileInfo)
{
- let iLen = 16,
- fakeMd5 = '';
-
- while (iLen--)
- fakeMd5 += '0123456789abcdefghijklmnopqrstuvwxyz'.substr(Math.round(Math.random() * 36), 1);
-
- this.addFile('jua-uid-' + fakeMd5 + '-' + (Date.now().toString()), oFileInfo);
+ this.addFile('jua-uid-' + Jua.randomId(16) + '-' + (Date.now().toString()), oFileInfo);
}
/**
@@ -516,6 +510,12 @@
}
}
+ Jua.randomId = len => {
+ let arr = new Uint8Array((len || 32) / 2);
+ crypto.getRandomValues(arr);
+ return arr.map(dec => dec.toString(16).padStart(2,'0')).join('');
+ }
+
/**
* @type {number}
*/
diff --git a/vendors/jua/jua.min.js b/vendors/jua/jua.min.js
index e8cfe4c54..71c9bc03b 100644
--- a/vendors/jua/jua.min.js
+++ b/vendors/jua/jua.min.js
@@ -1,2 +1,2 @@
/* RainLoop Webmail (c) RainLoop Team | MIT */
-(e=>{const t=20,n=e=>void 0!==e,r=(e,r,i,o)=>{if(e&&e.length){let a=i=n(i)?parseInt(i||0,10):t,s=null,u=0{e&&(!u||0<=--i?(s=l(e))&&r(s):u&&!d&&0>i&&o&&(d=!0,o(a)))})}},i=(e,t)=>Object.entries(t).forEach(([t,n])=>e.addEventListener(t,n)),l=e=>{let t=n(e.fileName)?e.fileName:n(e.name)?e.name:null,r=n(e.fileSize)?e.fileSize:n(e.size)?e.size:null,i=n(e.type)?e.type:null;return"/"===t.charAt(0)&&(t=t.substr(1)),i||0!==r?{FileName:t,Size:r,Type:i,Folder:"",File:e}:null},o=e=>{try{return e.dataTransfer.types.includes("Files")}catch(e){return!1}};class a{constructor(e,t){this.oXhrs={},this.oUids={},this.oJua=e,this.oOptions=Object.assign({action:"",name:"juaFile",hidden:{},disableMultiple:!1},t)}regTaskUid(e){this.oUids[e]=!0}uploadTask(e,t){if(!1===this.oUids[e]||!t||!t.File)return!1;try{const r=this,i=new XMLHttpRequest,l=new FormData,o=this.oOptions.action,a=this.oOptions.hidden,s=this.oJua.getEvent("onStart"),u=this.oJua.getEvent("onComplete"),d=this.oJua.getEvent("onProgress");return i.open("POST",o,!0),d&&i.upload&&(i.upload.onprogress=function(t){t&&t.lengthComputable&&n(t.loaded)&&n(t.total)&&d(e,t.loaded,t.total)}),i.onreadystatechange=function(){if(4===i.readyState&&200===i.status){if(u){let t=!1,n=null;try{n=JSON.parse(i.responseText),t=!0}catch(e){n=null}u(e,t,n)}n(r.oXhrs[e])&&(r.oXhrs[e]=null)}else 4===i.readyState&&u(e,!1,null)},s&&s(e),l.append("jua-post-type","ajax"),l.append(this.oOptions.name,t.File),Object.entries(a).forEach(([e,n])=>l.append(e,("function"==typeof n?n(t):n).toString())),i.send(l),this.oXhrs[e]=i,!0}catch(e){console.error(e)}return!1}generateNewInput(t){if(t){const n=this,i=e.createElement("input"),l=()=>i.click();i.type="file",i.tabIndex=-1,i.style.display="none",i.multiple=!n.oOptions.disableMultiple,t.addEventListener("click",l),i.addEventListener("input",()=>{const e=e=>{n.oJua.addNewFile(e),setTimeout(()=>{i.remove(),t.removeEventListener("click",l),n.generateNewInput(t)},10)};i.files&&i.files.length?r(i.files,e,n.oOptions.multipleSizeLimit,n.oJua.getEvent("onLimitReached")):e({FileName:i.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){console.error(e)}this.oXhrs[e]=null}}}class s extends Array{constructor(e){super(),this.limit=parseInt(e||0,10)}push(e,...t){this.limit>this.length&&(super.push([e,t]),this.call())}call(){if(!this.running){let e;for(this.running=!0;e=this.shift();)e[0](...e[1]);this.running=!1}}}class u{constructor(n){const l=this;l.oEvents={onSelect:null,onStart:null,onComplete:null,onProgress:null,onDragEnter:null,onDragLeave:null,onBodyDragEnter:null,onBodyDragLeave:null,onLimitReached:null},n=Object.assign({queueSize:10,clickElement:null,dragAndDropElement:null,dragAndDropBodyElement:null,disableDocumentDropPrevent:!1,multipleSizeLimit:t},n||{}),l.oQueue=new s(n.queueSize),l.oDriver=new a(l,n);let u=n.clickElement;if(u&&(u.style.position="relative",u.style.overflow="hidden","inline"===u.style.display&&(u.style.display="inline-block"),l.oDriver.generateNewInput(u)),u=n.dragAndDropElement){let t=n.dragAndDropBodyElement||e;n.disableDocumentDropPrevent||e.addEventListener("dragover",e=>{if(o(e))try{e.dataTransfer.dropEffect="none",e.preventDefault()}catch(e){console.error(e)}}),t&&i(t,{dragover:()=>l.docTimer.clear(),dragenter:e=>{o(e)&&(l.docTimer.clear(),e.preventDefault(),l.runEvent("onBodyDragEnter",[e]))},dragleave:e=>e.dataTransfer&&l.docTimer.start(()=>l.runEvent("onBodyDragLeave",[e])),drop:e=>{if(e.dataTransfer){let t=o(e);return t&&e.preventDefault(),l.runEvent("onBodyDragLeave",[e]),!t}return!1}}),i(u,{dragenter:e=>{o(e)&&(l.docTimer.clear(),e.preventDefault(),l.runEvent("onDragEnter",[u,e]))},dragover:e=>{if(o(e))try{let t=e.dataTransfer.effectAllowed;l.docTimer.clear(),e.dataTransfer.dropEffect="move"===t||"linkMove"===t?"move":"copy",e.stopPropagation(),e.preventDefault()}catch(e){console.error(e)}},dragleave:t=>{if(t.dataTransfer){let n=e.elementFromPoint(t.clientX,t.clientY);n&&u.contains(n)||(l.docTimer.clear(),l.runEvent("onDragLeave",[u,t]))}},drop:e=>{o(e)&&(e.preventDefault(),r(e.files||e.dataTransfer.files,e=>{e&&(l.addNewFile(e),l.docTimer.clear())},n.multipleSizeLimit,l.getEvent("onLimitReached"))),l.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+"-"+Date.now().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.push((...e)=>this.oDriver.uploadTask(...e),e,t))}}u.prototype.docTimer={start:function(e){this.clear(),this.timer=setTimeout(e,200)},clear:function(){this.timer&&clearTimeout(this.timer),this.timer=0}},this.Jua=u})(document);
+(e=>{const t=20,n=e=>void 0!==e,r=(e,r,i,o)=>{if(e&&e.length){let a=i=n(i)?parseInt(i||0,10):t,s=null,u=0{e&&(!u||0<=--i?(s=l(e))&&r(s):u&&!d&&0>i&&o&&(d=!0,o(a)))})}},i=(e,t)=>Object.entries(t).forEach(([t,n])=>e.addEventListener(t,n)),l=e=>{let t=n(e.fileName)?e.fileName:n(e.name)?e.name:null,r=n(e.fileSize)?e.fileSize:n(e.size)?e.size:null,i=n(e.type)?e.type:null;return"/"===t.charAt(0)&&(t=t.substr(1)),i||0!==r?{FileName:t,Size:r,Type:i,Folder:"",File:e}:null},o=e=>{try{return e.dataTransfer.types.includes("Files")}catch(e){return!1}};class a{constructor(e,t){this.oXhrs={},this.oUids={},this.oJua=e,this.oOptions=Object.assign({action:"",name:"juaFile",hidden:{},disableMultiple:!1},t)}regTaskUid(e){this.oUids[e]=!0}uploadTask(e,t){if(!1===this.oUids[e]||!t||!t.File)return!1;try{const r=this,i=new XMLHttpRequest,l=new FormData,o=this.oOptions.action,a=this.oOptions.hidden,s=this.oJua.getEvent("onStart"),u=this.oJua.getEvent("onComplete"),d=this.oJua.getEvent("onProgress");return i.open("POST",o,!0),d&&i.upload&&(i.upload.onprogress=function(t){t&&t.lengthComputable&&n(t.loaded)&&n(t.total)&&d(e,t.loaded,t.total)}),i.onreadystatechange=function(){if(4===i.readyState&&200===i.status){if(u){let t=!1,n=null;try{n=JSON.parse(i.responseText),t=!0}catch(e){n=null}u(e,t,n)}n(r.oXhrs[e])&&(r.oXhrs[e]=null)}else 4===i.readyState&&u(e,!1,null)},s&&s(e),l.append("jua-post-type","ajax"),l.append(this.oOptions.name,t.File),Object.entries(a).forEach(([e,n])=>l.append(e,("function"==typeof n?n(t):n).toString())),i.send(l),this.oXhrs[e]=i,!0}catch(e){console.error(e)}return!1}generateNewInput(t){if(t){const n=this,i=e.createElement("input"),l=()=>i.click();i.type="file",i.tabIndex=-1,i.style.display="none",i.multiple=!n.oOptions.disableMultiple,t.addEventListener("click",l),i.addEventListener("input",()=>{const e=e=>{n.oJua.addNewFile(e),setTimeout(()=>{i.remove(),t.removeEventListener("click",l),n.generateNewInput(t)},10)};i.files&&i.files.length?r(i.files,e,n.oOptions.multipleSizeLimit,n.oJua.getEvent("onLimitReached")):e({FileName:i.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){console.error(e)}this.oXhrs[e]=null}}}class s extends Array{constructor(e){super(),this.limit=parseInt(e||0,10)}push(e,...t){this.limit>this.length&&(super.push([e,t]),this.call())}call(){if(!this.running){let e;for(this.running=!0;e=this.shift();)e[0](...e[1]);this.running=!1}}}class u{constructor(n){const l=this;l.oEvents={onSelect:null,onStart:null,onComplete:null,onProgress:null,onDragEnter:null,onDragLeave:null,onBodyDragEnter:null,onBodyDragLeave:null,onLimitReached:null},n=Object.assign({queueSize:10,clickElement:null,dragAndDropElement:null,dragAndDropBodyElement:null,disableDocumentDropPrevent:!1,multipleSizeLimit:t},n||{}),l.oQueue=new s(n.queueSize),l.oDriver=new a(l,n);let u=n.clickElement;if(u&&(u.style.position="relative",u.style.overflow="hidden","inline"===u.style.display&&(u.style.display="inline-block"),l.oDriver.generateNewInput(u)),u=n.dragAndDropElement){let t=n.dragAndDropBodyElement||e;n.disableDocumentDropPrevent||e.addEventListener("dragover",e=>{if(o(e))try{e.dataTransfer.dropEffect="none",e.preventDefault()}catch(e){console.error(e)}}),t&&i(t,{dragover:()=>l.docTimer.clear(),dragenter:e=>{o(e)&&(l.docTimer.clear(),e.preventDefault(),l.runEvent("onBodyDragEnter",[e]))},dragleave:e=>e.dataTransfer&&l.docTimer.start(()=>l.runEvent("onBodyDragLeave",[e])),drop:e=>{if(e.dataTransfer){let t=o(e);return t&&e.preventDefault(),l.runEvent("onBodyDragLeave",[e]),!t}return!1}}),i(u,{dragenter:e=>{o(e)&&(l.docTimer.clear(),e.preventDefault(),l.runEvent("onDragEnter",[u,e]))},dragover:e=>{if(o(e))try{let t=e.dataTransfer.effectAllowed;l.docTimer.clear(),e.dataTransfer.dropEffect="move"===t||"linkMove"===t?"move":"copy",e.stopPropagation(),e.preventDefault()}catch(e){console.error(e)}},dragleave:t=>{if(t.dataTransfer){let n=e.elementFromPoint(t.clientX,t.clientY);n&&u.contains(n)||(l.docTimer.clear(),l.runEvent("onDragLeave",[u,t]))}},drop:e=>{o(e)&&(e.preventDefault(),r(e.files||e.dataTransfer.files,e=>{e&&(l.addNewFile(e),l.docTimer.clear())},n.multipleSizeLimit,l.getEvent("onLimitReached"))),l.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){this.addFile("jua-uid-"+u.randomId(16)+"-"+Date.now().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.push((...e)=>this.oDriver.uploadTask(...e),e,t))}}u.randomId=(e=>{let t=new Uint8Array((e||32)/2);return crypto.getRandomValues(t),t.map(e=>e.toString(16).padStart(2,"0")).join("")}),u.prototype.docTimer={start:function(e){this.clear(),this.timer=setTimeout(e,200)},clear:function(){this.timer&&clearTimeout(this.timer),this.timer=0}},this.Jua=u})(document);