mirror of
https://github.com/the-djmaze/snappymail.git
synced 2024-09-20 07:35:55 +08:00
Use jQuery.slim
Underscore.js _.uniq(_.compact( to native Array.filter((value, index, self) => !!value && self.indexOf(value) == index) Underscore.js _.compact to native Array.filter(value => !!value) Underscore.js _.uniq to native Array.filter((value, index, self) => self.indexOf(value) == index) Underscore.js _.values to native Object.values Underscore.js _.flatten to native Array.flat Underscore.js _.union to native Array.concat + unique filter Underscore.js _.reduce to native Array.reduce Underscore.js _.escape replaced with advanced htmlspecialchars() Underscore.js _.memoize replaced Now Underscore.js is a slim custom version (only _.debounce, _.defer & _.throttle)
This commit is contained in:
parent
996a71ad8a
commit
dca0ff02ed
|
@ -51,6 +51,12 @@ This fork has the following changes:
|
|||
* CRLF => LF line endings
|
||||
* Ongoing removal of jQuery and Underscore.js dependencies (things are native these days)
|
||||
|
||||
### slim jQuery and Underscore.js
|
||||
js: 1.14.0 = 7960367 / native = 5127981 bytes
|
||||
js/min: 1.14.0 = 1766594 / native = 1405850 bytes
|
||||
|
||||
360.744 bytes is nut much, but it already feels faster.
|
||||
|
||||
### PHP73 branch
|
||||
|
||||
There's a branch with only the PHP 7.3 changes at
|
||||
|
|
|
@ -86,15 +86,13 @@ class AdminApp extends AbstractApp {
|
|||
});
|
||||
|
||||
if (isArray(data.Result.List)) {
|
||||
list = _.compact(
|
||||
data.Result.List.map(item => {
|
||||
if (item) {
|
||||
item.loading = ko.observable(!isUnd(loading[item.file]));
|
||||
return 'core' === item.type && !item.canBeInstalled ? null : item;
|
||||
}
|
||||
return null;
|
||||
})
|
||||
);
|
||||
list = data.Result.List.map(item => {
|
||||
if (item) {
|
||||
item.loading = ko.observable(!isUnd(loading[item.file]));
|
||||
return 'core' === item.type && !item.canBeInstalled ? null : item;
|
||||
}
|
||||
return null;
|
||||
}).filter(value => !!value);
|
||||
}
|
||||
|
||||
PackageStore.packages(list);
|
||||
|
|
|
@ -321,7 +321,8 @@ class AppUser extends AbstractApp {
|
|||
};
|
||||
}
|
||||
|
||||
this.moveCache[hash].Uid = _.union(this.moveCache[hash].Uid, uidsForMove);
|
||||
this.moveCache[hash].Uid = this.moveCache[hash].Uid.concat(uidsForMove)
|
||||
.filter((value, index, self) => self.indexOf(value) == index);
|
||||
this.messagesMoveTrigger();
|
||||
}
|
||||
|
||||
|
@ -520,7 +521,9 @@ class AppUser extends AbstractApp {
|
|||
.getKeyId()
|
||||
.toHex()
|
||||
.toLowerCase(),
|
||||
_.uniq(_.compact(oItem.getKeyIds().map(item => (item && item.toHex ? item.toHex() : null)))),
|
||||
oItem.getKeyIds()
|
||||
.map(item => (item && item.toHex ? item.toHex() : null))
|
||||
.filter((value, index, self) => !!value && self.indexOf(value) == index),
|
||||
aUsers,
|
||||
aEmails,
|
||||
oItem.isPrivate(),
|
||||
|
@ -634,12 +637,10 @@ class AppUser extends AbstractApp {
|
|||
delegateRunOnDestroy(TemplateStore.templates());
|
||||
|
||||
TemplateStore.templates(
|
||||
_.compact(
|
||||
data.Result.Templates.map(templateData => {
|
||||
const template = new TemplateModel();
|
||||
return template.parse(templateData) ? template : null;
|
||||
})
|
||||
)
|
||||
data.Result.Templates.map(templateData => {
|
||||
const template = new TemplateModel();
|
||||
return template.parse(templateData) ? template : null;
|
||||
}).filter(value => !!value)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -819,7 +820,8 @@ class AppUser extends AbstractApp {
|
|||
messages = MessageStore.messageListChecked();
|
||||
}
|
||||
|
||||
rootUids = _.uniq(_.compact(messages.map(oMessage => (oMessage && oMessage.uid ? oMessage.uid : null))));
|
||||
rootUids = messages.map(oMessage => oMessage && oMessage.uid ? oMessage.uid : null)
|
||||
.filter((value, index, self) => !!value && self.indexOf(value) == index);
|
||||
|
||||
if ('' !== sFolderFullNameRaw && 0 < rootUids.length) {
|
||||
switch (iSetAction) {
|
||||
|
@ -880,7 +882,7 @@ class AppUser extends AbstractApp {
|
|||
Remote.suggestions((result, data) => {
|
||||
if (StorageResultType.Success === result && data && isArray(data.Result)) {
|
||||
autocompleteCallback(
|
||||
_.compact(data.Result.map(item => (item && item[0] ? new EmailModel(item[0], item[1]) : null)))
|
||||
data.Result.map(item => (item && item[0] ? new EmailModel(item[0], item[1]) : null)).filter(value => !!value)
|
||||
);
|
||||
} else if (StorageResultType.Abort !== result) {
|
||||
autocompleteCallback([]);
|
||||
|
@ -899,10 +901,10 @@ class AppUser extends AbstractApp {
|
|||
}
|
||||
|
||||
if (bExpanded) {
|
||||
aExpandedList.push(sFullNameHash);
|
||||
aExpandedList = _.uniq(aExpandedList);
|
||||
if (!aExpandedList.includes(sFullNameHash))
|
||||
aExpandedList.push(sFullNameHash);
|
||||
} else {
|
||||
aExpandedList = _.without(aExpandedList, sFullNameHash);
|
||||
aExpandedList = aExpandedList.filter(value => value !== sFullNameHash);
|
||||
}
|
||||
|
||||
Local.set(ClientSideKeyName.ExpandedFolders, aExpandedList);
|
||||
|
|
|
@ -18,7 +18,49 @@ export const FileType = {
|
|||
'Presentation': 'presentation',
|
||||
'Certificate': 'certificate',
|
||||
'CertificateBin': 'certificate-bin',
|
||||
'Archive': 'archive'
|
||||
'Archive': 'archive',
|
||||
|
||||
getIconClass: function(type) {
|
||||
let result = ['icon-file', ''];
|
||||
switch (type) {
|
||||
case this.Text:
|
||||
case this.Eml:
|
||||
case this.WordText:
|
||||
result[0] += '-text';
|
||||
break;
|
||||
case this.Html:
|
||||
case this.Code:
|
||||
result[0] += '-code';
|
||||
break;
|
||||
case this.Image:
|
||||
result[0] += '-image';
|
||||
break;
|
||||
case this.Audio:
|
||||
result[0] += '-music';
|
||||
break;
|
||||
case this.Video:
|
||||
result[0] += '-movie';
|
||||
break;
|
||||
case this.Archive:
|
||||
result[0] += '-zip';
|
||||
break;
|
||||
case this.Certificate:
|
||||
case this.CertificateBin:
|
||||
result[0] += '-certificate';
|
||||
break;
|
||||
case this.Sheet:
|
||||
result[0] += '-excel';
|
||||
break;
|
||||
case this.Presentation:
|
||||
result[0] += '-chart-graph';
|
||||
break;
|
||||
case this.Pdf:
|
||||
result['icon-none', 'pdf'];
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,13 +11,25 @@ import { jassl } from 'Common/Jassl';
|
|||
|
||||
const trim = $.trim;
|
||||
const isArray = Array.isArray;
|
||||
const isObject = _.isObject;
|
||||
const isFunc = _.isFunction;
|
||||
const isUnd = _.isUndefined;
|
||||
const isObject = v => typeof v === 'object';
|
||||
const isFunc = v => typeof v === 'function';
|
||||
const isUnd = v => undefined === v;
|
||||
const noop = () => {}; // eslint-disable-line no-empty-function
|
||||
const noopTrue = () => true;
|
||||
const noopFalse = () => false;
|
||||
|
||||
var htmlspecialchars = ((de,se,gt,lt,sq,dq,bt) => {
|
||||
return (str, quote_style = 3, double_encode = true) => {
|
||||
str = (''+str)
|
||||
.replace(double_encode?de:se,'&')
|
||||
.replace(gt,'<')
|
||||
.replace(lt,'>')
|
||||
.replace(bt,'`');
|
||||
if (quote_style & 1) { str = str.replace(sq,'''); }
|
||||
return (quote_style & 2) ? str.replace(dq,'"') : str;
|
||||
};
|
||||
})(/&/g,/&(?![\w#]+;)/gi,/</g,/>/g,/'/g,/"/g,/`/g);
|
||||
|
||||
export { trim, isArray, isObject, isFunc, isUnd, noop, noopTrue, noopFalse, jassl };
|
||||
|
||||
/**
|
||||
|
@ -167,7 +179,7 @@ export function fakeMd5(len = 32) {
|
|||
* @returns {string}
|
||||
*/
|
||||
export function encodeHtml(text) {
|
||||
return isNormal(text) ? _.escape(text.toString()) : '';
|
||||
return isNormal(text) ? htmlspecialchars(text.toString()) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -449,7 +461,7 @@ export function createCommandLegacy(context, fExecute, fCanExecute = true) {
|
|||
* @param {string} theme
|
||||
* @returns {string}
|
||||
*/
|
||||
export const convertThemeName = _.memoize((theme) => {
|
||||
export const convertThemeName = theme => {
|
||||
if ('@custom' === theme.substr(-7)) {
|
||||
theme = trim(theme.substring(0, theme.length - 7));
|
||||
}
|
||||
|
@ -458,9 +470,9 @@ export const convertThemeName = _.memoize((theme) => {
|
|||
theme
|
||||
.replace(/[^a-zA-Z0-9]+/g, ' ')
|
||||
.replace(/([A-Z])/g, ' $1')
|
||||
.replace(/[\s]+/g, ' ')
|
||||
.replace(/\s+/g, ' ')
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
|
@ -713,7 +725,7 @@ export function htmlToPlain(html) {
|
|||
.replace(/[\n]/gm, '<br />')
|
||||
.replace(/[\r]/gm, '')
|
||||
: '',
|
||||
fixAttibuteValue = (...args) => (args && 1 < args.length ? '' + args[1] + _.escape(args[2]) : ''),
|
||||
fixAttibuteValue = (...args) => (args && 1 < args.length ? '' + args[1] + htmlspecialchars(args[2]) : ''),
|
||||
convertLinks = (...args) => (args && 1 < args.length ? trim(args[1]) : '');
|
||||
|
||||
text = html
|
||||
|
@ -1384,7 +1396,7 @@ export function mailToHelper(mailToUrl, PopupComposeViewModel) {
|
|||
|
||||
if (!isUnd(params.to)) {
|
||||
to = EmailModel.parseEmailLine(decodeURIComponent(email + ',' + params.to));
|
||||
to = _.values(
|
||||
to = Object.values(
|
||||
to.reduce((result, value) => {
|
||||
if (value) {
|
||||
if (result[value.email]) {
|
||||
|
|
35
dev/External/ko.js
vendored
35
dev/External/ko.js
vendored
|
@ -13,7 +13,8 @@ const ko = window.ko,
|
|||
element.__opentip.deactivate();
|
||||
}
|
||||
});
|
||||
};
|
||||
},
|
||||
isFunction = v => typeof v === 'function';
|
||||
|
||||
ko.bindingHandlers.updateWidth = {
|
||||
init: (element, fValueAccessor) => {
|
||||
|
@ -145,7 +146,7 @@ ko.bindingHandlers.tooltip = {
|
|||
Globals = require('Common/Globals');
|
||||
|
||||
if (!Globals.bMobileDevice || isMobile) {
|
||||
const sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
|
||||
const sValue = !ko.isObservable(fValue) && isFunction(fValue) ? fValue() : ko.unwrap(fValue);
|
||||
|
||||
element.__opentip = new Opentip(element, {
|
||||
'style': 'rainloopTip',
|
||||
|
@ -203,7 +204,7 @@ ko.bindingHandlers.tooltip = {
|
|||
Globals = require('Common/Globals');
|
||||
|
||||
if ((!Globals.bMobileDevice || isMobile) && element.__opentip) {
|
||||
const sValue = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue);
|
||||
const sValue = !ko.isObservable(fValue) && isFunction(fValue) ? fValue() : ko.unwrap(fValue);
|
||||
if (sValue) {
|
||||
element.__opentip.setContent(isI18N ? require('Common/Translator').i18n(sValue) : sValue);
|
||||
element.__opentip.activate();
|
||||
|
@ -240,7 +241,7 @@ ko.bindingHandlers.tooltipErrorTip = {
|
|||
update: (element, fValueAccessor) => {
|
||||
const $el = $(element),
|
||||
fValue = fValueAccessor(),
|
||||
value = !ko.isObservable(fValue) && _.isFunction(fValue) ? fValue() : ko.unwrap(fValue),
|
||||
value = !ko.isObservable(fValue) && isFunction(fValue) ? fValue() : ko.unwrap(fValue),
|
||||
openTips = element.__opentip;
|
||||
|
||||
if (openTips) {
|
||||
|
@ -797,8 +798,7 @@ ko.bindingHandlers.saveTrigger = {
|
|||
|
||||
ko.bindingHandlers.emailsTags = {
|
||||
init: (element, fValueAccessor, fAllBindingsAccessor) => {
|
||||
const Utils = require('Common/Utils'),
|
||||
EmailModel = require('Model/Email').default,
|
||||
const EmailModel = require('Model/Email').default,
|
||||
$el = $(element),
|
||||
fValue = fValueAccessor(),
|
||||
fAllBindings = fAllBindingsAccessor(),
|
||||
|
@ -817,20 +817,18 @@ ko.bindingHandlers.emailsTags = {
|
|||
inputDelimiters: inputDelimiters,
|
||||
autoCompleteSource: fAutoCompleteSource,
|
||||
splitHook: (value) => {
|
||||
const v = Utils.trim(value);
|
||||
const v = value.trim();
|
||||
if (v && inputDelimiters.includes(v.substr(-1))) {
|
||||
return EmailModel.splitEmailLine(value);
|
||||
}
|
||||
return null;
|
||||
},
|
||||
parseHook: (input) =>
|
||||
_.flatten(
|
||||
input.map(inputValue => {
|
||||
const values = EmailModel.parseEmailLine(inputValue);
|
||||
return values.length ? values : inputValue;
|
||||
})
|
||||
).map(
|
||||
item => (_.isObject(item) ? [item.toLine(false), item] : [item, null])
|
||||
input.map(inputValue => {
|
||||
const values = EmailModel.parseEmailLine(inputValue);
|
||||
return values.length ? values : inputValue;
|
||||
}).flat(Infinity).map(
|
||||
item => (item.toLine ? [item.toLine(false), item] : [item, null])
|
||||
),
|
||||
change: (event) => {
|
||||
$el.data('EmailsTagsValue', event.target.value);
|
||||
|
@ -872,7 +870,7 @@ ko.bindingHandlers.command = {
|
|||
|
||||
if (!command.canExecute) {
|
||||
const __realCanExecute = command.__realCanExecute;
|
||||
if (_.isFunction(__realCanExecute)) {
|
||||
if (isFunction(__realCanExecute)) {
|
||||
command.canExecute = ko.computed(() => command.enabled() && __realCanExecute.call(viewModel, viewModel));
|
||||
} else {
|
||||
command.canExecute = ko.computed(() => command.enabled() && !!__realCanExecute);
|
||||
|
@ -912,11 +910,10 @@ ko.bindingHandlers.command = {
|
|||
// extenders
|
||||
|
||||
ko.extenders.trimmer = (target) => {
|
||||
const Utils = require('Common/Utils'),
|
||||
result = ko.computed({
|
||||
const result = ko.computed({
|
||||
read: target,
|
||||
write: (newValue) => {
|
||||
target(Utils.trim(newValue.toString()));
|
||||
target(newValue.toString().trim());
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1116,7 +1113,7 @@ ko.observable.fn.deleteAccessHelper = function() {
|
|||
ko.observable.fn.validateFunc = function(fFunc) {
|
||||
this.hasFuncError = ko.observable(false);
|
||||
|
||||
if (_.isFunction(fFunc)) {
|
||||
if (isFunction(fFunc)) {
|
||||
this.subscribe((value) => {
|
||||
this.hasFuncError(!fFunc(value));
|
||||
});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import window from 'window';
|
||||
import _ from '_';
|
||||
import ko from 'ko';
|
||||
|
||||
import { FileType } from 'Common/Enums';
|
||||
|
@ -22,159 +21,123 @@ import Audio from 'Common/Audio';
|
|||
* @param {string} sMimeType
|
||||
* @returns {string}
|
||||
*/
|
||||
export const staticFileType = _.memoize((ext, mimeType) => {
|
||||
ext = trim(ext).toLowerCase();
|
||||
mimeType = trim(mimeType).toLowerCase();
|
||||
export const staticFileType = (() => {
|
||||
let cache = {};
|
||||
return (ext, mimeType) => {
|
||||
ext = trim(ext).toLowerCase();
|
||||
mimeType = trim(mimeType).toLowerCase();
|
||||
|
||||
let result = FileType.Unknown;
|
||||
const mimeTypeParts = mimeType.split('/');
|
||||
let key = ext + mimeType;
|
||||
if (cache[key]) {
|
||||
return cache[key];
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case 'image' === mimeTypeParts[0] || ['png', 'jpg', 'jpeg', 'gif', 'bmp'].includes(ext):
|
||||
result = FileType.Image;
|
||||
break;
|
||||
case 'audio' === mimeTypeParts[0] || ['mp3', 'ogg', 'oga', 'wav'].includes(ext):
|
||||
result = FileType.Audio;
|
||||
break;
|
||||
case 'video' === mimeTypeParts[0] || ['mkv', 'avi'].includes(ext):
|
||||
result = FileType.Video;
|
||||
break;
|
||||
case ['php', 'js', 'css'].includes(ext):
|
||||
result = FileType.Code;
|
||||
break;
|
||||
case 'eml' === ext || ['message/delivery-status', 'message/rfc822'].includes(mimeType):
|
||||
result = FileType.Eml;
|
||||
break;
|
||||
case ('text' === mimeTypeParts[0] && 'html' !== mimeTypeParts[1]) || ['txt', 'log'].includes(ext):
|
||||
result = FileType.Text;
|
||||
break;
|
||||
case 'text/html' === mimeType || ['html'].includes(ext):
|
||||
result = FileType.Html;
|
||||
break;
|
||||
case [
|
||||
'zip',
|
||||
'7z',
|
||||
'tar',
|
||||
'rar',
|
||||
'gzip',
|
||||
'bzip',
|
||||
'bzip2',
|
||||
'x-zip',
|
||||
'x-7z',
|
||||
'x-rar',
|
||||
'x-tar',
|
||||
'x-gzip',
|
||||
'x-bzip',
|
||||
'x-bzip2',
|
||||
'x-zip-compressed',
|
||||
'x-7z-compressed',
|
||||
'x-rar-compressed'
|
||||
].includes(mimeTypeParts[1]) || ['zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2'].includes(ext):
|
||||
result = FileType.Archive;
|
||||
break;
|
||||
case ['pdf', 'x-pdf'].includes(mimeTypeParts[1]) || ['pdf'].includes(ext):
|
||||
result = FileType.Pdf;
|
||||
break;
|
||||
case ['application/pgp-signature', 'application/pgp-keys'].includes(mimeType) ||
|
||||
['asc', 'pem', 'ppk'].includes(ext):
|
||||
result = FileType.Certificate;
|
||||
break;
|
||||
case ['application/pkcs7-signature'].includes(mimeType) || ['p7s'].includes(ext):
|
||||
result = FileType.CertificateBin;
|
||||
break;
|
||||
case [
|
||||
'rtf',
|
||||
'msword',
|
||||
'vnd.msword',
|
||||
'vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
'vnd.ms-word.document.macroEnabled.12',
|
||||
'vnd.ms-word.template.macroEnabled.12'
|
||||
].includes(mimeTypeParts[1]):
|
||||
result = FileType.WordText;
|
||||
break;
|
||||
case [
|
||||
'excel',
|
||||
'ms-excel',
|
||||
'vnd.ms-excel',
|
||||
'vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'vnd.openxmlformats-officedocument.spreadsheetml.template',
|
||||
'vnd.ms-excel.sheet.macroEnabled.12',
|
||||
'vnd.ms-excel.template.macroEnabled.12',
|
||||
'vnd.ms-excel.addin.macroEnabled.12',
|
||||
'vnd.ms-excel.sheet.binary.macroEnabled.12'
|
||||
].includes(mimeTypeParts[1]):
|
||||
result = FileType.Sheet;
|
||||
break;
|
||||
case [
|
||||
'powerpoint',
|
||||
'ms-powerpoint',
|
||||
'vnd.ms-powerpoint',
|
||||
'vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'vnd.openxmlformats-officedocument.presentationml.template',
|
||||
'vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||
'vnd.ms-powerpoint.addin.macroEnabled.12',
|
||||
'vnd.ms-powerpoint.presentation.macroEnabled.12',
|
||||
'vnd.ms-powerpoint.template.macroEnabled.12',
|
||||
'vnd.ms-powerpoint.slideshow.macroEnabled.12'
|
||||
].includes(mimeTypeParts[1]):
|
||||
result = FileType.Presentation;
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
let result = FileType.Unknown;
|
||||
const mimeTypeParts = mimeType.split('/');
|
||||
|
||||
return result;
|
||||
});
|
||||
switch (true) {
|
||||
case 'image' === mimeTypeParts[0] || ['png', 'jpg', 'jpeg', 'gif', 'bmp'].includes(ext):
|
||||
result = FileType.Image;
|
||||
break;
|
||||
case 'audio' === mimeTypeParts[0] || ['mp3', 'ogg', 'oga', 'wav'].includes(ext):
|
||||
result = FileType.Audio;
|
||||
break;
|
||||
case 'video' === mimeTypeParts[0] || ['mkv', 'avi'].includes(ext):
|
||||
result = FileType.Video;
|
||||
break;
|
||||
case ['php', 'js', 'css'].includes(ext):
|
||||
result = FileType.Code;
|
||||
break;
|
||||
case 'eml' === ext || ['message/delivery-status', 'message/rfc822'].includes(mimeType):
|
||||
result = FileType.Eml;
|
||||
break;
|
||||
case ('text' === mimeTypeParts[0] && 'html' !== mimeTypeParts[1]) || ['txt', 'log'].includes(ext):
|
||||
result = FileType.Text;
|
||||
break;
|
||||
case 'text/html' === mimeType || ['html'].includes(ext):
|
||||
result = FileType.Html;
|
||||
break;
|
||||
case [
|
||||
'zip',
|
||||
'7z',
|
||||
'tar',
|
||||
'rar',
|
||||
'gzip',
|
||||
'bzip',
|
||||
'bzip2',
|
||||
'x-zip',
|
||||
'x-7z',
|
||||
'x-rar',
|
||||
'x-tar',
|
||||
'x-gzip',
|
||||
'x-bzip',
|
||||
'x-bzip2',
|
||||
'x-zip-compressed',
|
||||
'x-7z-compressed',
|
||||
'x-rar-compressed'
|
||||
].includes(mimeTypeParts[1]) || ['zip', '7z', 'tar', 'rar', 'gzip', 'bzip', 'bzip2'].includes(ext):
|
||||
result = FileType.Archive;
|
||||
break;
|
||||
case ['pdf', 'x-pdf'].includes(mimeTypeParts[1]) || ['pdf'].includes(ext):
|
||||
result = FileType.Pdf;
|
||||
break;
|
||||
case ['application/pgp-signature', 'application/pgp-keys'].includes(mimeType) ||
|
||||
['asc', 'pem', 'ppk'].includes(ext):
|
||||
result = FileType.Certificate;
|
||||
break;
|
||||
case ['application/pkcs7-signature'].includes(mimeType) || ['p7s'].includes(ext):
|
||||
result = FileType.CertificateBin;
|
||||
break;
|
||||
case [
|
||||
'rtf',
|
||||
'msword',
|
||||
'vnd.msword',
|
||||
'vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
'vnd.ms-word.document.macroEnabled.12',
|
||||
'vnd.ms-word.template.macroEnabled.12'
|
||||
].includes(mimeTypeParts[1]):
|
||||
result = FileType.WordText;
|
||||
break;
|
||||
case [
|
||||
'excel',
|
||||
'ms-excel',
|
||||
'vnd.ms-excel',
|
||||
'vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'vnd.openxmlformats-officedocument.spreadsheetml.template',
|
||||
'vnd.ms-excel.sheet.macroEnabled.12',
|
||||
'vnd.ms-excel.template.macroEnabled.12',
|
||||
'vnd.ms-excel.addin.macroEnabled.12',
|
||||
'vnd.ms-excel.sheet.binary.macroEnabled.12'
|
||||
].includes(mimeTypeParts[1]):
|
||||
result = FileType.Sheet;
|
||||
break;
|
||||
case [
|
||||
'powerpoint',
|
||||
'ms-powerpoint',
|
||||
'vnd.ms-powerpoint',
|
||||
'vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'vnd.openxmlformats-officedocument.presentationml.template',
|
||||
'vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||
'vnd.ms-powerpoint.addin.macroEnabled.12',
|
||||
'vnd.ms-powerpoint.presentation.macroEnabled.12',
|
||||
'vnd.ms-powerpoint.template.macroEnabled.12',
|
||||
'vnd.ms-powerpoint.slideshow.macroEnabled.12'
|
||||
].includes(mimeTypeParts[1]):
|
||||
result = FileType.Presentation;
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
|
||||
return cache[key] = result;
|
||||
};
|
||||
})();
|
||||
|
||||
/**
|
||||
* @param {string} sFileType
|
||||
* @returns {string}
|
||||
*/
|
||||
export const staticIconClass = _.memoize((fileType) => {
|
||||
let resultText = '',
|
||||
resultClass = 'icon-file';
|
||||
|
||||
switch (fileType) {
|
||||
case FileType.Text:
|
||||
case FileType.Eml:
|
||||
case FileType.WordText:
|
||||
resultClass = 'icon-file-text';
|
||||
break;
|
||||
case FileType.Html:
|
||||
case FileType.Code:
|
||||
resultClass = 'icon-file-code';
|
||||
break;
|
||||
case FileType.Image:
|
||||
resultClass = 'icon-file-image';
|
||||
break;
|
||||
case FileType.Audio:
|
||||
resultClass = 'icon-file-music';
|
||||
break;
|
||||
case FileType.Video:
|
||||
resultClass = 'icon-file-movie';
|
||||
break;
|
||||
case FileType.Archive:
|
||||
resultClass = 'icon-file-zip';
|
||||
break;
|
||||
case FileType.Certificate:
|
||||
case FileType.CertificateBin:
|
||||
resultClass = 'icon-file-certificate';
|
||||
break;
|
||||
case FileType.Sheet:
|
||||
resultClass = 'icon-file-excel';
|
||||
break;
|
||||
case FileType.Presentation:
|
||||
resultClass = 'icon-file-chart-graph';
|
||||
break;
|
||||
case FileType.Pdf:
|
||||
resultText = 'pdf';
|
||||
resultClass = 'icon-none';
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
|
||||
return [resultClass, resultText];
|
||||
});
|
||||
export const staticIconClass = fileType => FileType.getIconClass(fileType);
|
||||
|
||||
/**
|
||||
* @static
|
||||
|
@ -187,7 +150,8 @@ export const staticCombinedIconClass = (data) => {
|
|||
|
||||
if (isNonEmptyArray(data)) {
|
||||
result = 'icon-attachment';
|
||||
types = _.uniq(_.compact(data.map(item => (item ? staticFileType(getFileExtension(item[0]), item[1]) : ''))));
|
||||
types = data.map(item => item ? staticFileType(getFileExtension(item[0]), item[1]) : '')
|
||||
.filter((value, index, self) => !!value && self.indexOf(value) == index);
|
||||
|
||||
if (types && 1 === types.length && types[0]) {
|
||||
switch (types[0]) {
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import _ from '_';
|
||||
import addressparser from 'emailjs-addressparser';
|
||||
import { trim, encodeHtml, isNonEmptyArray } from 'Common/Utils';
|
||||
|
||||
|
@ -184,11 +183,9 @@ class EmailModel {
|
|||
static parseEmailLine(line) {
|
||||
const parsedResult = addressparser(line);
|
||||
if (isNonEmptyArray(parsedResult)) {
|
||||
return _.compact(
|
||||
parsedResult.map(item =>
|
||||
item.address ? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '') : null
|
||||
)
|
||||
);
|
||||
return parsedResult.map(item =>
|
||||
item.address ? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '') : null
|
||||
).filter(value => !!value);
|
||||
}
|
||||
|
||||
return [];
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import _ from '_';
|
||||
import ko from 'ko';
|
||||
|
||||
import { FilterRulesType, FiltersAction } from 'Common/Enums';
|
||||
|
@ -230,12 +229,10 @@ class FilterModel extends AbstractModel {
|
|||
|
||||
if (isNonEmptyArray(json.Conditions)) {
|
||||
this.conditions(
|
||||
_.compact(
|
||||
json.Conditions.map(aData => {
|
||||
const filterCondition = new FilterConditionModel();
|
||||
return filterCondition && filterCondition.parse(aData) ? filterCondition : null;
|
||||
})
|
||||
)
|
||||
json.Conditions.map(aData => {
|
||||
const filterCondition = new FilterConditionModel();
|
||||
return filterCondition && filterCondition.parse(aData) ? filterCondition : null;
|
||||
}).filter(value => !!value)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import _ from '_';
|
||||
import $ from '$';
|
||||
import ko from 'ko';
|
||||
import moment from 'moment';
|
||||
|
@ -200,13 +199,9 @@ class MessageModel extends AbstractModel {
|
|||
* @returns {Array}
|
||||
*/
|
||||
getEmails(properties) {
|
||||
return _.compact(
|
||||
_.uniq(
|
||||
_.reduce(properties, (carry, property) => carry.concat(this[property]), []).map(
|
||||
(oItem) => (oItem ? oItem.email : '')
|
||||
)
|
||||
)
|
||||
);
|
||||
return properties.reduce((carry, property) => carry.concat(this[property]), []).map(
|
||||
oItem => oItem ? oItem.email : ''
|
||||
).filter((value, index, self) => !!value && self.indexOf(value) == index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import _ from '_';
|
||||
import ko from 'ko';
|
||||
|
||||
import { windowResizeCallback, isArray, trim, delegateRunOnDestroy } from 'Common/Utils';
|
||||
|
@ -113,12 +112,10 @@ class FiltersUserSettings {
|
|||
this.serverError(false);
|
||||
|
||||
this.filters(
|
||||
_.compact(
|
||||
data.Result.Filters.map(aItem => {
|
||||
const filter = new FilterModel();
|
||||
return filter && filter.parse(aItem) ? filter : null;
|
||||
})
|
||||
)
|
||||
data.Result.Filters.map(aItem => {
|
||||
const filter = new FilterModel();
|
||||
return filter && filter.parse(aItem) ? filter : null;
|
||||
}).filter(value => !!value)
|
||||
);
|
||||
|
||||
this.modules(data.Result.Modules ? data.Result.Modules : {});
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import ko from 'ko';
|
||||
import _ from '_';
|
||||
import { Magics } from 'Common/Enums';
|
||||
import * as Settings from 'Storage/Settings';
|
||||
|
||||
|
@ -17,7 +16,9 @@ class AccountUserStore {
|
|||
}
|
||||
|
||||
computers() {
|
||||
this.accountsEmails = ko.computed(() => _.compact(this.accounts().map(item => (item ? item.email : null))));
|
||||
this.accountsEmails = ko.computed(
|
||||
() => this.accounts().map(item => (item ? item.email : null)).filter(value => !!value)
|
||||
);
|
||||
|
||||
this.accountsUnreadCount = ko.computed(() => 0);
|
||||
// this.accountsUnreadCount = ko.computed(() => {
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import ko from 'ko';
|
||||
import _ from '_';
|
||||
|
||||
import { settingsGet } from 'Storage/Settings';
|
||||
|
||||
|
@ -95,7 +94,7 @@ class FolderUserStore {
|
|||
});
|
||||
|
||||
this.folderListSystem = ko.computed(() =>
|
||||
_.compact(this.folderListSystemNames().map(name => getFolderFromCacheList(name)))
|
||||
this.folderListSystemNames().map(name => getFolderFromCacheList(name)).filter(value => !!value)
|
||||
);
|
||||
|
||||
this.folderMenuForMove = ko.computed(() =>
|
||||
|
@ -203,7 +202,7 @@ class FolderUserStore {
|
|||
return limit <= result.length;
|
||||
});
|
||||
|
||||
return _.uniq(result);
|
||||
return result.filter((value, index, self) => self.indexOf(value) == index);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import _ from '_';
|
||||
import ko from 'ko';
|
||||
|
||||
class IdentityUserStore {
|
||||
|
@ -6,7 +5,9 @@ class IdentityUserStore {
|
|||
this.identities = ko.observableArray([]);
|
||||
this.identities.loading = ko.observable(false).extend({ throttle: 100 });
|
||||
|
||||
this.identitiesIDS = ko.computed(() => _.compact(this.identities().map(item => (item ? item.id : null))));
|
||||
this.identitiesIDS = ko.computed(
|
||||
() => this.identities().map(item => (item ? item.id : null)).filter(value => !!value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -153,7 +153,9 @@ class MessageUserStore {
|
|||
focusedMessage = this.selectorMessageFocused();
|
||||
|
||||
if (checked.length) {
|
||||
return _.union(checked, selectedMessage ? [selectedMessage] : []);
|
||||
return selectedMessage
|
||||
? checked.concat([selectedMessage]).filter((value, index, self) => self.indexOf(value) == index)
|
||||
: checked;
|
||||
} else if (selectedMessage) {
|
||||
return [selectedMessage];
|
||||
}
|
||||
|
@ -167,7 +169,7 @@ class MessageUserStore {
|
|||
if (message) {
|
||||
result.push(message.uid);
|
||||
if (1 < message.threadsLen()) {
|
||||
result = _.union(result, message.threads());
|
||||
result = result.concat(message.threads()).filter((value, index, self) => self.indexOf(value) == index);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -42,62 +42,36 @@ class PgpUserStore {
|
|||
}
|
||||
|
||||
findPublicKeysByEmail(email) {
|
||||
return _.compact(
|
||||
_.flatten(
|
||||
this.openpgpkeysPublic().map(item => {
|
||||
const key = item && item.emails.includes(email) ? item : null;
|
||||
return key ? key.getNativeKeys() : [null];
|
||||
}),
|
||||
true
|
||||
)
|
||||
);
|
||||
return this.openpgpkeysPublic().map(item => {
|
||||
const key = item && item.emails.includes(email) ? item : null;
|
||||
return key ? key.getNativeKeys() : [null];
|
||||
}).flat().filter(value => !!value);
|
||||
}
|
||||
|
||||
findPublicKeysBySigningKeyIds(signingKeyIds) {
|
||||
return _.compact(
|
||||
_.flatten(
|
||||
signingKeyIds.map(id => {
|
||||
const key = id && id.toHex ? this.findPublicKeyByHex(id.toHex()) : null;
|
||||
return key ? key.getNativeKeys() : [null];
|
||||
}),
|
||||
true
|
||||
)
|
||||
);
|
||||
return signingKeyIds.map(id => {
|
||||
const key = id && id.toHex ? this.findPublicKeyByHex(id.toHex()) : null;
|
||||
return key ? key.getNativeKeys() : [null];
|
||||
}).flat().filter(value => !!value);
|
||||
}
|
||||
|
||||
findPrivateKeysByEncryptionKeyIds(encryptionKeyIds, recipients, returnWrapKeys) {
|
||||
let result = isArray(encryptionKeyIds)
|
||||
? _.compact(
|
||||
_.flatten(
|
||||
encryptionKeyIds.map(id => {
|
||||
const key = id && id.toHex ? this.findPrivateKeyByHex(id.toHex()) : null;
|
||||
return key ? (returnWrapKeys ? [key] : key.getNativeKeys()) : [null];
|
||||
}),
|
||||
true
|
||||
)
|
||||
)
|
||||
? encryptionKeyIds.map(id => {
|
||||
const key = id && id.toHex ? this.findPrivateKeyByHex(id.toHex()) : null;
|
||||
return key ? (returnWrapKeys ? [key] : key.getNativeKeys()) : [null];
|
||||
}).flat().filter(value => !!value)
|
||||
: [];
|
||||
|
||||
if (0 === result.length && isNonEmptyArray(recipients)) {
|
||||
result = _.uniq(
|
||||
_.compact(
|
||||
_.flatten(
|
||||
recipients.map(sEmail => {
|
||||
const keys = sEmail ? this.findAllPrivateKeysByEmailNotNative(sEmail) : null;
|
||||
return keys
|
||||
? returnWrapKeys
|
||||
? keys
|
||||
: _.flatten(
|
||||
keys.map(key => key.getNativeKeys()),
|
||||
true
|
||||
)
|
||||
: [null];
|
||||
}),
|
||||
true
|
||||
)
|
||||
),
|
||||
(key) => key.id
|
||||
);
|
||||
result = recipients.map(sEmail => {
|
||||
const keys = sEmail ? this.findAllPrivateKeysByEmailNotNative(sEmail) : null;
|
||||
return keys
|
||||
? returnWrapKeys
|
||||
? keys
|
||||
: keys.map(key => key.getNativeKeys()).flat()
|
||||
: [null];
|
||||
}).flat().filter((key, index, self) => key => !!key.id && self.indexOf(key) == index);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -297,7 +271,7 @@ class PgpUserStore {
|
|||
} else if (validPrivateKey) {
|
||||
const keyIds = isNonEmptyArray(signingKeyIds) ? signingKeyIds : null,
|
||||
additional = keyIds
|
||||
? _.compact(keyIds.map(item => (item && item.toHex ? item.toHex() : null))).join(', ')
|
||||
? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(value => !!value).join(', ')
|
||||
: '';
|
||||
|
||||
store.controlsHelper(
|
||||
|
@ -354,7 +328,7 @@ class PgpUserStore {
|
|||
} else {
|
||||
const keyIds = isNonEmptyArray(signingKeyIds) ? signingKeyIds : null,
|
||||
additional = keyIds
|
||||
? _.compact(keyIds.map(item => (item && item.toHex ? item.toHex() : null))).join(', ')
|
||||
? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(value => !!value).join(', ')
|
||||
: '';
|
||||
|
||||
store.controlsHelper(
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import ko from 'ko';
|
||||
import _ from '_';
|
||||
|
||||
// import Remote from 'Remote/User/Ajax';
|
||||
|
||||
|
@ -16,7 +15,7 @@ class TemplateUserStore {
|
|||
|
||||
subscribers() {
|
||||
this.templates.subscribe((list) => {
|
||||
this.templatesNames(_.compact(list.map(item => (item ? item.name : null))));
|
||||
this.templatesNames(list.map(item => (item ? item.name : null)).filter(value => !!value));
|
||||
});
|
||||
|
||||
// this.templatesNames.subscribe((aList) => {
|
||||
|
|
|
@ -600,13 +600,13 @@ class ComposePopupView extends AbstractViewNext {
|
|||
case ComposeType.ReplyAll:
|
||||
case ComposeType.Forward:
|
||||
case ComposeType.ForwardAsAttachment:
|
||||
_.union(message.to, message.cc, message.bcc).forEach(fEachHelper);
|
||||
message.to.concat(message.cc, message.bcc).forEach(fEachHelper);
|
||||
if (!resultIdentity) {
|
||||
message.deliveredTo.forEach(fEachHelper);
|
||||
}
|
||||
break;
|
||||
case ComposeType.Draft:
|
||||
_.union(message.from, message.replyTo).forEach(fEachHelper);
|
||||
message.from.concat(message.replyTo).forEach(fEachHelper);
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
|
@ -859,7 +859,8 @@ class ComposePopupView extends AbstractViewNext {
|
|||
addEmailsTo(fKoValue, emails) {
|
||||
if (isNonEmptyArray(emails)) {
|
||||
const value = trim(fKoValue()),
|
||||
values = _.uniq(_.compact(emails.map(item => (item ? item.toLine(false) : null))));
|
||||
values = emails.map(item => item ? item.toLine(false) : null)
|
||||
.filter((value, index, self) => !!value && self.indexOf(value) == index);
|
||||
|
||||
fKoValue(value + ('' === value ? '' : ', ') + trim(values.join(', ')));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import _ from '_';
|
||||
import $ from '$';
|
||||
import ko from 'ko';
|
||||
import key from 'key';
|
||||
|
@ -44,7 +43,9 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
|
|||
this.signKey = ko.observable(null);
|
||||
this.encryptKeys = ko.observableArray([]);
|
||||
|
||||
this.encryptKeysView = ko.computed(() => _.compact(this.encryptKeys().map(oKey => (oKey ? oKey.key : null))));
|
||||
this.encryptKeysView = ko.computed(
|
||||
() => this.encryptKeys().map(oKey => (oKey ? oKey.key : null)).filter(value => !!value)
|
||||
);
|
||||
|
||||
this.privateKeysOptions = ko.computed(() => {
|
||||
const opts = PgpStore.openpgpkeysPrivate().map((oKey, iIndex) => {
|
||||
|
@ -59,7 +60,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
|
|||
}));
|
||||
});
|
||||
|
||||
return _.compact(_.flatten(opts, true));
|
||||
return opts.flat().filter(value => !!value);
|
||||
});
|
||||
|
||||
this.publicKeysOptions = ko.computed(() => {
|
||||
|
@ -74,7 +75,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
|
|||
'class': index % 2 ? 'odd' : 'even'
|
||||
}));
|
||||
});
|
||||
return _.compact(_.flatten(opts, true));
|
||||
return opts.flat().filter(value => !!value);
|
||||
});
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
|
@ -159,7 +160,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
|
|||
|
||||
this.encryptKeys().forEach(oKey => {
|
||||
if (oKey && oKey.key) {
|
||||
aPublicKeys = aPublicKeys.concat(_.compact(_.flatten(oKey.key.getNativeKeys())));
|
||||
aPublicKeys = aPublicKeys.concat(oKey.key.getNativeKeys().flat(Infinity).filter(value => !!value));
|
||||
} else if (oKey && oKey.email) {
|
||||
this.notification(
|
||||
i18n('PGP_NOTIFICATIONS/NO_PUBLIC_KEYS_FOUND_FOR', {
|
||||
|
@ -355,13 +356,11 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
|
|||
}
|
||||
|
||||
rec = rec.join(', ').split(',');
|
||||
rec = _.compact(
|
||||
rec.map(value => {
|
||||
rec = rec.map(value => {
|
||||
email.clear();
|
||||
email.parse(trim(value));
|
||||
return '' === email.email ? false : email.email;
|
||||
})
|
||||
);
|
||||
}).filter(value => !!value);
|
||||
|
||||
if (identity && identity.email()) {
|
||||
emailLine = identity.email();
|
||||
|
@ -383,28 +382,22 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
|
|||
|
||||
if (rec && 0 < rec.length) {
|
||||
this.encryptKeys(
|
||||
_.uniq(
|
||||
_.compact(
|
||||
_.flatten(
|
||||
rec.map(recEmail => {
|
||||
const keys = PgpStore.findAllPublicKeysByEmailNotNative(recEmail);
|
||||
return keys
|
||||
? keys.map(publicKey => ({
|
||||
'empty': !publicKey,
|
||||
'selected': ko.observable(!!publicKey),
|
||||
'removable': ko.observable(
|
||||
!this.sign() || !this.signKey() || this.signKey().key.id !== publicKey.id
|
||||
),
|
||||
'users': publicKey ? publicKey.users || [recEmail] : [recEmail],
|
||||
'hash': publicKey ? publicKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() : '',
|
||||
'key': publicKey
|
||||
}))
|
||||
: [];
|
||||
}),
|
||||
true
|
||||
)
|
||||
),
|
||||
(encryptKey) => encryptKey.hash
|
||||
rec.map(recEmail => {
|
||||
const keys = PgpStore.findAllPublicKeysByEmailNotNative(recEmail);
|
||||
return keys
|
||||
? keys.map(publicKey => ({
|
||||
'empty': !publicKey,
|
||||
'selected': ko.observable(!!publicKey),
|
||||
'removable': ko.observable(
|
||||
!this.sign() || !this.signKey() || this.signKey().key.id !== publicKey.id
|
||||
),
|
||||
'users': publicKey ? publicKey.users || [recEmail] : [recEmail],
|
||||
'hash': publicKey ? publicKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() : '',
|
||||
'key': publicKey
|
||||
}))
|
||||
: [];
|
||||
}).flat().filter(
|
||||
(encryptKey, index, self) => encryptKey => !!encryptKey.hash && self.indexOf(encryptKey) == index
|
||||
)
|
||||
);
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import window from 'window';
|
||||
import _ from '_';
|
||||
import $ from '$';
|
||||
import ko from 'ko';
|
||||
import key from 'key';
|
||||
|
@ -171,7 +170,9 @@ class ContactsPopupView extends AbstractViewNext {
|
|||
const checked = this.contactsChecked(),
|
||||
selected = this.currentContact();
|
||||
|
||||
return _.union(checked, selected ? [selected] : []);
|
||||
return selected
|
||||
? checked.concat([selected]).filter((value, index, self) => self.indexOf(value) == index)
|
||||
: checked;
|
||||
});
|
||||
|
||||
this.contactsCheckedOrSelectedUids = ko.computed(() =>
|
||||
|
@ -253,7 +254,7 @@ class ContactsPopupView extends AbstractViewNext {
|
|||
return null;
|
||||
});
|
||||
|
||||
aE = _.compact(aE);
|
||||
aE = aE.filter(value => !!value);
|
||||
}
|
||||
|
||||
if (isNonEmptyArray(aE)) {
|
||||
|
@ -596,7 +597,7 @@ class ContactsPopupView extends AbstractViewNext {
|
|||
return contact.parse(item) ? contact : null;
|
||||
});
|
||||
|
||||
list = _.compact(list);
|
||||
list = list.filter(value => !!value);
|
||||
|
||||
count = pInt(data.Result.Count);
|
||||
count = 0 < count ? count : 0;
|
||||
|
|
|
@ -453,11 +453,11 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
|||
// aTo = [],
|
||||
// EmailModel = require('Model/Email').default,
|
||||
// fParseEmailLine = function(sLine) {
|
||||
// return sLine ? _.compact([window.decodeURIComponent(sLine)].map(sItem => {
|
||||
// return sLine ? [window.decodeURIComponent(sLine)].map(sItem => {
|
||||
// var oEmailModel = new EmailModel();
|
||||
// oEmailModel.parse(sItem);
|
||||
// return '' !== oEmailModel.email ? oEmailModel : null;
|
||||
// })) : null;
|
||||
// }).filter(value => !!value) : null;
|
||||
// }
|
||||
// ;
|
||||
//
|
||||
|
@ -477,26 +477,24 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
|||
listIndex = 0;
|
||||
|
||||
const div = $('<div>'),
|
||||
dynamicEls = _.compact(
|
||||
this.message().attachments().map(item => {
|
||||
if (item && !item.isLinked && item.isImage()) {
|
||||
if (item === attachment) {
|
||||
index = listIndex;
|
||||
}
|
||||
|
||||
listIndex += 1;
|
||||
|
||||
return {
|
||||
src: item.linkPreview(),
|
||||
thumb: item.linkThumbnail(),
|
||||
subHtml: item.fileName,
|
||||
downloadUrl: item.linkPreview()
|
||||
};
|
||||
dynamicEls = this.message().attachments().map(item => {
|
||||
if (item && !item.isLinked && item.isImage()) {
|
||||
if (item === attachment) {
|
||||
index = listIndex;
|
||||
}
|
||||
|
||||
return null;
|
||||
})
|
||||
);
|
||||
listIndex += 1;
|
||||
|
||||
return {
|
||||
src: item.linkPreview(),
|
||||
thumb: item.linkThumbnail(),
|
||||
subHtml: item.fileName,
|
||||
downloadUrl: item.linkPreview()
|
||||
};
|
||||
}
|
||||
|
||||
return null;
|
||||
}).filter(value => !!value);
|
||||
|
||||
if (0 < dynamicEls.length) {
|
||||
div.on('onBeforeOpen.lg', () => {
|
||||
|
@ -885,7 +883,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
|||
|
||||
getAttachmentsHashes() {
|
||||
const atts = this.message() ? this.message().attachments() : [];
|
||||
return _.compact(atts.map(item => (item && !item.isLinked && item.checked() ? item.download : '')));
|
||||
return atts.map(item => (item && !item.isLinked && item.checked() ? item.download : '')).filter(value => !!value);
|
||||
}
|
||||
|
||||
downloadAsZip() {
|
||||
|
|
16
dev/polyfill.js
Normal file
16
dev/polyfill.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
|
||||
Array.prototype.flat || Object.defineProperty(Array.prototype, 'flat', {
|
||||
configurable: true,
|
||||
value: function flat(depth) {
|
||||
depth = isNaN(depth) ? 1 : Number(depth);
|
||||
return depth ? Array.prototype.reduce.call(this, (acc, cur) => {
|
||||
if (Array.isArray(cur)) {
|
||||
acc.push.apply(acc, flat.call(cur, depth - 1));
|
||||
} else {
|
||||
acc.push(cur);
|
||||
}
|
||||
return acc;
|
||||
}, []) : this.slice();
|
||||
},
|
||||
writable: true
|
||||
});
|
|
@ -103,8 +103,7 @@
|
|||
"raw-loader": "4.0.0",
|
||||
"rimraf": "3.0.2",
|
||||
"simplestatemanager": "4.1.1",
|
||||
"style-loader": "1.1.3",
|
||||
"underscore": "1.9.2"
|
||||
"style-loader": "1.1.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"gulp-terser": "^1.2.0",
|
||||
|
|
|
@ -72,7 +72,8 @@ config.paths.js = {
|
|||
libs: {
|
||||
name: 'libs.js',
|
||||
src: [
|
||||
'node_modules/jquery/dist/jquery.min.js',
|
||||
'dev/polyfill.js',
|
||||
'node_modules/jquery/dist/jquery.slim.min.js',
|
||||
'vendors/jquery-ui/js/jquery-ui-1.12.1.custom.min.js', // custom
|
||||
'vendors/inputosaurus/inputosaurus.js', // custom (modified)
|
||||
'vendors/routes/signals.min.js', // fixed
|
||||
|
@ -82,7 +83,7 @@ config.paths.js = {
|
|||
'vendors/keymaster/keymaster.js', // custom (modified)
|
||||
'vendors/qr.js/qr.min.js', // fixed (license)
|
||||
'vendors/bootstrap/js/bootstrap.min.js', // fixed
|
||||
'node_modules/underscore/underscore-min.js',
|
||||
'vendors/underscore/underscore-min.custom.js',
|
||||
'node_modules/moment/min/moment.min.js',
|
||||
'node_modules/knockout/build/output/knockout-latest.js',
|
||||
'node_modules/knockout-sortable/build/knockout-sortable.min.js ',
|
||||
|
|
6
vendors/underscore/underscore-min.custom.js
vendored
Normal file
6
vendors/underscore/underscore-min.custom.js
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Underscore.js 1.9.2
|
||||
// https://underscorejs.org
|
||||
// (c) 2009-2018 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||
// Underscore may be freely distributed under the MIT license.
|
||||
|
||||
(()=>{var e=function(t){return t instanceof e?t:this instanceof e?void 0:new e(t)};"undefined"==typeof exports||exports.nodeType?("object"==typeof self&&self.self===self&&self||"object"==typeof global&&global.global===global&&global||this||{})._=e:("undefined"!=typeof module&&!module.nodeType&&module.exports&&(exports=module.exports=e),exports._=e);e.VERSION="1.9.2";var t=function(e,t,n,o,l){if(!(o instanceof t))return e.apply(n,l);var r,u="object"!=typeof(r=e.prototype)?{}:Object.create(r),i=e.apply(u,l);return"object"==typeof i?i:u};e.defer=(()=>{var e=(e,t,...n)=>setTimeout(()=>e.apply(null,n),t),n=function(...o){for(var l=0,r=[o[l++],1];l<o.length;)r.push(o[l++]);return t(e,n,this,this,r)};return n})(),e.throttle=function(e,t,n){var o,l,r,u,i=0;n||(n={});var a=function(){i=!1===n.leading?0:Date.now(),o=null,u=e.apply(l,r),o||(l=r=null)},f=function(){var f=Date.now();i||!1!==n.leading||(i=f);var p=t-(f-i);return l=this,r=arguments,p<=0||p>t?(o&&(clearTimeout(o),o=null),i=f,u=e.apply(l,r),o||(l=r=null)):o||!1===n.trailing||(o=setTimeout(a,p)),u};return f.cancel=function(){clearTimeout(o),i=0,o=l=r=null},f},e.debounce=function(e,t,n){var o,l,r=function(t,n){o=null,n&&(l=e.apply(t,n))},u=function(...u){if(o&&clearTimeout(o),n){var i=!o;o=setTimeout(r,t),i&&(l=e.apply(this,u))}else{var a=this;o=setTimeout(()=>r.apply(null,[a,u]),t)}return l};return u.cancel=function(){clearTimeout(o),o=null},u},"function"==typeof define&&define.amd&&define("underscore",[],function(){return e})})();
|
169
vendors/underscore/underscore.custom.js
vendored
Normal file
169
vendors/underscore/underscore.custom.js
vendored
Normal file
|
@ -0,0 +1,169 @@
|
|||
// Underscore.js 1.9.2
|
||||
// https://underscorejs.org
|
||||
// (c) 2009-2018 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
|
||||
// Underscore may be freely distributed under the MIT license.
|
||||
/*
|
||||
_.debounce
|
||||
_.defer
|
||||
_.throttle
|
||||
*/
|
||||
|
||||
(() => {
|
||||
|
||||
// Baseline setup
|
||||
// --------------
|
||||
|
||||
// Create a safe reference to the Underscore object for use below.
|
||||
var _ = function(obj) {
|
||||
if (obj instanceof _) return obj;
|
||||
if (!(this instanceof _)) return new _(obj);
|
||||
};
|
||||
|
||||
// Export the Underscore object for **Node.js**, with
|
||||
// backwards-compatibility for their old module API. If we're in
|
||||
// the browser, add `_` as a global object.
|
||||
// (`nodeType` is checked to ensure that `module`
|
||||
// and `exports` are not HTML elements.)
|
||||
if (typeof exports != 'undefined' && !exports.nodeType) {
|
||||
if (typeof module != 'undefined' && !module.nodeType && module.exports) {
|
||||
exports = module.exports = _;
|
||||
}
|
||||
exports._ = _;
|
||||
} else {
|
||||
// Establish the root object, `window` (`self`) in the browser, `global`
|
||||
// on the server, or `this` in some virtual machines. We use `self`
|
||||
// instead of `window` for `WebWorker` support.
|
||||
var root = typeof self == 'object' && self.self === self && self ||
|
||||
typeof global == 'object' && global.global === global && global ||
|
||||
this ||
|
||||
{};
|
||||
root._ = _;
|
||||
}
|
||||
|
||||
// Current version.
|
||||
_.VERSION = '1.9.2';
|
||||
|
||||
// An internal function for creating a new object that inherits from another.
|
||||
var baseCreate = function(prototype) {
|
||||
if (typeof prototype !== 'object') return {};
|
||||
return Object.create(prototype);
|
||||
};
|
||||
|
||||
// Function (ahem) Functions
|
||||
// ------------------
|
||||
|
||||
// Determines whether to execute a function as a constructor
|
||||
// or a normal function with the provided arguments.
|
||||
var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
|
||||
if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
|
||||
var self = baseCreate(sourceFunc.prototype);
|
||||
var result = sourceFunc.apply(self, args);
|
||||
return (typeof result === 'object') ? result : self;
|
||||
};
|
||||
|
||||
// Defers a function, scheduling it to run after the current call stack has
|
||||
// cleared.
|
||||
_.defer = (() => {
|
||||
var func = (func, wait, ...args) => setTimeout(() => func.apply(null, args), wait);
|
||||
var bound = function(...params) {
|
||||
var position = 0;
|
||||
var args = [params[position++], 1];
|
||||
while (position < params.length) args.push(params[position++]);
|
||||
return executeBound(func, bound, this, this, args);
|
||||
};
|
||||
return bound;
|
||||
})();
|
||||
|
||||
// Returns a function, that, when invoked, will only be triggered at most once
|
||||
// during a given window of time. Normally, the throttled function will run
|
||||
// as much as it can, without ever going more than once per `wait` duration;
|
||||
// but if you'd like to disable the execution on the leading edge, pass
|
||||
// `{leading: false}`. To disable execution on the trailing edge, ditto.
|
||||
_.throttle = function(func, wait, options) {
|
||||
var timeout, context, args, result;
|
||||
var previous = 0;
|
||||
if (!options) options = {};
|
||||
|
||||
var later = function() {
|
||||
previous = options.leading === false ? 0 : Date.now();
|
||||
timeout = null;
|
||||
result = func.apply(context, args);
|
||||
if (!timeout) context = args = null;
|
||||
};
|
||||
|
||||
var throttled = function() {
|
||||
var now = Date.now();
|
||||
if (!previous && options.leading === false) previous = now;
|
||||
var remaining = wait - (now - previous);
|
||||
context = this;
|
||||
args = arguments;
|
||||
if (remaining <= 0 || remaining > wait) {
|
||||
if (timeout) {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
}
|
||||
previous = now;
|
||||
result = func.apply(context, args);
|
||||
if (!timeout) context = args = null;
|
||||
} else if (!timeout && options.trailing !== false) {
|
||||
timeout = setTimeout(later, remaining);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
throttled.cancel = function() {
|
||||
clearTimeout(timeout);
|
||||
previous = 0;
|
||||
timeout = context = args = null;
|
||||
};
|
||||
|
||||
return throttled;
|
||||
};
|
||||
|
||||
// Returns a function, that, as long as it continues to be invoked, will not
|
||||
// be triggered. The function will be called after it stops being called for
|
||||
// N milliseconds. If `immediate` is passed, trigger the function on the
|
||||
// leading edge, instead of the trailing.
|
||||
_.debounce = function(func, wait, immediate) {
|
||||
var timeout, result;
|
||||
|
||||
var later = function(context, args) {
|
||||
timeout = null;
|
||||
if (args) result = func.apply(context, args);
|
||||
};
|
||||
|
||||
var debounced = function(...args) {
|
||||
if (timeout) clearTimeout(timeout);
|
||||
if (immediate) {
|
||||
var callNow = !timeout;
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) result = func.apply(this, args);
|
||||
} else {
|
||||
var obj = this;
|
||||
timeout = setTimeout(() => later.apply(null, [obj, args]), wait);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
debounced.cancel = function() {
|
||||
clearTimeout(timeout);
|
||||
timeout = null;
|
||||
};
|
||||
|
||||
return debounced;
|
||||
};
|
||||
|
||||
// AMD registration happens at the end for compatibility with AMD loaders
|
||||
// that may not enforce next-turn semantics on modules. Even though general
|
||||
// practice for AMD registration is to be anonymous, underscore registers
|
||||
// as a named module because, like jQuery, it is a base library that is
|
||||
// popular enough to be bundled in a third party lib, but not be part of
|
||||
// an AMD load request. Those cases could generate an error when an
|
||||
// anonymous define() is called outside of a loader request.
|
||||
if (typeof define == 'function' && define.amd) {
|
||||
define('underscore', [], function() {
|
||||
return _;
|
||||
});
|
||||
}
|
||||
})();
|
|
@ -6775,11 +6775,6 @@ unc-path-regex@^0.1.2:
|
|||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa"
|
||||
|
||||
underscore@1.9.2:
|
||||
version "1.9.2"
|
||||
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.2.tgz#0c8d6f536d6f378a5af264a72f7bec50feb7cf2f"
|
||||
integrity sha512-D39qtimx0c1fI3ya1Lnhk3E9nONswSKhnffBI0gME9C99fYOkNi04xs8K6pePLhvl1frbDemkaBQ5ikWllR2HQ==
|
||||
|
||||
undertaker-registry@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/undertaker-registry/-/undertaker-registry-1.0.1.tgz#5e4bda308e4a8a2ae584f9b9a4359a499825cc50"
|
||||
|
|
Loading…
Reference in a new issue