Use JavaScript Optional chaining

This commit is contained in:
the-djmaze 2022-09-02 11:52:07 +02:00
parent d9bc435e2c
commit 732b6eb641
55 changed files with 169 additions and 199 deletions

View file

@ -4,7 +4,7 @@ import { addObservablesTo } from 'External/ko';
let notificator = null, let notificator = null,
player = null, player = null,
canPlay = type => player && !!player.canPlayType(type).replace('no', ''), canPlay = type => !!player?.canPlayType(type).replace('no', ''),
audioCtx = window.AudioContext || window.webkitAudioContext, audioCtx = window.AudioContext || window.webkitAudioContext,
@ -92,7 +92,7 @@ export const SMAudio = new class {
} }
pause() { pause() {
player && player.pause(); player?.pause();
fireEvent('audio.stop'); fireEvent('audio.stop');
} }

View file

@ -37,8 +37,7 @@ export const
* @param {string} folderHash * @param {string} folderHash
* @returns {string} * @returns {string}
*/ */
getFolderFullName = folderHash => getFolderFullName = folderHash => (folderHash && FOLDERS_NAME_CACHE[folderHash]) || '',
folderHash && FOLDERS_NAME_CACHE[folderHash] ? FOLDERS_NAME_CACHE[folderHash] : '',
/** /**
* @param {string} folderHash * @param {string} folderHash
@ -79,9 +78,7 @@ export class MessageFlagsCache
* @returns {bool} * @returns {bool}
*/ */
static hasFlag(folderFullName, uid, flag) { static hasFlag(folderFullName, uid, flag) {
return MESSAGE_FLAGS_CACHE[folderFullName] return MESSAGE_FLAGS_CACHE[folderFullName]?.[uid]?.includes(flag);
&& MESSAGE_FLAGS_CACHE[folderFullName][uid]
&& MESSAGE_FLAGS_CACHE[folderFullName][uid].includes(flag);
} }
/** /**
@ -90,7 +87,7 @@ export class MessageFlagsCache
* @returns {?Array} * @returns {?Array}
*/ */
static getFor(folderFullName, uid) { static getFor(folderFullName, uid) {
return MESSAGE_FLAGS_CACHE[folderFullName] && MESSAGE_FLAGS_CACHE[folderFullName][uid]; return MESSAGE_FLAGS_CACHE[folderFullName]?.[uid];
} }
/** /**

View file

@ -256,7 +256,7 @@ export const FileInfo = {
.map(item => item ? FileInfo.getIconClass(FileInfo.getExtension(item.fileName), item.mimeType) : '') .map(item => item ? FileInfo.getIconClass(FileInfo.getExtension(item.fileName), item.mimeType) : '')
.validUnique(); .validUnique();
return (icons && 1 === icons.length && 'icon-file' !== icons[0]) return (1 === icons?.length && 'icon-file' !== icons[0])
? icons[0] ? icons[0]
: 'icon-attachment'; : 'icon-attachment';
} }

View file

@ -56,7 +56,7 @@ fetchFolderInformation = (fCallback, folder, list = []) => {
Remote.request('FolderInformation', fCallback, { Remote.request('FolderInformation', fCallback, {
Folder: folder, Folder: folder,
FlagsUids: uids, FlagsUids: uids,
UidNext: (folderFromCache && folderFromCache.uidNext) || 0 // Used to check for new messages UidNext: folderFromCache?.uidNext || 0 // Used to check for new messages
}); });
} else if (SettingsUserStore.useThreads()) { } else if (SettingsUserStore.useThreads()) {
MessagelistUserStore.reloadFlagsAndCachedMessage(); MessagelistUserStore.reloadFlagsAndCachedMessage();
@ -134,7 +134,7 @@ refreshFoldersInterval = 300000,
* @param {Array=} list = [] * @param {Array=} list = []
*/ */
folderInformation = (folder, list) => { folderInformation = (folder, list) => {
if (folder && folder.trim()) { if (folder?.trim()) {
fetchFolderInformation( fetchFolderInformation(
(iError, data) => { (iError, data) => {
if (!iError && data.Result) { if (!iError && data.Result) {

View file

@ -31,7 +31,7 @@ export const
new CustomEvent(name, {detail:detail, cancelable: !!cancelable}) new CustomEvent(name, {detail:detail, cancelable: !!cancelable})
), ),
formFieldFocused = () => doc.activeElement && doc.activeElement.matches('input,textarea'), formFieldFocused = () => doc.activeElement?.matches('input,textarea'),
addShortcut = (...args) => shortcuts.add(...args), addShortcut = (...args) => shortcuts.add(...args),

View file

@ -28,7 +28,7 @@ export const
* @param {string} text * @param {string} text
* @returns {string} * @returns {string}
*/ */
encodeHtml = text => (text && text.toString ? text.toString() : '' + text).replace(htmlre, m => htmlmap[m]), encodeHtml = text => (text?.toString?.() || '' + text).replace(htmlre, m => htmlmap[m]),
/** /**
* Clears the Message Html for viewing * Clears the Message Html for viewing
@ -47,7 +47,7 @@ export const
findAttachmentByCid = cid => oAttachments.findByCid(cid), findAttachmentByCid = cid => oAttachments.findByCid(cid),
findLocationByCid = cid => { findLocationByCid = cid => {
const attachment = findAttachmentByCid(cid); const attachment = findAttachmentByCid(cid);
return attachment && attachment.contentLocation ? attachment : 0; return attachment?.contentLocation ? attachment : 0;
}, },
// convert body attributes to CSS // convert body attributes to CSS
@ -256,7 +256,7 @@ export const
value = value.slice(4); value = value.slice(4);
setAttribute('data-x-src-cid', value); setAttribute('data-x-src-cid', value);
attachment = findAttachmentByCid(value); attachment = findAttachmentByCid(value);
if (attachment && attachment.download) { if (attachment?.download) {
oElement.src = attachment.linkPreview(); oElement.src = attachment.linkPreview();
attachment.isInline(true); attachment.isInline(true);
attachment.isLinked(true); attachment.isLinked(true);
@ -320,7 +320,7 @@ export const
let lowerUrl = found.toLowerCase(); let lowerUrl = found.toLowerCase();
if ('cid:' === lowerUrl.slice(0, 4)) { if ('cid:' === lowerUrl.slice(0, 4)) {
const attachment = findAttachmentByCid(found); const attachment = findAttachmentByCid(found);
if (attachment && attachment.linkPreview && name) { if (attachment?.linkPreview && name) {
oStyle[property] = "url('" + attachment.linkPreview() + "')"; oStyle[property] = "url('" + attachment.linkPreview() + "')";
attachment.isInline(true); attachment.isInline(true);
attachment.isLinked(true); attachment.isLinked(true);
@ -434,9 +434,8 @@ export const
parent = node, parent = node,
ordered = 'OL' == node.tagName, ordered = 'OL' == node.tagName,
i = 0; i = 0;
while (parent && parent.parentNode && parent.parentNode.closest) { while ((parent = parent?.parentNode?.closest('ol,ul'))) {
parent = parent.parentNode.closest('ol,ul'); prefix = ' ' + prefix;
parent && (prefix = ' ' + prefix);
} }
node.querySelectorAll(':scope > li').forEach(li => { node.querySelectorAll(':scope > li').forEach(li => {
li.prepend('\n' + prefix + (ordered ? `${++i}. ` : ' * ')); li.prepend('\n' + prefix + (ordered ? `${++i}. ` : ' * '));
@ -567,7 +566,7 @@ export class HtmlEditor {
editor.on('focus', () => this.blurTimer && clearTimeout(this.blurTimer)); editor.on('focus', () => this.blurTimer && clearTimeout(this.blurTimer));
editor.on('mode', () => { editor.on('mode', () => {
this.blurTrigger(); this.blurTrigger();
this.onModeChange && this.onModeChange(!this.isPlain()); this.onModeChange?.(!this.isPlain());
}); });
} }
} }
@ -575,7 +574,7 @@ export class HtmlEditor {
blurTrigger() { blurTrigger() {
if (this.onBlur) { if (this.onBlur) {
clearTimeout(this.blurTimer); clearTimeout(this.blurTimer);
this.blurTimer = setTimeout(() => this.onBlur && this.onBlur(), 200); this.blurTimer = setTimeout(() => this.onBlur?.(), 200);
} }
} }
@ -685,7 +684,7 @@ export class HtmlEditor {
hasFocus() { hasFocus() {
try { try {
return this.editor && !!this.editor.focusManager.hasFocus; return !!this.editor?.focusManager.hasFocus;
} catch (e) { } catch (e) {
return false; return false;
} }

View file

@ -49,10 +49,7 @@ export function runSettingsViewModelHooks(admin) {
* @param {string} name * @param {string} name
* @returns {?} * @returns {?}
*/ */
rl.pluginSettingsGet = (pluginSection, name) => { rl.pluginSettingsGet = (pluginSection, name) =>
let plugins = SettingsGet('Plugins'); SettingsGet('Plugins')?.[pluginSection]?.[name];
plugins = plugins && null != plugins[pluginSection] ? plugins[pluginSection] : null;
return plugins ? (null == plugins[name] ? null : plugins[name]) : null;
};
rl.pluginPopupView = AbstractViewPopup; rl.pluginPopupView = AbstractViewPopup;

View file

@ -422,7 +422,7 @@ export class Selector {
lineUid = ''; lineUid = '';
const uid = this.getItemUid(item); const uid = this.getItemUid(item);
if (event && event.shiftKey) { if (event?.shiftKey) {
if (uid && this.sLastUid && uid !== this.sLastUid) { if (uid && this.sLastUid && uid !== this.sLastUid) {
list = this.list(); list = this.list();
checked = item.checked(); checked = item.checked();

View file

@ -142,7 +142,7 @@ export const
* @param {Function=} langCallback = null * @param {Function=} langCallback = null
*/ */
initOnStartOrLangChange = (startCallback, langCallback = null) => { initOnStartOrLangChange = (startCallback, langCallback = null) => {
startCallback && startCallback(); startCallback?.();
startCallback && trigger.subscribe(startCallback); startCallback && trigger.subscribe(startCallback);
langCallback && trigger.subscribe(langCallback); langCallback && trigger.subscribe(langCallback);
}, },

View file

@ -26,8 +26,7 @@ export const
.trim(), .trim(),
defaultOptionsAfterRender = (domItem, item) => defaultOptionsAfterRender = (domItem, item) =>
domItem && item && undefined !== item.disabled item && undefined !== item.disabled && domItem?.classList.toggle('disabled', domItem.disabled = item.disabled),
&& domItem.classList.toggle('disabled', domItem.disabled = item.disabled),
// unescape(encodeURIComponent()) makes the UTF-16 DOMString to an UTF-8 string // unescape(encodeURIComponent()) makes the UTF-16 DOMString to an UTF-8 string
b64EncodeJSON = data => btoa(unescape(encodeURIComponent(JSON.stringify(data)))), b64EncodeJSON = data => btoa(unescape(encodeURIComponent(JSON.stringify(data)))),

View file

@ -131,7 +131,7 @@ computedPaginatorHelper = (koCurrentPage, koPageCount) => {
* @returns {boolean} * @returns {boolean}
*/ */
mailToHelper = mailToUrl => { mailToHelper = mailToUrl => {
if (mailToUrl && 'mailto:' === mailToUrl.slice(0, 7).toLowerCase()) { if ('mailto:' === mailToUrl?.slice(0, 7).toLowerCase()) {
mailToUrl = mailToUrl.slice(7).split('?'); mailToUrl = mailToUrl.slice(7).split('?');
const const
@ -181,7 +181,7 @@ setLayoutResizer = (source, target, sClientSideKeyName, mode) =>
target.removeAttribute('style'); target.removeAttribute('style');
source.removeAttribute('style'); source.removeAttribute('style');
} }
source.observer && source.observer.disconnect(); source.observer?.disconnect();
// source.classList.toggle('resizable', mode); // source.classList.toggle('resizable', mode);
if (mode) { if (mode) {
const length = Local.get(sClientSideKeyName + mode) || SettingsGet('Resizer' + sClientSideKeyName + mode), const length = Local.get(sClientSideKeyName + mode) || SettingsGet('Resizer' + sClientSideKeyName + mode),
@ -248,7 +248,7 @@ setLayoutResizer = (source, target, sClientSideKeyName, mode) =>
} }
source.layoutResizer.mode = mode; source.layoutResizer.mode = mode;
source.layoutResizer.key = sClientSideKeyName; source.layoutResizer.key = sClientSideKeyName;
source.observer && source.observer.observe(source, { box: 'border-box' }); source.observer?.observe(source, { box: 'border-box' });
} }
}, },
@ -266,7 +266,7 @@ populateMessageBody = (oMessage, preload) => {
oMessage = preload ? oMessage : null; oMessage = preload ? oMessage : null;
let let
isNew = false, isNew = false,
json = oData && oData.Result, json = oData?.Result,
message = oMessage || MessageUserStore.message(); message = oMessage || MessageUserStore.message();
if ( if (

View file

@ -12,7 +12,7 @@ export class AbstractInput {
this.value = params.value || ''; this.value = params.value || '';
this.label = params.label || ''; this.label = params.label || '';
this.enable = null == params.enable ? true : params.enable; this.enable = null == params.enable ? true : params.enable;
this.trigger = params.trigger && params.trigger.subscribe ? params.trigger : null; this.trigger = params.trigger?.subscribe ? params.trigger : null;
this.placeholder = params.placeholder || ''; this.placeholder = params.placeholder || '';
this.labeled = null != params.label; this.labeled = null != params.label;

View file

@ -2,7 +2,7 @@ import { doc, createElement, addEventsListeners } from 'Common/Globals';
import { EmailModel } from 'Model/Email'; import { EmailModel } from 'Model/Email';
const contentType = 'snappymail/emailaddress', const contentType = 'snappymail/emailaddress',
getAddressKey = li => li && li.emailaddress && li.emailaddress.key; getAddressKey = li => li?.emailaddress?.key;
let dragAddress, datalist; let dragAddress, datalist;
@ -19,7 +19,7 @@ export class EmailAddressesComponent {
const self = this, const self = this,
// In Chrome we have no access to dataTransfer.getData unless it's the 'drop' event // In Chrome we have no access to dataTransfer.getData unless it's the 'drop' event
// In Chrome Mobile dataTransfer.types.includes(contentType) fails, only text/plain is set // In Chrome Mobile dataTransfer.types.includes(contentType) fails, only text/plain is set
validDropzone = () => dragAddress && dragAddress.li.parentNode !== self.ul, validDropzone = () => dragAddress?.li.parentNode !== self.ul,
fnDrag = e => validDropzone() && e.preventDefault(); fnDrag = e => validDropzone() && e.preventDefault();
self.element = element; self.element = element;
@ -116,7 +116,7 @@ export class EmailAddressesComponent {
value, value,
items => { items => {
self._resetDatalist(); self._resetDatalist();
items && items.forEach(item => datalist.append(new Option(item))); items?.forEach(item => datalist.append(new Option(item)));
} }
) )
} }

View file

@ -14,8 +14,8 @@ const rlContentType = 'snappymail/action',
// In Chrome we have no access to dataTransfer.getData unless it's the 'drop' event // In Chrome we have no access to dataTransfer.getData unless it's the 'drop' event
// In Chrome Mobile dataTransfer.types.includes(rlContentType) fails, only text/plain is set // In Chrome Mobile dataTransfer.types.includes(rlContentType) fails, only text/plain is set
dragMessages = () => dragData && 'messages' === dragData.action, dragMessages = () => 'messages' === dragData?.action,
dragSortable = () => dragData && 'sortable' === dragData.action, dragSortable = () => 'sortable' === dragData?.action,
setDragAction = (e, action, effect, data, img) => { setDragAction = (e, action, effect, data, img) => {
dragData = { dragData = {
action: action, action: action,
@ -45,8 +45,8 @@ Object.assign(ko.bindingHandlers, {
let editor = null; let editor = null;
const fValue = fValueAccessor(), const fValue = fValueAccessor(),
fUpdateEditorValue = () => fValue && fValue.__editor && fValue.__editor.setHtmlOrPlain(fValue()), fUpdateEditorValue = () => fValue?.__editor?.setHtmlOrPlain(fValue()),
fUpdateKoValue = () => fValue && fValue.__editor && fValue(fValue.__editor.getDataWithHtmlMark()), fUpdateKoValue = () => fValue?.__editor && fValue(fValue.__editor.getDataWithHtmlMark()),
fOnReady = () => { fOnReady = () => {
fValue.__editor = editor; fValue.__editor = editor;
fUpdateEditorValue(); fUpdateEditorValue();
@ -76,7 +76,7 @@ Object.assign(ko.bindingHandlers, {
focused = fValue.focused; focused = fValue.focused;
element.addresses = new EmailAddressesComponent(element, { element.addresses = new EmailAddressesComponent(element, {
focusCallback: value => focused && focused(!!value), focusCallback: value => focused?.(!!value),
autoCompleteSource: fAllBindings.get('autoCompleteSource'), autoCompleteSource: fAllBindings.get('autoCompleteSource'),
onChange: value => fValue(value) onChange: value => fValue(value)
}); });
@ -137,7 +137,7 @@ Object.assign(ko.bindingHandlers, {
if (dragMessages()) { if (dragMessages()) {
fnStop(e); fnStop(e);
element.classList.add('droppableHover'); element.classList.add('droppableHover');
if (folder && folder.collapsed()) { if (folder?.collapsed()) {
dragTimer.start(() => { dragTimer.start(() => {
folder.collapsed(false); folder.collapsed(false);
setExpandedFolder(folder.fullName, true); setExpandedFolder(folder.fullName, true);
@ -153,7 +153,7 @@ Object.assign(ko.bindingHandlers, {
fnStop(e); fnStop(e);
if (dragMessages() && ['move','copy'].includes(e.dataTransfer.effectAllowed)) { if (dragMessages() && ['move','copy'].includes(e.dataTransfer.effectAllowed)) {
let data = dragData.data; let data = dragData.data;
if (folder && data && data.folder && isArray(data.uids)) { if (folder && data?.folder && isArray(data.uids)) {
moveMessagesToFolder(data.folder, data.uids, folder.fullName, data.copy && e.ctrlKey); moveMessagesToFolder(data.folder, data.uids, folder.fullName, data.copy && e.ctrlKey);
} }
} }
@ -220,7 +220,7 @@ Object.assign(ko.bindingHandlers, {
options.list(arr); options.list(arr);
} }
dragData = null; dragData = null;
options.afterMove && options.afterMove(); options.afterMove?.();
} }
} }
}); });

8
dev/External/ko.js vendored
View file

@ -26,14 +26,14 @@ export const
addSubscribablesTo = (target, subscribables) => addSubscribablesTo = (target, subscribables) =>
forEachObjectEntry(subscribables, (key, fn) => target[key].subscribe(fn)), forEachObjectEntry(subscribables, (key, fn) => target[key].subscribe(fn)),
dispose = disposable => disposable && isFunction(disposable.dispose) && disposable.dispose(), dispose = disposable => isFunction(disposable?.dispose) && disposable.dispose(),
// With this we don't need delegateRunOnDestroy // With this we don't need delegateRunOnDestroy
koArrayWithDestroy = data => { koArrayWithDestroy = data => {
data = ko.observableArray(data); data = ko.observableArray(data);
data.subscribe(changes => data.subscribe(changes =>
changes.forEach(item => changes.forEach(item =>
'deleted' === item.status && null == item.moved && item.value.onDestroy && item.value.onDestroy() 'deleted' === item.status && null == item.moved && item.value.onDestroy?.()
) )
, data, 'arrayChange'); , data, 'arrayChange');
return data; return data;
@ -172,12 +172,12 @@ ko.extenders.toggleSubscribeProperty = (target, options) => {
const prop = options[1]; const prop = options[1];
if (prop) { if (prop) {
target.subscribe( target.subscribe(
prev => prev && prev[prop] && prev[prop](false), prev => prev?.[prop]?.(false),
options[0], options[0],
'beforeChange' 'beforeChange'
); );
target.subscribe(next => next && next[prop] && next[prop](true), options[0]); target.subscribe(next => next?.[prop]?.(true), options[0]);
} }
return target; return target;

View file

@ -50,8 +50,7 @@ export class AbstractModel {
// forEachObjectEntry(this, (key, value) => { // forEachObjectEntry(this, (key, value) => {
forEachObjectValue(this, value => { forEachObjectValue(this, value => {
/** clear CollectionModel */ /** clear CollectionModel */
let arr = ko.isObservableArray(value) ? value() : value; (ko.isObservableArray(value) ? value() : value)?.onDestroy?.();
arr && arr.onDestroy && arr.onDestroy();
/** destroy ko.observable/ko.computed? */ /** destroy ko.observable/ko.computed? */
// dispose(value); // dispose(value);
/** clear object value */ /** clear object value */
@ -76,7 +75,7 @@ export class AbstractModel {
*/ */
static reviveFromJson(json) { static reviveFromJson(json) {
let obj = this.validJson(json) ? new this() : null; let obj = this.validJson(json) ? new this() : null;
obj && obj.revivePropertiesFromJson(json); obj?.revivePropertiesFromJson(json);
return obj; return obj;
} }

View file

@ -128,7 +128,7 @@ export class AbstractViewSettings
addSubscribablesTo(this, { addSubscribablesTo(this, {
[prop]: (value => { [prop]: (value => {
this[trigger](SaveSettingsStep.Animate); this[trigger](SaveSettingsStep.Animate);
valueCb && valueCb(value); valueCb?.(value);
rl.app.Remote.saveSetting(name, value, rl.app.Remote.saveSetting(name, value,
iError => { iError => {
this[trigger](iError ? SaveSettingsStep.FalseResult : SaveSettingsStep.TrueResult); this[trigger](iError ? SaveSettingsStep.FalseResult : SaveSettingsStep.TrueResult);

View file

@ -10,10 +10,7 @@ let
defaultScreenName = ''; defaultScreenName = '';
const const
autofocus = dom => { autofocus = dom => dom.querySelector('[autofocus]')?.focus(),
const af = dom.querySelector('[autofocus]');
af && af.focus();
},
visiblePopups = new Set, visiblePopups = new Set,
@ -21,7 +18,7 @@ const
* @param {string} screenName * @param {string} screenName
* @returns {?Object} * @returns {?Object}
*/ */
screen = screenName => screenName && null != SCREENS[screenName] ? SCREENS[screenName] : null, screen = screenName => (screenName && SCREENS[screenName]) || null,
/** /**
* @param {Function} ViewModelClass * @param {Function} ViewModelClass
@ -77,10 +74,10 @@ const
if (e.target === vmDom) { if (e.target === vmDom) {
if (vmDom.classList.contains('animate')) { if (vmDom.classList.contains('animate')) {
autofocus(vmDom); autofocus(vmDom);
vm.afterShow && vm.afterShow(); vm.afterShow?.();
} else { } else {
vmDom.close(); vmDom.close();
vm.afterHide && vm.afterHide(); vm.afterHide?.();
} }
} }
}; };
@ -101,7 +98,7 @@ const
}); });
} else { } else {
visiblePopups.delete(vm); visiblePopups.delete(vm);
vm.onHide && vm.onHide(); vm.onHide?.();
vm.keyScope.unset(); vm.keyScope.unset();
vmDom.classList.remove('animate'); // trigger the transitions vmDom.classList.remove('animate'); // trigger the transitions
} }
@ -118,7 +115,7 @@ const
vm vm
); );
vm.onBuild && vm.onBuild(vmDom); vm.onBuild?.(vmDom);
fireEvent('rl-view-model', vm); fireEvent('rl-view-model', vm);
} else { } else {
@ -142,10 +139,10 @@ const
}, },
hideScreen = (screenToHide, destroy) => { hideScreen = (screenToHide, destroy) => {
screenToHide.onHide && screenToHide.onHide(); screenToHide.onHide?.();
forEachViewModel(screenToHide, (vm, dom) => { forEachViewModel(screenToHide, (vm, dom) => {
dom.hidden = true; dom.hidden = true;
vm.onHide && vm.onHide(); vm.onHide?.();
destroy && vm.viewModelDom.remove(); destroy && vm.viewModelDom.remove();
}); });
}, },
@ -155,7 +152,7 @@ const
* @returns {void} * @returns {void}
*/ */
hideScreenPopup = ViewModelClassToHide => { hideScreenPopup = ViewModelClassToHide => {
if (ViewModelClassToHide && ViewModelClassToHide.__vm && ViewModelClassToHide.__dom) { if (ViewModelClassToHide?.__vm && ViewModelClassToHide?.__dom) {
ViewModelClassToHide.__vm.modalVisible(false); ViewModelClassToHide.__vm.modalVisible(false);
} }
}, },
@ -190,7 +187,7 @@ const
} }
} }
if (vmScreen && vmScreen.__started) { if (vmScreen?.__started) {
isSameScreen = currentScreen && vmScreen === currentScreen; isSameScreen = currentScreen && vmScreen === currentScreen;
if (!vmScreen.__builded) { if (!vmScreen.__builded) {
@ -200,7 +197,7 @@ const
buildViewModel(ViewModelClass, vmScreen) buildViewModel(ViewModelClass, vmScreen)
); );
vmScreen.onBuild && vmScreen.onBuild(); vmScreen.onBuild?.();
} }
setTimeout(() => { setTimeout(() => {
@ -214,19 +211,19 @@ const
// show screen // show screen
if (!isSameScreen) { if (!isSameScreen) {
vmScreen.onShow && vmScreen.onShow(); vmScreen.onShow?.();
forEachViewModel(vmScreen, (vm, dom) => { forEachViewModel(vmScreen, (vm, dom) => {
vm.beforeShow && vm.beforeShow(); vm.beforeShow?.();
i18nToNodes(dom); i18nToNodes(dom);
dom.hidden = false; dom.hidden = false;
vm.onShow && vm.onShow(); vm.onShow?.();
autofocus(dom); autofocus(dom);
}); });
} }
// -- // --
vmScreen.__cross && vmScreen.__cross.parse(subPart); vmScreen.__cross?.parse(subPart);
}, 1); }, 1);
} }
} }
@ -248,11 +245,11 @@ export const
if (vm) { if (vm) {
params = params || []; params = params || [];
vm.beforeShow && vm.beforeShow(...params); vm.beforeShow?.(...params);
vm.modalVisible(true); vm.modalVisible(true);
vm.onShow && vm.onShow(...params); vm.onShow?.(...params);
} }
}, },
@ -295,7 +292,7 @@ export const
const c = elementById('rl-content'), l = elementById('rl-loading'); const c = elementById('rl-content'), l = elementById('rl-loading');
c && (c.hidden = false); c && (c.hidden = false);
l && l.remove(); l?.remove();
}, },
/** /**

View file

@ -12,7 +12,7 @@ export class AbstractCollectionModel extends Array
} }
onDestroy() { onDestroy() {
this.forEach(item => item.onDestroy && item.onDestroy()); this.forEach(item => item.onDestroy?.());
} }
/** /**

View file

@ -283,7 +283,7 @@ export class EmailModel extends AbstractModel {
*/ */
static reviveFromJson(json) { static reviveFromJson(json) {
const email = super.reviveFromJson(json); const email = super.reviveFromJson(json);
email && email.clearDuplicateName(); email?.clearDuplicateName();
return email; return email;
} }
@ -351,7 +351,7 @@ export class EmailModel extends AbstractModel {
? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '') ? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '')
: null; : null;
if (address && address.email) { if (address?.email) {
exists = true; exists = true;
} }

View file

@ -30,7 +30,7 @@ export class EmailCollectionModel extends AbstractCollectionModel
toStringClear() { toStringClear() {
const result = []; const result = [];
this.forEach(email => { this.forEach(email => {
if (email && email.email && email.name) { if (email?.email && email?.name) {
result.push(email.email); result.push(email.email);
} }
}); });

View file

@ -100,8 +100,8 @@ export const
.post('Folders', FolderUserStore.foldersLoading) .post('Folders', FolderUserStore.foldersLoading)
.then(data => { .then(data => {
data = FolderCollectionModel.reviveFromJson(data.Result); data = FolderCollectionModel.reviveFromJson(data.Result);
data && data.storeIt(); data?.storeIt();
fCallback && fCallback(true); fCallback?.(true);
// Repeat every 15 minutes? // Repeat every 15 minutes?
// this.foldersTimeout = setTimeout(loadFolders, 900000); // this.foldersTimeout = setTimeout(loadFolders, 900000);
}) })
@ -128,7 +128,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
*/ */
static reviveFromJson(object) { static reviveFromJson(object) {
const expandedFolders = Local.get(ClientSideKeyNameExpandedFolders); const expandedFolders = Local.get(ClientSideKeyNameExpandedFolders);
if (object && object.SystemFolders) { if (object?.SystemFolders) {
forEachObjectEntry(SystemFolders, key => forEachObjectEntry(SystemFolders, key =>
SystemFolders[key] = SettingsGet(key+'Folder') || object.SystemFolders[FolderType[key]] SystemFolders[key] = SettingsGet(key+'Folder') || object.SystemFolders[FolderType[key]]
); );

View file

@ -323,7 +323,7 @@ export class MessageModel extends AbstractModel {
*/ */
fromDkimData() { fromDkimData() {
let result = ['none', '']; let result = ['none', ''];
if (1 === arrayLength(this.from) && this.from[0] && this.from[0].dkimStatus) { if (1 === arrayLength(this.from) && this.from[0]?.dkimStatus) {
result = [this.from[0].dkimStatus, this.from[0].dkimValue || '']; result = [this.from[0].dkimStatus, this.from[0].dkimValue || ''];
} }
@ -399,7 +399,7 @@ export class MessageModel extends AbstractModel {
* @returns {string} * @returns {string}
*/ */
fromAsSingleEmail() { fromAsSingleEmail() {
return isArray(this.from) && this.from[0] ? this.from[0].email : ''; return (isArray(this.from) && this.from[0]?.email) || '';
} }
/** /**

View file

@ -136,7 +136,7 @@ export class AbstractFetchRemote
undefined === iTimeout ? 30000 : pInt(iTimeout), undefined === iTimeout ? 30000 : pInt(iTimeout),
data => { data => {
let cached = false; let cached = false;
if (data && data.Time) { if (data?.Time) {
cached = pInt(data.Time) > Date.now() - start; cached = pInt(data.Time) > Date.now() - start;
} }
@ -162,7 +162,7 @@ export class AbstractFetchRemote
} }
} }
fCallback && fCallback( fCallback?.(
iError, iError,
data, data,
cached, cached,
@ -173,7 +173,7 @@ export class AbstractFetchRemote
) )
.catch(err => { .catch(err => {
console.error({fetchError:err}); console.error({fetchError:err});
fCallback && fCallback( fCallback?.(
'TimeoutError' == err.reason ? 3 : (err.name == 'AbortError' ? 2 : 1), 'TimeoutError' == err.reason ? 3 : (err.name == 'AbortError' ? 2 : 1),
err err
); );
@ -191,7 +191,7 @@ export class AbstractFetchRemote
if (trigger) { if (trigger) {
value = !!value; value = !!value;
(isArray(trigger) ? trigger : [trigger]).forEach(fTrigger => { (isArray(trigger) ? trigger : [trigger]).forEach(fTrigger => {
fTrigger && fTrigger(value); fTrigger?.(value);
}); });
} }
} }
@ -207,12 +207,12 @@ export class AbstractFetchRemote
} }
/* /*
let isCached = false, type = ''; let isCached = false, type = '';
if (data && data.Time) { if (data?.Time) {
isCached = pInt(data.Time) > microtime() - start; isCached = pInt(data.Time) > microtime() - start;
} }
// backward capability // backward capability
switch (true) { switch (true) {
case 'success' === textStatus && data && data.Result && action === data.Action: case 'success' === textStatus && data?.Result && action === data.Action:
type = AbstractFetchRemote.SUCCESS; type = AbstractFetchRemote.SUCCESS;
break; break;
case 'abort' === textStatus && (!data || !data.__aborted__): case 'abort' === textStatus && (!data || !data.__aborted__):

View file

@ -24,13 +24,13 @@ class RemoteUserFetch extends AbstractFetchRemote {
const const
sFolderFullName = pString(params.Folder), sFolderFullName = pString(params.Folder),
folder = getFolderFromCacheList(sFolderFullName), folder = getFolderFromCacheList(sFolderFullName),
folderHash = (folder && folder.hash) || ''; folderHash = folder?.hash || '';
params = Object.assign({ params = Object.assign({
Offset: 0, Offset: 0,
Limit: SettingsUserStore.messagesPerPage(), Limit: SettingsUserStore.messagesPerPage(),
Search: '', Search: '',
UidNext: (folder && folder.uidNext) || 0, // Used to check for new messages UidNext: folder?.uidNext || 0, // Used to check for new messages
Sort: FolderUserStore.sortMode(), Sort: FolderUserStore.sortMode(),
Hash: folderHash + SettingsGet('AccountHash') Hash: folderHash + SettingsGet('AccountHash')
}, params); }, params);

View file

@ -53,7 +53,7 @@ export class AbstractSettingsScreen extends AbstractScreen {
settingsScreen settingsScreen
); );
settingsScreen.onBuild && settingsScreen.onBuild(viewModelDom); settingsScreen.onBuild?.(viewModelDom);
} else { } else {
console.log('Cannot find sub settings view model position: SettingsSubScreen'); console.log('Cannot find sub settings view model position: SettingsSubScreen');
} }
@ -67,10 +67,10 @@ export class AbstractSettingsScreen extends AbstractScreen {
this.oCurrentSubScreen = settingsScreen; this.oCurrentSubScreen = settingsScreen;
// show // show
settingsScreen.beforeShow && settingsScreen.beforeShow(); settingsScreen.beforeShow?.();
i18nToNodes(settingsScreen.viewModelDom); i18nToNodes(settingsScreen.viewModelDom);
settingsScreen.viewModelDom.hidden = false; settingsScreen.viewModelDom.hidden = false;
settingsScreen.onShow && settingsScreen.onShow(); settingsScreen.onShow?.();
this.menu.forEach(item => { this.menu.forEach(item => {
item.selected( item.selected(
@ -90,7 +90,7 @@ export class AbstractSettingsScreen extends AbstractScreen {
onHide() { onHide() {
let subScreen = this.oCurrentSubScreen; let subScreen = this.oCurrentSubScreen;
if (subScreen) { if (subScreen) {
subScreen.onHide && subScreen.onHide(); subScreen.onHide?.();
subScreen.viewModelDom.hidden = true; subScreen.viewModelDom.hidden = true;
} }
} }

View file

@ -95,7 +95,7 @@ export class MailBoxUserScreen extends AbstractScreen {
/* // Disabled in SystemDropDown.html /* // Disabled in SystemDropDown.html
const email = AccountUserStore.email(); const email = AccountUserStore.email();
AccountUserStore.accounts.forEach(item => AccountUserStore.accounts.forEach(item =>
item && email === item.email && item.count(e.detail) email === item?.email && item?.count(e.detail)
); );
*/ */
this.updateWindowTitle(); this.updateWindowTitle();

View file

@ -30,7 +30,7 @@ export class UserSettingsAccounts /*extends AbstractViewSettings*/ {
} }
editAccount(account) { editAccount(account) {
if (account && account.isAdditional()) { if (account?.isAdditional()) {
showScreenPopup(AccountPopupView, [account]); showScreenPopup(AccountPopupView, [account]);
} }
} }
@ -48,7 +48,7 @@ export class UserSettingsAccounts /*extends AbstractViewSettings*/ {
* @returns {void} * @returns {void}
*/ */
deleteAccount(accountToRemove) { deleteAccount(accountToRemove) {
if (accountToRemove && accountToRemove.askDelete()) { if (accountToRemove?.askDelete()) {
this.accountForDeletion(null); this.accountForDeletion(null);
if (accountToRemove) { if (accountToRemove) {
this.accounts.remove((account) => accountToRemove === account); this.accounts.remove((account) => accountToRemove === account);
@ -72,7 +72,7 @@ export class UserSettingsAccounts /*extends AbstractViewSettings*/ {
* @returns {void} * @returns {void}
*/ */
deleteIdentity(identityToRemove) { deleteIdentity(identityToRemove) {
if (identityToRemove && identityToRemove.askDelete()) { if (identityToRemove?.askDelete()) {
this.identityForDeletion(null); this.identityForDeletion(null);
if (identityToRemove) { if (identityToRemove) {

View file

@ -50,6 +50,6 @@ export class UserSettingsFilters /*extends AbstractViewSettings*/ {
} }
onShow() { onShow() {
window.Sieve && window.Sieve.updateList(); window.Sieve?.updateList();
} }
} }

View file

@ -74,7 +74,7 @@ export class UserSettingsThemes /*extends AbstractViewSettings*/ {
.on('onComplete', (id, result, data) => { .on('onComplete', (id, result, data) => {
themeBackground.loading(false); themeBackground.loading(false);
if (result && id && data && data.Result && data.Result.Name && data.Result.Hash) { if (result && id && data?.Result?.Name && data?.Result?.Hash) {
themeBackground.name(data.Result.Name); themeBackground.name(data.Result.Name);
themeBackground.hash(data.Result.Hash); themeBackground.hash(data.Result.Hash);
} else { } else {
@ -94,11 +94,7 @@ export class UserSettingsThemes /*extends AbstractViewSettings*/ {
} }
} }
if (!errorMsg && data.ErrorMessage) { themeBackground.error(errorMsg || data.ErrorMessage || i18n('SETTINGS_THEMES/ERROR_UNKNOWN'));
errorMsg = data.ErrorMessage;
}
themeBackground.error(errorMsg || i18n('SETTINGS_THEMES/ERROR_UNKNOWN'));
} }
return true; return true;

View file

@ -13,8 +13,7 @@ import {
const const
// import { defaultOptionsAfterRender } from 'Common/Utils'; // import { defaultOptionsAfterRender } from 'Common/Utils';
defaultOptionsAfterRender = (domItem, item) => defaultOptionsAfterRender = (domItem, item) =>
domItem && item && undefined !== item.disabled item && undefined !== item.disabled && domItem?.classList.toggle('disabled', domItem.disabled = item.disabled),
&& domItem.classList.toggle('disabled', domItem.disabled = item.disabled),
// import { folderListOptionsBuilder } from 'Common/Folders'; // import { folderListOptionsBuilder } from 'Common/Folders';
/** /**

View file

@ -22,7 +22,7 @@ PackageAdminStore.fetch = () => {
const loading = {}; const loading = {};
PackageAdminStore.forEach(item => { PackageAdminStore.forEach(item => {
if (item && item.loading()) { if (item?.loading()) {
loading[item.file] = item; loading[item.file] = item;
} }
}); });

View file

@ -21,6 +21,6 @@ AppUserStore.focusedState.subscribe(value => {
ThemeStore.isMobile() && leftPanelDisabled('FolderList' !== value); ThemeStore.isMobile() && leftPanelDisabled('FolderList' !== value);
} }
let dom = elementById('V-Mail'+name); let dom = elementById('V-Mail'+name);
dom && dom.classList.toggle('focused', name === value); dom?.classList.toggle('focused', name === value);
}); });
}); });

View file

@ -33,12 +33,12 @@ ContactUserStore.sync = fResultFunc => {
line = JSON.parse(line); line = JSON.parse(line);
if ('ContactsSync' === line.Action) { if ('ContactsSync' === line.Action) {
ContactUserStore.syncing(false); ContactUserStore.syncing(false);
fResultFunc && fResultFunc(line.ErrorCode, line); fResultFunc?.(line.ErrorCode, line);
} }
} catch (e) { } catch (e) {
ContactUserStore.syncing(false); ContactUserStore.syncing(false);
console.error(e); console.error(e);
fResultFunc && fResultFunc(Notification.UnknownError); fResultFunc?.(Notification.UnknownError);
} }
}, 'ContactsSync'); }, 'ContactsSync');
} }

View file

@ -80,15 +80,9 @@ export const FolderUserStore = new class {
const const
subscribeRemoveSystemFolder = observable => { subscribeRemoveSystemFolder = observable => {
observable.subscribe(() => { observable.subscribe(() => getFolderFromCacheList(observable())?.type(FolderType.User), self, 'beforeChange');
const folder = getFolderFromCacheList(observable());
folder && folder.type(FolderType.User);
}, self, 'beforeChange');
}, },
fSetSystemFolderType = type => value => { fSetSystemFolderType = type => value => getFolderFromCacheList(value)?.type(type);
const folder = getFolderFromCacheList(value);
folder && folder.type(type);
};
subscribeRemoveSystemFolder(self.sentFolder); subscribeRemoveSystemFolder(self.sentFolder);
subscribeRemoveSystemFolder(self.draftsFolder); subscribeRemoveSystemFolder(self.draftsFolder);
@ -134,8 +128,7 @@ export const FolderUserStore = new class {
fSearchFunction = (list) => { fSearchFunction = (list) => {
list.forEach(folder => { list.forEach(folder => {
if ( if (
folder && folder?.selectable() &&
folder.selectable() &&
folder.exists && folder.exists &&
timeout > folder.expires && timeout > folder.expires &&
(folder.isSystemFolder() || (folder.isSubscribed() && (folder.checkable() || !bDisplaySpecSetting))) (folder.isSystemFolder() || (folder.isSubscribed() && (folder.checkable() || !bDisplaySpecSetting)))
@ -143,7 +136,7 @@ export const FolderUserStore = new class {
timeouts.push([folder.expires, folder.fullName]); timeouts.push([folder.expires, folder.fullName]);
} }
if (folder && folder.subFolders.length) { if (folder?.subFolders.length) {
fSearchFunction(folder.subFolders()); fSearchFunction(folder.subFolders());
} }
}); });

View file

@ -38,7 +38,7 @@ export const GnuPGUserStore = new class {
this.privateKeys([]); this.privateKeys([]);
Remote.request('GnupgGetKeys', Remote.request('GnupgGetKeys',
(iError, oData) => { (iError, oData) => {
if (oData && oData.Result) { if (oData?.Result) {
this.keyring = oData.Result; this.keyring = oData.Result;
const initKey = (key, isPrivate) => { const initKey = (key, isPrivate) => {
const aEmails = []; const aEmails = [];
@ -73,7 +73,7 @@ export const GnuPGUserStore = new class {
key.view = () => { key.view = () => {
const fetch = pass => Remote.request('GnupgExportKey', const fetch = pass => Remote.request('GnupgExportKey',
(iError, oData) => { (iError, oData) => {
if (oData && oData.Result) { if (oData?.Result) {
key.armor = oData.Result; key.armor = oData.Result;
showScreenPopup(OpenPgpKeyPopupView, [key]); showScreenPopup(OpenPgpKeyPopupView, [key]);
} }
@ -111,10 +111,10 @@ export const GnuPGUserStore = new class {
importKey(key, callback) { importKey(key, callback) {
Remote.request('GnupgImportKey', Remote.request('GnupgImportKey',
(iError, oData) => { (iError, oData) => {
if (oData && oData.Result/* && (oData.Result.imported || oData.Result.secretimported)*/) { if (oData?.Result/* && (oData.Result.imported || oData.Result.secretimported)*/) {
this.loadKeyrings(); this.loadKeyrings();
} }
callback && callback(iError, oData); callback?.(iError, oData);
}, { }, {
Key: key Key: key
} }
@ -131,10 +131,10 @@ export const GnuPGUserStore = new class {
storeKeyPair(keyPair, callback) { storeKeyPair(keyPair, callback) {
Remote.request('PgpStoreKeyPair', Remote.request('PgpStoreKeyPair',
(iError, oData) => { (iError, oData) => {
if (oData && oData.Result) { if (oData?.Result) {
// this.gnupgKeyring = oData.Result; // this.gnupgKeyring = oData.Result;
} }
callback && callback(iError, oData); callback?.(iError, oData);
}, keyPair }, keyPair
); );
} }
@ -187,7 +187,7 @@ export const GnuPGUserStore = new class {
} }
if (null !== params.Passphrase) { if (null !== params.Passphrase) {
const result = await Remote.post('GnupgDecrypt', null, params); const result = await Remote.post('GnupgDecrypt', null, params);
if (result && result.Result) { if (result?.Result) {
return result.Result; return result.Result;
} }
} }
@ -208,7 +208,7 @@ export const GnuPGUserStore = new class {
data.SigPart = data.SigPart.body; data.SigPart = data.SigPart.body;
} }
let response = await Remote.post('MessagePgpVerify', null, data); let response = await Remote.post('MessagePgpVerify', null, data);
if (response && response.Result) { if (response?.Result) {
return { return {
fingerprint: response.Result.fingerprint, fingerprint: response.Result.fingerprint,
success: 0 == response.Result.status // GOODSIG success: 0 == response.Result.status // GOODSIG

View file

@ -42,7 +42,7 @@ export const MessageUserStore = new class {
purgeMessageBodyCache() { purgeMessageBodyCache() {
const messagesDom = this.bodiesDom(), const messagesDom = this.bodiesDom(),
children = messagesDom && messagesDom.children; children = messagesDom?.children;
if (children) { if (children) {
while (15 < children.length) { while (15 < children.length) {
children[0].remove(); children[0].remove();

View file

@ -270,8 +270,7 @@ MessagelistUserStore.setAction = (sFolderFullName, iSetAction, messages) => {
let folder, let folder,
alreadyUnread = 0, alreadyUnread = 0,
rootUids = messages.map(oMessage => oMessage && oMessage.uid ? oMessage.uid : null) rootUids = messages.map(oMessage => oMessage?.uid).validUnique(),
.validUnique(),
length = rootUids.length; length = rootUids.length;
if (sFolderFullName && length) { if (sFolderFullName && length) {
@ -333,7 +332,7 @@ MessagelistUserStore.removeMessagesFromList = (
? messageList.filter(item => item && uidForRemove.includes(pInt(item.uid))) ? messageList.filter(item => item && uidForRemove.includes(pInt(item.uid)))
: []; : [];
messages.forEach(item => item && item.isUnseen() && ++unseenCount); messages.forEach(item => item?.isUnseen() && ++unseenCount);
if (fromFolder) { if (fromFolder) {
fromFolder.hash = ''; fromFolder.hash = '';
@ -387,7 +386,7 @@ MessagelistUserStore.removeMessagesFromList = (
if (MessagelistUserStore.threadUid()) { if (MessagelistUserStore.threadUid()) {
if ( if (
messageList.length && messageList.length &&
messageList.find(item => item && item.deleted() && item.uid == MessagelistUserStore.threadUid()) messageList.find(item => item?.deleted() && item.uid == MessagelistUserStore.threadUid())
) { ) {
const message = messageList.find(item => item && !item.deleted()); const message = messageList.find(item => item && !item.deleted());
let setHash; let setHash;

View file

@ -6,7 +6,7 @@ import { fireEvent } from 'Common/Globals';
* Might not work due to the new ServiceWorkerRegistration.showNotification * Might not work due to the new ServiceWorkerRegistration.showNotification
*/ */
const HTML5Notification = window.Notification, const HTML5Notification = window.Notification,
HTML5NotificationStatus = () => (HTML5Notification && HTML5Notification.permission) || 'denied', HTML5NotificationStatus = () => HTML5Notification?.permission || 'denied',
NotificationsDenied = () => 'denied' === HTML5NotificationStatus(), NotificationsDenied = () => 'denied' === HTML5NotificationStatus(),
NotificationsGranted = () => 'granted' === HTML5NotificationStatus(), NotificationsGranted = () => 'granted' === HTML5NotificationStatus(),
dispatchMessage = data => { dispatchMessage = data => {
@ -26,7 +26,7 @@ if (WorkerNotifications && ServiceWorkerRegistration && ServiceWorkerRegistratio
/* Listen for close requests from the ServiceWorker */ /* Listen for close requests from the ServiceWorker */
WorkerNotifications.addEventListener('message', event => { WorkerNotifications.addEventListener('message', event => {
const obj = JSON.parse(event.data); const obj = JSON.parse(event.data);
obj && 'notificationclick' === obj.action && dispatchMessage(obj.data); 'notificationclick' === obj?.action && dispatchMessage(obj.data);
}); });
} else { } else {
WorkerNotifications = null; WorkerNotifications = null;
@ -60,7 +60,7 @@ export const NotificationUserStore = new class {
icon: imageSrc || Links.staticLink('css/images/icon-message-notification.png'), icon: imageSrc || Links.staticLink('css/images/icon-message-notification.png'),
data: messageData data: messageData
}; };
if (messageData && messageData.Uid) { if (messageData?.Uid) {
options.tag = messageData.Uid; options.tag = messageData.Uid;
} }
if (WorkerNotifications) { if (WorkerNotifications) {
@ -83,7 +83,7 @@ export const NotificationUserStore = new class {
.catch(e => console.error(e)); .catch(e => console.error(e));
} else { } else {
const notification = new HTML5Notification(title, options); const notification = new HTML5Notification(title, options);
notification.show && notification.show(); notification.show?.();
notification.onclick = messageData ? () => dispatchMessage(messageData) : null; notification.onclick = messageData ? () => dispatchMessage(messageData) : null;
setTimeout(() => notification.close(), 7000); setTimeout(() => notification.close(), 7000);
} }

View file

@ -196,7 +196,7 @@ export const OpenPGPUserStore = new class {
const publicKey = findOpenPGPKey(this.publicKeys, sender/*, sign*/); const publicKey = findOpenPGPKey(this.publicKeys, sender/*, sign*/);
return await openpgp.decrypt({ return await openpgp.decrypt({
message, message,
verificationKeys: publicKey && publicKey.key, verificationKeys: publicKey?.key,
// expectSigned: true, // expectSigned: true,
// signature: '', // Detached signature // signature: '', // Detached signature
decryptionKeys: decryptedKey decryptionKeys: decryptedKey

View file

@ -169,7 +169,7 @@ export const
} }
); );
if (result) { if (result) {
if (result.error && result.error.message) { if (result.error?.message) {
if ('PWD_DIALOG_CANCEL' !== result.error.code) { if ('PWD_DIALOG_CANCEL' !== result.error.code) {
alert(result.error.code + ': ' + result.error.message); alert(result.error.code + ': ' + result.error.message);
} }

View file

@ -38,7 +38,7 @@ export class AccountPopupView extends AbstractViewPopup {
this.submitRequest(false); this.submitRequest(false);
if (iError) { if (iError) {
this.submitError(getNotification(iError)); this.submitError(getNotification(iError));
this.submitErrorAdditional((data && data.ErrorMessageAdditional) || ''); this.submitErrorAdditional(data?.ErrorMessageAdditional);
} else { } else {
rl.app.accountsAndIdentities(); rl.app.accountsAndIdentities();
this.close(); this.close();
@ -54,7 +54,7 @@ export class AccountPopupView extends AbstractViewPopup {
} }
onShow(account) { onShow(account) {
if (account && account.isAdditional()) { if (account?.isAdditional()) {
this.isNew(false); this.isNew(false);
this.email(account.email); this.email(account.email);
} else { } else {

View file

@ -213,8 +213,8 @@ export class ComposePopupView extends AbstractViewPopup {
super('Compose'); super('Compose');
const fEmailOutInHelper = (context, identity, name, isIn) => { const fEmailOutInHelper = (context, identity, name, isIn) => {
if (identity && context && identity[name]() && (isIn ? true : context[name]())) { const identityEmail = context && identity?.[name]();
const identityEmail = identity[name](); if (identityEmail && (isIn ? true : context[name]())) {
let list = context[name]().trim().split(','); let list = context[name]().trim().split(',');
list = list.filter(email => { list = list.filter(email => {
@ -222,9 +222,7 @@ export class ComposePopupView extends AbstractViewPopup {
return email && identityEmail.trim() !== email; return email && identityEmail.trim() !== email;
}); });
if (isIn) { isIn && list.push(identityEmail);
list.push(identityEmail);
}
context[name](list.join(',')); context[name](list.join(','));
} }
@ -355,7 +353,7 @@ export class ComposePopupView extends AbstractViewPopup {
}, },
attachmentsInProcess: () => this.attachments.filter(item => item && !item.complete()), attachmentsInProcess: () => this.attachments.filter(item => item && !item.complete()),
attachmentsInError: () => this.attachments.filter(item => item && item.error()), attachmentsInError: () => this.attachments.filter(item => item?.error()),
attachmentsCount: () => this.attachments.length, attachmentsCount: () => this.attachments.length,
attachmentsInErrorCount: () => this.attachmentsInError.length, attachmentsInErrorCount: () => this.attachmentsInError.length,
@ -511,7 +509,7 @@ export class ComposePopupView extends AbstractViewPopup {
alternative.children.push(data); alternative.children.push(data);
data = alternative; data = alternative;
} }
if (sign && !draft && sign[1]) { if (!draft && sign?.[1]) {
if ('openpgp' == sign[0]) { if ('openpgp' == sign[0]) {
// Doesn't sign attachments // Doesn't sign attachments
params.Html = params.Text = ''; params.Html = params.Text = '';
@ -611,7 +609,7 @@ export class ComposePopupView extends AbstractViewPopup {
this.savedErrorDesc(i18n('COMPOSE/SAVED_ERROR_ON_SEND').trim()); this.savedErrorDesc(i18n('COMPOSE/SAVED_ERROR_ON_SEND').trim());
} else { } else {
this.sendError(true); this.sendError(true);
this.sendErrorDesc(getNotification(iError, data && data.ErrorMessage) this.sendErrorDesc(getNotification(iError, data?.ErrorMessage)
|| getNotification(Notification.CantSendMessage)); || getNotification(Notification.CantSendMessage));
} }
} else { } else {
@ -762,7 +760,7 @@ export class ComposePopupView extends AbstractViewPopup {
(iError, data) => { (iError, data) => {
if (!iError && isArray(data.Result)) { if (!iError && isArray(data.Result)) {
fResponse( fResponse(
data.Result.map(item => (item && item[0] ? (new EmailModel(item[0], item[1])).toLine() : null)) data.Result.map(item => (item?.[0] ? (new EmailModel(item[0], item[1])).toLine() : null))
.filter(v => v) .filter(v => v)
); );
} else if (Notification.RequestAborted !== iError) { } else if (Notification.RequestAborted !== iError) {
@ -777,7 +775,7 @@ export class ComposePopupView extends AbstractViewPopup {
} }
selectIdentity(identity) { selectIdentity(identity) {
identity = identity && identity.item; identity = identity?.item;
if (identity) { if (identity) {
this.currentIdentity(identity); this.currentIdentity(identity);
this.setSignatureFromIdentity(identity); this.setSignatureFromIdentity(identity);
@ -1153,7 +1151,7 @@ export class ComposePopupView extends AbstractViewPopup {
}); });
} else { } else {
this.attachments.forEach(attachment => { this.attachments.forEach(attachment => {
if (attachment && attachment.fromMessage) { if (attachment?.fromMessage) {
attachment attachment
.waiting(false) .waiting(false)
.uploading(false) .uploading(false)
@ -1180,7 +1178,7 @@ export class ComposePopupView extends AbstractViewPopup {
if (!this.to()) { if (!this.to()) {
this.to.focused(true); this.to.focused(true);
} else if (!this.to.focused()) { } else if (!this.to.focused()) {
this.oEditor && this.oEditor.focus(); this.oEditor?.focus();
} }
}, 100); }, 100);
} }
@ -1266,7 +1264,7 @@ export class ComposePopupView extends AbstractViewPopup {
}) })
.on('onComplete', (id, result, data) => { .on('onComplete', (id, result, data) => {
const attachment = this.getAttachmentById(id), const attachment = this.getAttachmentById(id),
response = (data && data.Result) || {}, response = data?.Result || {},
errorCode = response.ErrorCode, errorCode = response.ErrorCode,
attachmentJson = result && response.Attachment; attachmentJson = result && response.Attachment;
@ -1354,7 +1352,7 @@ export class ComposePopupView extends AbstractViewPopup {
prepareAttachmentsForSendOrSave() { prepareAttachmentsForSendOrSave() {
const result = {}; const result = {};
this.attachments.forEach(item => { this.attachments.forEach(item => {
if (item && item.complete() && item.tempName() && item.enabled()) { if (item?.complete() && item?.tempName() && item?.enabled()) {
result[item.tempName()] = [item.fileName(), item.isInline ? '1' : '0', item.CID, item.contentLocation]; result[item.tempName()] = [item.fileName(), item.isInline ? '1' : '0', item.CID, item.contentLocation];
} }
}); });
@ -1381,7 +1379,7 @@ export class ComposePopupView extends AbstractViewPopup {
oJua || attachment.waiting(false).uploading(true); oJua || attachment.waiting(false).uploading(true);
attachment.cancel = () => { attachment.cancel = () => {
this.attachments.remove(attachment); this.attachments.remove(attachment);
oJua && oJua.cancel(attachment.id); oJua?.cancel(attachment.id);
}; };
this.attachments.push(attachment); this.attachments.push(attachment);
view && this.attachmentsArea(); view && this.attachmentsArea();
@ -1435,7 +1433,7 @@ export class ComposePopupView extends AbstractViewPopup {
isEmptyForm(includeAttachmentInProgress = true) { isEmptyForm(includeAttachmentInProgress = true) {
const withoutAttachment = includeAttachmentInProgress const withoutAttachment = includeAttachmentInProgress
? !this.attachments.length ? !this.attachments.length
: !this.attachments.some(item => item && item.complete()); : !this.attachments.some(item => item?.complete());
return ( return (
!this.to.length && !this.to.length &&
@ -1491,7 +1489,7 @@ export class ComposePopupView extends AbstractViewPopup {
this.sending(false); this.sending(false);
this.saving(false); this.saving(false);
this.oEditor && this.oEditor.clear(); this.oEditor?.clear();
this.dropMailvelope(); this.dropMailvelope();
} }

View file

@ -108,7 +108,7 @@ export class ContactsPopupView extends AbstractViewPopup {
contactHasValidName: () => !!this.viewProperties.find(prop => propertyIsName(prop) && prop.isValid()), contactHasValidName: () => !!this.viewProperties.find(prop => propertyIsName(prop) && prop.isValid()),
contactsCheckedOrSelected: () => { contactsCheckedOrSelected: () => {
const checked = ContactUserStore.filter(item => item.checked && item.checked()), const checked = ContactUserStore.filter(item => item.checked?.()),
selected = this.currentContact(); selected = this.currentContact();
return selected return selected
@ -120,7 +120,7 @@ export class ContactsPopupView extends AbstractViewPopup {
contactsSyncEnabled: () => ContactUserStore.allowSync() && ContactUserStore.syncMode(), contactsSyncEnabled: () => ContactUserStore.allowSync() && ContactUserStore.syncMode(),
viewHash: () => '' + this.viewProperties.map(property => property.value && property.value()).join('') viewHash: () => '' + this.viewProperties.map(property => property.value?.()).join('')
}); });
this.search.subscribe(() => this.reloadContactList()); this.search.subscribe(() => this.reloadContactList());
@ -164,7 +164,7 @@ export class ContactsPopupView extends AbstractViewPopup {
const data = oItem.getNameAndEmailHelper(), const data = oItem.getNameAndEmailHelper(),
email = data ? new EmailModel(data[0], data[1]) : null; email = data ? new EmailModel(data[0], data[1]) : null;
if (email && email.validate()) { if (email?.validate()) {
return email; return email;
} }
} }
@ -344,7 +344,7 @@ export class ContactsPopupView extends AbstractViewPopup {
if (this.contactsCheckedOrSelected().length) { if (this.contactsCheckedOrSelected().length) {
Remote.request('ContactsDelete', Remote.request('ContactsDelete',
(iError, oData) => { (iError, oData) => {
if (500 < (!iError && oData && oData.Time ? pInt(oData.Time) : 0)) { if (500 < (!iError && oData?.Time) ? pInt(oData.Time) : 0) {
this.reloadContactList(this.bDropPageAfterDelete); this.reloadContactList(this.bDropPageAfterDelete);
} else { } else {
setTimeout(() => this.reloadContactList(this.bDropPageAfterDelete), 500); setTimeout(() => this.reloadContactList(this.bDropPageAfterDelete), 500);

View file

@ -248,7 +248,7 @@ export class DomainPopupView extends AbstractViewPopup {
if (oDomain) { if (oDomain) {
this.enableSmartPorts(false); this.enableSmartPorts(false);
this.edit(true); this.edit(true);
forEachObjectEntry(oDomain, (key, value) => this[key] && this[key](value)); forEachObjectEntry(oDomain, (key, value) => this[key]?.(value));
this.enableSmartPorts(true); this.enableSmartPorts(true);
} }
} }

View file

@ -63,9 +63,7 @@ export class IdentityPopupView extends AbstractViewPopup {
submitForm() { submitForm() {
if (!this.submitRequest()) { if (!this.submitRequest()) {
if (this.signature && this.signature.__fetchEditorValue) { this.signature?.__fetchEditorValue?.();
this.signature.__fetchEditorValue();
}
if (!this.emailHasError()) { if (!this.emailHasError()) {
this.emailHasError(!this.email().trim()); this.emailHasError(!this.email().trim());

View file

@ -51,7 +51,7 @@ export class LanguagesPopupView extends AbstractViewPopup {
} }
changeLanguage(lang) { changeLanguage(lang) {
this.fLang && this.fLang(lang); this.fLang?.(lang);
this.close(); this.close();
} }
} }

View file

@ -94,7 +94,7 @@ export class OpenPgpGeneratePopupView extends AbstractViewPopup {
showError(e) { showError(e) {
console.log(e); console.log(e);
if (e && e.message) { if (e?.message) {
this.submitError(e.message); this.submitError(e.message);
} }
} }

View file

@ -114,9 +114,9 @@ export class LoginUserView extends AbstractViewLogin {
if (Notification.InvalidInputArgument == iError) { if (Notification.InvalidInputArgument == iError) {
iError = Notification.AuthError; iError = Notification.AuthError;
} }
this.submitError(getNotification(iError, (oData ? oData.ErrorMessage : ''), this.submitError(getNotification(iError, oData?.ErrorMessage,
Notification.UnknownNotification)); Notification.UnknownNotification));
this.submitErrorAdditional((oData && oData.ErrorMessageAdditional) || ''); this.submitErrorAdditional(oData?.ErrorMessageAdditional);
} else { } else {
rl.setData(oData.Result); rl.setData(oData.Result);
} }

View file

@ -82,7 +82,7 @@ export class MailFolderList extends AbstractViewLeft {
} }
el = eqs(event, 'a'); el = eqs(event, 'a');
if (el && el.matches('.selectable')) { if (el?.matches('.selectable')) {
event.preventDefault(); event.preventDefault();
const folder = ko.dataFor(el); const folder = ko.dataFor(el);
if (folder) { if (folder) {
@ -170,10 +170,10 @@ export class MailFolderList extends AbstractViewLeft {
AppUserStore.focusedState.subscribe(value => { AppUserStore.focusedState.subscribe(value => {
let el = qs('li a.focused'); let el = qs('li a.focused');
el && el.classList.remove('focused'); el?.classList.remove('focused');
if (Scope.FolderList === value) { if (Scope.FolderList === value) {
el = qs('li a.selected'); el = qs('li a.selected');
el && el.classList.add('focused'); el?.classList.add('focused');
} }
}); });
} }

View file

@ -210,7 +210,7 @@ export class MailMessageList extends AbstractViewRight {
const sFolder = e.detail.Folder, iUid = e.detail.Uid; const sFolder = e.detail.Folder, iUid = e.detail.Uid;
const message = MessagelistUserStore.find( const message = MessagelistUserStore.find(
item => item && sFolder === item.folder && iUid == item.uid item => sFolder === item?.folder && iUid == item?.uid
); );
if ('INBOX' === sFolder) { if ('INBOX' === sFolder) {
@ -326,7 +326,7 @@ export class MailMessageList extends AbstractViewRight {
moveNewCommand(vm, event) { moveNewCommand(vm, event) {
if (this.newMoveToFolder && this.mobileCheckedStateShow()) { if (this.newMoveToFolder && this.mobileCheckedStateShow()) {
if (vm && event && event.preventDefault) { if (vm && event?.preventDefault) {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
} }
@ -428,7 +428,7 @@ export class MailMessageList extends AbstractViewRight {
getDragData(event) { getDragData(event) {
const item = ko.dataFor(doc.elementFromPoint(event.clientX, event.clientY)); const item = ko.dataFor(doc.elementFromPoint(event.clientX, event.clientY));
item && item.checked && item.checked(true); item?.checked?.(true);
const uids = MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails(); const uids = MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails();
item && !uids.includes(item.uid) && uids.push(item.uid); item && !uids.includes(item.uid) && uids.push(item.uid);
return uids.length ? { return uids.length ? {
@ -571,7 +571,7 @@ export class MailMessageList extends AbstractViewRight {
} }
gotoThread(message) { gotoThread(message) {
if (message && 0 < message.threadsLen()) { if (0 < message?.threadsLen()) {
MessagelistUserStore.pageBeforeThread(MessagelistUserStore.page()); MessagelistUserStore.pageBeforeThread(MessagelistUserStore.page());
hasher.setHash( hasher.setHash(
@ -718,7 +718,7 @@ export class MailMessageList extends AbstractViewRight {
registerShortcut('t', '', [Scope.MessageList], () => { registerShortcut('t', '', [Scope.MessageList], () => {
let message = MessagelistUserStore.selectedMessage() || MessagelistUserStore.focusedMessage(); let message = MessagelistUserStore.selectedMessage() || MessagelistUserStore.focusedMessage();
if (message && 0 < message.threadsLen()) { if (0 < message?.threadsLen()) {
this.gotoThread(message); this.gotoThread(message);
} }
return false; return false;

View file

@ -134,8 +134,8 @@ export class MailMessageView extends AbstractViewRight {
allowAttachmentControls: () => arrayLength(attachmentsActions) && SettingsCapa('AttachmentsActions'), allowAttachmentControls: () => arrayLength(attachmentsActions) && SettingsCapa('AttachmentsActions'),
downloadAsZipAllowed: () => this.attachmentsActions.includes('zip') downloadAsZipAllowed: () => this.attachmentsActions.includes('zip')
&& (currentMessage() ? currentMessage().attachments : []) && (currentMessage()?.attachments || [])
.filter(item => item && !item.isLinked() && item.checked() && item.download) .filter(item => item?.download && !item?.isLinked() && item?.checked())
.length, .length,
tagsAllowed: () => FolderUserStore.currentFolder() ? FolderUserStore.currentFolder().tagsAllowed() : false, tagsAllowed: () => FolderUserStore.currentFolder() ? FolderUserStore.currentFolder().tagsAllowed() : false,
@ -286,7 +286,7 @@ export class MailMessageView extends AbstractViewRight {
el = eqs(event, '.attachmentsPlace .attachmentItem .attachmentNameParent'); el = eqs(event, '.attachmentsPlace .attachmentItem .attachmentNameParent');
if (el) { if (el) {
const attachment = ko.dataFor(el); const attachment = ko.dataFor(el);
if (attachment && attachment.linkDownload()) { if (attachment?.linkDownload()) {
if ('message/rfc822' == attachment.mimeType) { if ('message/rfc822' == attachment.mimeType) {
// TODO // TODO
rl.fetch(attachment.linkDownload()).then(response => { rl.fetch(attachment.linkDownload()).then(response => {
@ -393,7 +393,7 @@ export class MailMessageView extends AbstractViewRight {
// toggle message blockquotes // toggle message blockquotes
registerShortcut('b', '', [Scope.MessageList, Scope.MessageView], () => { registerShortcut('b', '', [Scope.MessageList, Scope.MessageView], () => {
const message = currentMessage(); const message = currentMessage();
if (message && message.body) { if (message?.body) {
message.body.querySelectorAll('.rlBlockquoteSwitcher').forEach(node => node.click()); message.body.querySelectorAll('.rlBlockquoteSwitcher').forEach(node => node.click());
return false; return false;
} }
@ -411,7 +411,7 @@ export class MailMessageView extends AbstractViewRight {
// print // print
addShortcut('p,printscreen', 'meta', [Scope.MessageView, Scope.MessageList], () => { addShortcut('p,printscreen', 'meta', [Scope.MessageView, Scope.MessageList], () => {
currentMessage() && currentMessage().printMessage(); currentMessage()?.printMessage();
return false; return false;
}); });
@ -510,7 +510,7 @@ export class MailMessageView extends AbstractViewRight {
downloadAsZip() { downloadAsZip() {
const hashes = (currentMessage() ? currentMessage().attachments : []) const hashes = (currentMessage() ? currentMessage().attachments : [])
.map(item => (item && !item.isLinked() && item.checked() ? item.download : '')) .map(item => item?.checked() && !item?.isLinked() ? item.download : '')
.filter(v => v); .filter(v => v);
if (hashes.length) { if (hashes.length) {
Remote.post('AttachmentsActions', this.downloadAsZipLoading, { Remote.post('AttachmentsActions', this.downloadAsZipLoading, {
@ -518,7 +518,7 @@ export class MailMessageView extends AbstractViewRight {
Hashes: hashes Hashes: hashes
}) })
.then(result => { .then(result => {
let hash = result && result.Result && result.Result.FileHash; let hash = result?.Result?.FileHash;
if (hash) { if (hash) {
download(attachmentDownload(hash), hash+'.zip'); download(attachmentDownload(hash), hash+'.zip');
} else { } else {
@ -577,7 +577,7 @@ export class MailMessageView extends AbstractViewRight {
if (result.data) { if (result.data) {
MimeToMessage(result.data, oMessage); MimeToMessage(result.data, oMessage);
oMessage.html() ? oMessage.viewHtml() : oMessage.viewPlain(); oMessage.html() ? oMessage.viewHtml() : oMessage.viewPlain();
if (result.signatures && result.signatures.length) { if (result.signatures?.length) {
oMessage.pgpSigned(true); oMessage.pgpSigned(true);
oMessage.pgpVerified({ oMessage.pgpVerified({
signatures: result.signatures, signatures: result.signatures,
@ -596,7 +596,7 @@ export class MailMessageView extends AbstractViewRight {
oMessage.pgpVerified(result); oMessage.pgpVerified(result);
} }
/* /*
if (result && result.success) { if (result?.success) {
i18n('OPENPGP/GOOD_SIGNATURE', { i18n('OPENPGP/GOOD_SIGNATURE', {
USER: validKey.user + ' (' + validKey.id + ')' USER: validKey.user + ' (' + validKey.id + ')'
}); });
@ -604,7 +604,7 @@ export class MailMessageView extends AbstractViewRight {
} else { } else {
const keyIds = arrayLength(signingKeyIds) ? signingKeyIds : null, const keyIds = arrayLength(signingKeyIds) ? signingKeyIds : null,
additional = keyIds additional = keyIds
? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(v => v).join(', ') ? keyIds.map(item => item?.toHex?.()).filter(v => v).join(', ')
: ''; : '';
i18n('OPENPGP/ERROR', { i18n('OPENPGP/ERROR', {

View file

@ -52,7 +52,7 @@ export class SystemDropDownUserView extends AbstractViewRight {
} }
accountClick(account, event) { accountClick(account, event) {
let email = account && account.email; let email = account?.email;
if (email && 0 === event.button && AccountUserStore.email() != email) { if (email && 0 === event.button && AccountUserStore.email() != email) {
AccountUserStore.loading(true); AccountUserStore.loading(true);
event.preventDefault(); event.preventDefault();

View file

@ -70,7 +70,7 @@
htmlDrag = b => doc.documentElement.classList.toggle('firefox-drag', b), htmlDrag = b => doc.documentElement.classList.toggle('firefox-drag', b),
setDragImage = (src, xOffset, yOffset) => { setDragImage = (src, xOffset, yOffset) => {
img && img.remove(); img?.remove();
if (src) { if (src) {
// create drag image from custom element or drag source // create drag image from custom element or drag source
img = src.cloneNode(true); img = src.cloneNode(true);
@ -85,7 +85,7 @@
if (dragSource) { if (dragSource) {
clearInterval(holdInterval); clearInterval(holdInterval);
// dispose of drag image element // dispose of drag image element
img && img.remove(); img?.remove();
isDragging && dispatchEvent(lastTouch, 'dragend', dragSource); isDragging && dispatchEvent(lastTouch, 'dragend', dragSource);
img = dragSource = lastTouch = lastTarget = dataTransfer = holdInterval = null; img = dragSource = lastTouch = lastTarget = dataTransfer = holdInterval = null;
isDragging = allowDrop = false; isDragging = allowDrop = false;

View file

@ -64,9 +64,8 @@ const
keydown = event => { keydown = event => {
let key = (event.key || '').toLowerCase().replace(' ','space'), let key = (event.key || '').toLowerCase().replace(' ','space'),
modifiers = ['alt','ctrl','meta','shift'].filter(v => event[v+'Key']).join('+'); modifiers = ['alt','ctrl','meta','shift'].filter(v => event[v+'Key']).join('+');
scope[key] && scope[key][modifiers] && scope[key][modifiers].forEach(cmd => exec(event, cmd)); scope[key]?.[modifiers]?.forEach(cmd => exec(event, cmd));
!event.defaultPrevented && _scope !== 'all' && _scopes.all[key] && _scopes.all[key][modifiers] !event.defaultPrevented && _scope !== 'all' && _scopes.all[key]?.[modifiers]?.forEach(cmd => exec(event, cmd));
&& _scopes.all[key][modifiers].forEach(cmd => exec(event, cmd));
}; };
win.shortcuts = shortcuts; win.shortcuts = shortcuts;