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:
djmaze 2020-07-23 16:06:16 +02:00
parent 996a71ad8a
commit dca0ff02ed
27 changed files with 515 additions and 353 deletions

View file

@ -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);

View file

@ -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);

View file

@ -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;
}
};
/**

View file

@ -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,'&amp;')
.replace(gt,'&lt;')
.replace(lt,'&gt;')
.replace(bt,'&#x60;');
if (quote_style & 1) { str = str.replace(sq,'&#x27;'); }
return (quote_style & 2) ? str.replace(dq,'&quot;') : 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
View file

@ -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));
});

View file

@ -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]) {

View file

@ -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 [];

View file

@ -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)
);
}

View file

@ -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);
}
/**

View file

@ -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 : {});

View file

@ -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(() => {

View file

@ -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);
}
}

View file

@ -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)
);
}
}

View file

@ -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);
}
}
});

View file

@ -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(

View file

@ -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) => {

View file

@ -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(', ')));
}

View file

@ -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
)
);

View file

@ -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;

View file

@ -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
View 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
});