mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Use JavaScript Optional chaining
This commit is contained in:
parent
d9bc435e2c
commit
732b6eb641
55 changed files with 169 additions and 199 deletions
|
|
@ -4,7 +4,7 @@ import { addObservablesTo } from 'External/ko';
|
|||
|
||||
let notificator = null,
|
||||
player = null,
|
||||
canPlay = type => player && !!player.canPlayType(type).replace('no', ''),
|
||||
canPlay = type => !!player?.canPlayType(type).replace('no', ''),
|
||||
|
||||
audioCtx = window.AudioContext || window.webkitAudioContext,
|
||||
|
||||
|
|
@ -92,7 +92,7 @@ export const SMAudio = new class {
|
|||
}
|
||||
|
||||
pause() {
|
||||
player && player.pause();
|
||||
player?.pause();
|
||||
fireEvent('audio.stop');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,8 +37,7 @@ export const
|
|||
* @param {string} folderHash
|
||||
* @returns {string}
|
||||
*/
|
||||
getFolderFullName = folderHash =>
|
||||
folderHash && FOLDERS_NAME_CACHE[folderHash] ? FOLDERS_NAME_CACHE[folderHash] : '',
|
||||
getFolderFullName = folderHash => (folderHash && FOLDERS_NAME_CACHE[folderHash]) || '',
|
||||
|
||||
/**
|
||||
* @param {string} folderHash
|
||||
|
|
@ -79,9 +78,7 @@ export class MessageFlagsCache
|
|||
* @returns {bool}
|
||||
*/
|
||||
static hasFlag(folderFullName, uid, flag) {
|
||||
return MESSAGE_FLAGS_CACHE[folderFullName]
|
||||
&& MESSAGE_FLAGS_CACHE[folderFullName][uid]
|
||||
&& MESSAGE_FLAGS_CACHE[folderFullName][uid].includes(flag);
|
||||
return MESSAGE_FLAGS_CACHE[folderFullName]?.[uid]?.includes(flag);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -90,7 +87,7 @@ export class MessageFlagsCache
|
|||
* @returns {?Array}
|
||||
*/
|
||||
static getFor(folderFullName, uid) {
|
||||
return MESSAGE_FLAGS_CACHE[folderFullName] && MESSAGE_FLAGS_CACHE[folderFullName][uid];
|
||||
return MESSAGE_FLAGS_CACHE[folderFullName]?.[uid];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ export const FileInfo = {
|
|||
.map(item => item ? FileInfo.getIconClass(FileInfo.getExtension(item.fileName), item.mimeType) : '')
|
||||
.validUnique();
|
||||
|
||||
return (icons && 1 === icons.length && 'icon-file' !== icons[0])
|
||||
return (1 === icons?.length && 'icon-file' !== icons[0])
|
||||
? icons[0]
|
||||
: 'icon-attachment';
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ fetchFolderInformation = (fCallback, folder, list = []) => {
|
|||
Remote.request('FolderInformation', fCallback, {
|
||||
Folder: folder,
|
||||
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()) {
|
||||
MessagelistUserStore.reloadFlagsAndCachedMessage();
|
||||
|
|
@ -134,7 +134,7 @@ refreshFoldersInterval = 300000,
|
|||
* @param {Array=} list = []
|
||||
*/
|
||||
folderInformation = (folder, list) => {
|
||||
if (folder && folder.trim()) {
|
||||
if (folder?.trim()) {
|
||||
fetchFolderInformation(
|
||||
(iError, data) => {
|
||||
if (!iError && data.Result) {
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ export const
|
|||
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),
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export const
|
|||
* @param {string} text
|
||||
* @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
|
||||
|
|
@ -47,7 +47,7 @@ export const
|
|||
findAttachmentByCid = cid => oAttachments.findByCid(cid),
|
||||
findLocationByCid = cid => {
|
||||
const attachment = findAttachmentByCid(cid);
|
||||
return attachment && attachment.contentLocation ? attachment : 0;
|
||||
return attachment?.contentLocation ? attachment : 0;
|
||||
},
|
||||
|
||||
// convert body attributes to CSS
|
||||
|
|
@ -256,7 +256,7 @@ export const
|
|||
value = value.slice(4);
|
||||
setAttribute('data-x-src-cid', value);
|
||||
attachment = findAttachmentByCid(value);
|
||||
if (attachment && attachment.download) {
|
||||
if (attachment?.download) {
|
||||
oElement.src = attachment.linkPreview();
|
||||
attachment.isInline(true);
|
||||
attachment.isLinked(true);
|
||||
|
|
@ -320,7 +320,7 @@ export const
|
|||
let lowerUrl = found.toLowerCase();
|
||||
if ('cid:' === lowerUrl.slice(0, 4)) {
|
||||
const attachment = findAttachmentByCid(found);
|
||||
if (attachment && attachment.linkPreview && name) {
|
||||
if (attachment?.linkPreview && name) {
|
||||
oStyle[property] = "url('" + attachment.linkPreview() + "')";
|
||||
attachment.isInline(true);
|
||||
attachment.isLinked(true);
|
||||
|
|
@ -434,9 +434,8 @@ export const
|
|||
parent = node,
|
||||
ordered = 'OL' == node.tagName,
|
||||
i = 0;
|
||||
while (parent && parent.parentNode && parent.parentNode.closest) {
|
||||
parent = parent.parentNode.closest('ol,ul');
|
||||
parent && (prefix = ' ' + prefix);
|
||||
while ((parent = parent?.parentNode?.closest('ol,ul'))) {
|
||||
prefix = ' ' + prefix;
|
||||
}
|
||||
node.querySelectorAll(':scope > li').forEach(li => {
|
||||
li.prepend('\n' + prefix + (ordered ? `${++i}. ` : ' * '));
|
||||
|
|
@ -567,7 +566,7 @@ export class HtmlEditor {
|
|||
editor.on('focus', () => this.blurTimer && clearTimeout(this.blurTimer));
|
||||
editor.on('mode', () => {
|
||||
this.blurTrigger();
|
||||
this.onModeChange && this.onModeChange(!this.isPlain());
|
||||
this.onModeChange?.(!this.isPlain());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -575,7 +574,7 @@ export class HtmlEditor {
|
|||
blurTrigger() {
|
||||
if (this.onBlur) {
|
||||
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() {
|
||||
try {
|
||||
return this.editor && !!this.editor.focusManager.hasFocus;
|
||||
return !!this.editor?.focusManager.hasFocus;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,10 +49,7 @@ export function runSettingsViewModelHooks(admin) {
|
|||
* @param {string} name
|
||||
* @returns {?}
|
||||
*/
|
||||
rl.pluginSettingsGet = (pluginSection, name) => {
|
||||
let plugins = SettingsGet('Plugins');
|
||||
plugins = plugins && null != plugins[pluginSection] ? plugins[pluginSection] : null;
|
||||
return plugins ? (null == plugins[name] ? null : plugins[name]) : null;
|
||||
};
|
||||
rl.pluginSettingsGet = (pluginSection, name) =>
|
||||
SettingsGet('Plugins')?.[pluginSection]?.[name];
|
||||
|
||||
rl.pluginPopupView = AbstractViewPopup;
|
||||
|
|
|
|||
|
|
@ -422,7 +422,7 @@ export class Selector {
|
|||
lineUid = '';
|
||||
|
||||
const uid = this.getItemUid(item);
|
||||
if (event && event.shiftKey) {
|
||||
if (event?.shiftKey) {
|
||||
if (uid && this.sLastUid && uid !== this.sLastUid) {
|
||||
list = this.list();
|
||||
checked = item.checked();
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ export const
|
|||
* @param {Function=} langCallback = null
|
||||
*/
|
||||
initOnStartOrLangChange = (startCallback, langCallback = null) => {
|
||||
startCallback && startCallback();
|
||||
startCallback?.();
|
||||
startCallback && trigger.subscribe(startCallback);
|
||||
langCallback && trigger.subscribe(langCallback);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -26,8 +26,7 @@ export const
|
|||
.trim(),
|
||||
|
||||
defaultOptionsAfterRender = (domItem, item) =>
|
||||
domItem && item && undefined !== item.disabled
|
||||
&& domItem.classList.toggle('disabled', domItem.disabled = item.disabled),
|
||||
item && undefined !== item.disabled && domItem?.classList.toggle('disabled', domItem.disabled = item.disabled),
|
||||
|
||||
// unescape(encodeURIComponent()) makes the UTF-16 DOMString to an UTF-8 string
|
||||
b64EncodeJSON = data => btoa(unescape(encodeURIComponent(JSON.stringify(data)))),
|
||||
|
|
|
|||
|
|
@ -131,7 +131,7 @@ computedPaginatorHelper = (koCurrentPage, koPageCount) => {
|
|||
* @returns {boolean}
|
||||
*/
|
||||
mailToHelper = mailToUrl => {
|
||||
if (mailToUrl && 'mailto:' === mailToUrl.slice(0, 7).toLowerCase()) {
|
||||
if ('mailto:' === mailToUrl?.slice(0, 7).toLowerCase()) {
|
||||
mailToUrl = mailToUrl.slice(7).split('?');
|
||||
|
||||
const
|
||||
|
|
@ -181,7 +181,7 @@ setLayoutResizer = (source, target, sClientSideKeyName, mode) =>
|
|||
target.removeAttribute('style');
|
||||
source.removeAttribute('style');
|
||||
}
|
||||
source.observer && source.observer.disconnect();
|
||||
source.observer?.disconnect();
|
||||
// source.classList.toggle('resizable', mode);
|
||||
if (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.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;
|
||||
let
|
||||
isNew = false,
|
||||
json = oData && oData.Result,
|
||||
json = oData?.Result,
|
||||
message = oMessage || MessageUserStore.message();
|
||||
|
||||
if (
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export class AbstractInput {
|
|||
this.value = params.value || '';
|
||||
this.label = params.label || '';
|
||||
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.labeled = null != params.label;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { doc, createElement, addEventsListeners } from 'Common/Globals';
|
|||
import { EmailModel } from 'Model/Email';
|
||||
|
||||
const contentType = 'snappymail/emailaddress',
|
||||
getAddressKey = li => li && li.emailaddress && li.emailaddress.key;
|
||||
getAddressKey = li => li?.emailaddress?.key;
|
||||
|
||||
let dragAddress, datalist;
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ export class EmailAddressesComponent {
|
|||
const self = this,
|
||||
// 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
|
||||
validDropzone = () => dragAddress && dragAddress.li.parentNode !== self.ul,
|
||||
validDropzone = () => dragAddress?.li.parentNode !== self.ul,
|
||||
fnDrag = e => validDropzone() && e.preventDefault();
|
||||
|
||||
self.element = element;
|
||||
|
|
@ -116,7 +116,7 @@ export class EmailAddressesComponent {
|
|||
value,
|
||||
items => {
|
||||
self._resetDatalist();
|
||||
items && items.forEach(item => datalist.append(new Option(item)));
|
||||
items?.forEach(item => datalist.append(new Option(item)));
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
16
dev/External/User/ko.js
vendored
16
dev/External/User/ko.js
vendored
|
|
@ -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 Mobile dataTransfer.types.includes(rlContentType) fails, only text/plain is set
|
||||
dragMessages = () => dragData && 'messages' === dragData.action,
|
||||
dragSortable = () => dragData && 'sortable' === dragData.action,
|
||||
dragMessages = () => 'messages' === dragData?.action,
|
||||
dragSortable = () => 'sortable' === dragData?.action,
|
||||
setDragAction = (e, action, effect, data, img) => {
|
||||
dragData = {
|
||||
action: action,
|
||||
|
|
@ -45,8 +45,8 @@ Object.assign(ko.bindingHandlers, {
|
|||
let editor = null;
|
||||
|
||||
const fValue = fValueAccessor(),
|
||||
fUpdateEditorValue = () => fValue && fValue.__editor && fValue.__editor.setHtmlOrPlain(fValue()),
|
||||
fUpdateKoValue = () => fValue && fValue.__editor && fValue(fValue.__editor.getDataWithHtmlMark()),
|
||||
fUpdateEditorValue = () => fValue?.__editor?.setHtmlOrPlain(fValue()),
|
||||
fUpdateKoValue = () => fValue?.__editor && fValue(fValue.__editor.getDataWithHtmlMark()),
|
||||
fOnReady = () => {
|
||||
fValue.__editor = editor;
|
||||
fUpdateEditorValue();
|
||||
|
|
@ -76,7 +76,7 @@ Object.assign(ko.bindingHandlers, {
|
|||
focused = fValue.focused;
|
||||
|
||||
element.addresses = new EmailAddressesComponent(element, {
|
||||
focusCallback: value => focused && focused(!!value),
|
||||
focusCallback: value => focused?.(!!value),
|
||||
autoCompleteSource: fAllBindings.get('autoCompleteSource'),
|
||||
onChange: value => fValue(value)
|
||||
});
|
||||
|
|
@ -137,7 +137,7 @@ Object.assign(ko.bindingHandlers, {
|
|||
if (dragMessages()) {
|
||||
fnStop(e);
|
||||
element.classList.add('droppableHover');
|
||||
if (folder && folder.collapsed()) {
|
||||
if (folder?.collapsed()) {
|
||||
dragTimer.start(() => {
|
||||
folder.collapsed(false);
|
||||
setExpandedFolder(folder.fullName, true);
|
||||
|
|
@ -153,7 +153,7 @@ Object.assign(ko.bindingHandlers, {
|
|||
fnStop(e);
|
||||
if (dragMessages() && ['move','copy'].includes(e.dataTransfer.effectAllowed)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
@ -220,7 +220,7 @@ Object.assign(ko.bindingHandlers, {
|
|||
options.list(arr);
|
||||
}
|
||||
dragData = null;
|
||||
options.afterMove && options.afterMove();
|
||||
options.afterMove?.();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
8
dev/External/ko.js
vendored
8
dev/External/ko.js
vendored
|
|
@ -26,14 +26,14 @@ export const
|
|||
addSubscribablesTo = (target, subscribables) =>
|
||||
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
|
||||
koArrayWithDestroy = data => {
|
||||
data = ko.observableArray(data);
|
||||
data.subscribe(changes =>
|
||||
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');
|
||||
return data;
|
||||
|
|
@ -172,12 +172,12 @@ ko.extenders.toggleSubscribeProperty = (target, options) => {
|
|||
const prop = options[1];
|
||||
if (prop) {
|
||||
target.subscribe(
|
||||
prev => prev && prev[prop] && prev[prop](false),
|
||||
prev => prev?.[prop]?.(false),
|
||||
options[0],
|
||||
'beforeChange'
|
||||
);
|
||||
|
||||
target.subscribe(next => next && next[prop] && next[prop](true), options[0]);
|
||||
target.subscribe(next => next?.[prop]?.(true), options[0]);
|
||||
}
|
||||
|
||||
return target;
|
||||
|
|
|
|||
|
|
@ -50,8 +50,7 @@ export class AbstractModel {
|
|||
// forEachObjectEntry(this, (key, value) => {
|
||||
forEachObjectValue(this, value => {
|
||||
/** clear CollectionModel */
|
||||
let arr = ko.isObservableArray(value) ? value() : value;
|
||||
arr && arr.onDestroy && arr.onDestroy();
|
||||
(ko.isObservableArray(value) ? value() : value)?.onDestroy?.();
|
||||
/** destroy ko.observable/ko.computed? */
|
||||
// dispose(value);
|
||||
/** clear object value */
|
||||
|
|
@ -76,7 +75,7 @@ export class AbstractModel {
|
|||
*/
|
||||
static reviveFromJson(json) {
|
||||
let obj = this.validJson(json) ? new this() : null;
|
||||
obj && obj.revivePropertiesFromJson(json);
|
||||
obj?.revivePropertiesFromJson(json);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ export class AbstractViewSettings
|
|||
addSubscribablesTo(this, {
|
||||
[prop]: (value => {
|
||||
this[trigger](SaveSettingsStep.Animate);
|
||||
valueCb && valueCb(value);
|
||||
valueCb?.(value);
|
||||
rl.app.Remote.saveSetting(name, value,
|
||||
iError => {
|
||||
this[trigger](iError ? SaveSettingsStep.FalseResult : SaveSettingsStep.TrueResult);
|
||||
|
|
|
|||
|
|
@ -10,10 +10,7 @@ let
|
|||
defaultScreenName = '';
|
||||
|
||||
const
|
||||
autofocus = dom => {
|
||||
const af = dom.querySelector('[autofocus]');
|
||||
af && af.focus();
|
||||
},
|
||||
autofocus = dom => dom.querySelector('[autofocus]')?.focus(),
|
||||
|
||||
visiblePopups = new Set,
|
||||
|
||||
|
|
@ -21,7 +18,7 @@ const
|
|||
* @param {string} screenName
|
||||
* @returns {?Object}
|
||||
*/
|
||||
screen = screenName => screenName && null != SCREENS[screenName] ? SCREENS[screenName] : null,
|
||||
screen = screenName => (screenName && SCREENS[screenName]) || null,
|
||||
|
||||
/**
|
||||
* @param {Function} ViewModelClass
|
||||
|
|
@ -77,10 +74,10 @@ const
|
|||
if (e.target === vmDom) {
|
||||
if (vmDom.classList.contains('animate')) {
|
||||
autofocus(vmDom);
|
||||
vm.afterShow && vm.afterShow();
|
||||
vm.afterShow?.();
|
||||
} else {
|
||||
vmDom.close();
|
||||
vm.afterHide && vm.afterHide();
|
||||
vm.afterHide?.();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -101,7 +98,7 @@ const
|
|||
});
|
||||
} else {
|
||||
visiblePopups.delete(vm);
|
||||
vm.onHide && vm.onHide();
|
||||
vm.onHide?.();
|
||||
vm.keyScope.unset();
|
||||
vmDom.classList.remove('animate'); // trigger the transitions
|
||||
}
|
||||
|
|
@ -118,7 +115,7 @@ const
|
|||
vm
|
||||
);
|
||||
|
||||
vm.onBuild && vm.onBuild(vmDom);
|
||||
vm.onBuild?.(vmDom);
|
||||
|
||||
fireEvent('rl-view-model', vm);
|
||||
} else {
|
||||
|
|
@ -142,10 +139,10 @@ const
|
|||
},
|
||||
|
||||
hideScreen = (screenToHide, destroy) => {
|
||||
screenToHide.onHide && screenToHide.onHide();
|
||||
screenToHide.onHide?.();
|
||||
forEachViewModel(screenToHide, (vm, dom) => {
|
||||
dom.hidden = true;
|
||||
vm.onHide && vm.onHide();
|
||||
vm.onHide?.();
|
||||
destroy && vm.viewModelDom.remove();
|
||||
});
|
||||
},
|
||||
|
|
@ -155,7 +152,7 @@ const
|
|||
* @returns {void}
|
||||
*/
|
||||
hideScreenPopup = ViewModelClassToHide => {
|
||||
if (ViewModelClassToHide && ViewModelClassToHide.__vm && ViewModelClassToHide.__dom) {
|
||||
if (ViewModelClassToHide?.__vm && ViewModelClassToHide?.__dom) {
|
||||
ViewModelClassToHide.__vm.modalVisible(false);
|
||||
}
|
||||
},
|
||||
|
|
@ -190,7 +187,7 @@ const
|
|||
}
|
||||
}
|
||||
|
||||
if (vmScreen && vmScreen.__started) {
|
||||
if (vmScreen?.__started) {
|
||||
isSameScreen = currentScreen && vmScreen === currentScreen;
|
||||
|
||||
if (!vmScreen.__builded) {
|
||||
|
|
@ -200,7 +197,7 @@ const
|
|||
buildViewModel(ViewModelClass, vmScreen)
|
||||
);
|
||||
|
||||
vmScreen.onBuild && vmScreen.onBuild();
|
||||
vmScreen.onBuild?.();
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
|
|
@ -214,19 +211,19 @@ const
|
|||
|
||||
// show screen
|
||||
if (!isSameScreen) {
|
||||
vmScreen.onShow && vmScreen.onShow();
|
||||
vmScreen.onShow?.();
|
||||
|
||||
forEachViewModel(vmScreen, (vm, dom) => {
|
||||
vm.beforeShow && vm.beforeShow();
|
||||
vm.beforeShow?.();
|
||||
i18nToNodes(dom);
|
||||
dom.hidden = false;
|
||||
vm.onShow && vm.onShow();
|
||||
vm.onShow?.();
|
||||
autofocus(dom);
|
||||
});
|
||||
}
|
||||
// --
|
||||
|
||||
vmScreen.__cross && vmScreen.__cross.parse(subPart);
|
||||
vmScreen.__cross?.parse(subPart);
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
|
|
@ -248,11 +245,11 @@ export const
|
|||
if (vm) {
|
||||
params = params || [];
|
||||
|
||||
vm.beforeShow && vm.beforeShow(...params);
|
||||
vm.beforeShow?.(...params);
|
||||
|
||||
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');
|
||||
c && (c.hidden = false);
|
||||
l && l.remove();
|
||||
l?.remove();
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export class AbstractCollectionModel extends Array
|
|||
}
|
||||
|
||||
onDestroy() {
|
||||
this.forEach(item => item.onDestroy && item.onDestroy());
|
||||
this.forEach(item => item.onDestroy?.());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -283,7 +283,7 @@ export class EmailModel extends AbstractModel {
|
|||
*/
|
||||
static reviveFromJson(json) {
|
||||
const email = super.reviveFromJson(json);
|
||||
email && email.clearDuplicateName();
|
||||
email?.clearDuplicateName();
|
||||
return email;
|
||||
}
|
||||
|
||||
|
|
@ -351,7 +351,7 @@ export class EmailModel extends AbstractModel {
|
|||
? new EmailModel(item.address.replace(/^[<]+(.*)[>]+$/g, '$1'), item.name || '')
|
||||
: null;
|
||||
|
||||
if (address && address.email) {
|
||||
if (address?.email) {
|
||||
exists = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export class EmailCollectionModel extends AbstractCollectionModel
|
|||
toStringClear() {
|
||||
const result = [];
|
||||
this.forEach(email => {
|
||||
if (email && email.email && email.name) {
|
||||
if (email?.email && email?.name) {
|
||||
result.push(email.email);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -100,8 +100,8 @@ export const
|
|||
.post('Folders', FolderUserStore.foldersLoading)
|
||||
.then(data => {
|
||||
data = FolderCollectionModel.reviveFromJson(data.Result);
|
||||
data && data.storeIt();
|
||||
fCallback && fCallback(true);
|
||||
data?.storeIt();
|
||||
fCallback?.(true);
|
||||
// Repeat every 15 minutes?
|
||||
// this.foldersTimeout = setTimeout(loadFolders, 900000);
|
||||
})
|
||||
|
|
@ -128,7 +128,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
|||
*/
|
||||
static reviveFromJson(object) {
|
||||
const expandedFolders = Local.get(ClientSideKeyNameExpandedFolders);
|
||||
if (object && object.SystemFolders) {
|
||||
if (object?.SystemFolders) {
|
||||
forEachObjectEntry(SystemFolders, key =>
|
||||
SystemFolders[key] = SettingsGet(key+'Folder') || object.SystemFolders[FolderType[key]]
|
||||
);
|
||||
|
|
|
|||
|
|
@ -323,7 +323,7 @@ export class MessageModel extends AbstractModel {
|
|||
*/
|
||||
fromDkimData() {
|
||||
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 || ''];
|
||||
}
|
||||
|
||||
|
|
@ -399,7 +399,7 @@ export class MessageModel extends AbstractModel {
|
|||
* @returns {string}
|
||||
*/
|
||||
fromAsSingleEmail() {
|
||||
return isArray(this.from) && this.from[0] ? this.from[0].email : '';
|
||||
return (isArray(this.from) && this.from[0]?.email) || '';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -136,7 +136,7 @@ export class AbstractFetchRemote
|
|||
undefined === iTimeout ? 30000 : pInt(iTimeout),
|
||||
data => {
|
||||
let cached = false;
|
||||
if (data && data.Time) {
|
||||
if (data?.Time) {
|
||||
cached = pInt(data.Time) > Date.now() - start;
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ export class AbstractFetchRemote
|
|||
}
|
||||
}
|
||||
|
||||
fCallback && fCallback(
|
||||
fCallback?.(
|
||||
iError,
|
||||
data,
|
||||
cached,
|
||||
|
|
@ -173,7 +173,7 @@ export class AbstractFetchRemote
|
|||
)
|
||||
.catch(err => {
|
||||
console.error({fetchError:err});
|
||||
fCallback && fCallback(
|
||||
fCallback?.(
|
||||
'TimeoutError' == err.reason ? 3 : (err.name == 'AbortError' ? 2 : 1),
|
||||
err
|
||||
);
|
||||
|
|
@ -191,7 +191,7 @@ export class AbstractFetchRemote
|
|||
if (trigger) {
|
||||
value = !!value;
|
||||
(isArray(trigger) ? trigger : [trigger]).forEach(fTrigger => {
|
||||
fTrigger && fTrigger(value);
|
||||
fTrigger?.(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -207,12 +207,12 @@ export class AbstractFetchRemote
|
|||
}
|
||||
/*
|
||||
let isCached = false, type = '';
|
||||
if (data && data.Time) {
|
||||
if (data?.Time) {
|
||||
isCached = pInt(data.Time) > microtime() - start;
|
||||
}
|
||||
// backward capability
|
||||
switch (true) {
|
||||
case 'success' === textStatus && data && data.Result && action === data.Action:
|
||||
case 'success' === textStatus && data?.Result && action === data.Action:
|
||||
type = AbstractFetchRemote.SUCCESS;
|
||||
break;
|
||||
case 'abort' === textStatus && (!data || !data.__aborted__):
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
|||
const
|
||||
sFolderFullName = pString(params.Folder),
|
||||
folder = getFolderFromCacheList(sFolderFullName),
|
||||
folderHash = (folder && folder.hash) || '';
|
||||
folderHash = folder?.hash || '';
|
||||
|
||||
params = Object.assign({
|
||||
Offset: 0,
|
||||
Limit: SettingsUserStore.messagesPerPage(),
|
||||
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(),
|
||||
Hash: folderHash + SettingsGet('AccountHash')
|
||||
}, params);
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ export class AbstractSettingsScreen extends AbstractScreen {
|
|||
settingsScreen
|
||||
);
|
||||
|
||||
settingsScreen.onBuild && settingsScreen.onBuild(viewModelDom);
|
||||
settingsScreen.onBuild?.(viewModelDom);
|
||||
} else {
|
||||
console.log('Cannot find sub settings view model position: SettingsSubScreen');
|
||||
}
|
||||
|
|
@ -67,10 +67,10 @@ export class AbstractSettingsScreen extends AbstractScreen {
|
|||
this.oCurrentSubScreen = settingsScreen;
|
||||
|
||||
// show
|
||||
settingsScreen.beforeShow && settingsScreen.beforeShow();
|
||||
settingsScreen.beforeShow?.();
|
||||
i18nToNodes(settingsScreen.viewModelDom);
|
||||
settingsScreen.viewModelDom.hidden = false;
|
||||
settingsScreen.onShow && settingsScreen.onShow();
|
||||
settingsScreen.onShow?.();
|
||||
|
||||
this.menu.forEach(item => {
|
||||
item.selected(
|
||||
|
|
@ -90,7 +90,7 @@ export class AbstractSettingsScreen extends AbstractScreen {
|
|||
onHide() {
|
||||
let subScreen = this.oCurrentSubScreen;
|
||||
if (subScreen) {
|
||||
subScreen.onHide && subScreen.onHide();
|
||||
subScreen.onHide?.();
|
||||
subScreen.viewModelDom.hidden = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ export class MailBoxUserScreen extends AbstractScreen {
|
|||
/* // Disabled in SystemDropDown.html
|
||||
const email = AccountUserStore.email();
|
||||
AccountUserStore.accounts.forEach(item =>
|
||||
item && email === item.email && item.count(e.detail)
|
||||
email === item?.email && item?.count(e.detail)
|
||||
);
|
||||
*/
|
||||
this.updateWindowTitle();
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ export class UserSettingsAccounts /*extends AbstractViewSettings*/ {
|
|||
}
|
||||
|
||||
editAccount(account) {
|
||||
if (account && account.isAdditional()) {
|
||||
if (account?.isAdditional()) {
|
||||
showScreenPopup(AccountPopupView, [account]);
|
||||
}
|
||||
}
|
||||
|
|
@ -48,7 +48,7 @@ export class UserSettingsAccounts /*extends AbstractViewSettings*/ {
|
|||
* @returns {void}
|
||||
*/
|
||||
deleteAccount(accountToRemove) {
|
||||
if (accountToRemove && accountToRemove.askDelete()) {
|
||||
if (accountToRemove?.askDelete()) {
|
||||
this.accountForDeletion(null);
|
||||
if (accountToRemove) {
|
||||
this.accounts.remove((account) => accountToRemove === account);
|
||||
|
|
@ -72,7 +72,7 @@ export class UserSettingsAccounts /*extends AbstractViewSettings*/ {
|
|||
* @returns {void}
|
||||
*/
|
||||
deleteIdentity(identityToRemove) {
|
||||
if (identityToRemove && identityToRemove.askDelete()) {
|
||||
if (identityToRemove?.askDelete()) {
|
||||
this.identityForDeletion(null);
|
||||
|
||||
if (identityToRemove) {
|
||||
|
|
|
|||
|
|
@ -50,6 +50,6 @@ export class UserSettingsFilters /*extends AbstractViewSettings*/ {
|
|||
}
|
||||
|
||||
onShow() {
|
||||
window.Sieve && window.Sieve.updateList();
|
||||
window.Sieve?.updateList();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export class UserSettingsThemes /*extends AbstractViewSettings*/ {
|
|||
.on('onComplete', (id, result, data) => {
|
||||
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.hash(data.Result.Hash);
|
||||
} else {
|
||||
|
|
@ -94,11 +94,7 @@ export class UserSettingsThemes /*extends AbstractViewSettings*/ {
|
|||
}
|
||||
}
|
||||
|
||||
if (!errorMsg && data.ErrorMessage) {
|
||||
errorMsg = data.ErrorMessage;
|
||||
}
|
||||
|
||||
themeBackground.error(errorMsg || i18n('SETTINGS_THEMES/ERROR_UNKNOWN'));
|
||||
themeBackground.error(errorMsg || data.ErrorMessage || i18n('SETTINGS_THEMES/ERROR_UNKNOWN'));
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ import {
|
|||
const
|
||||
// import { defaultOptionsAfterRender } from 'Common/Utils';
|
||||
defaultOptionsAfterRender = (domItem, item) =>
|
||||
domItem && item && undefined !== item.disabled
|
||||
&& domItem.classList.toggle('disabled', domItem.disabled = item.disabled),
|
||||
item && undefined !== item.disabled && domItem?.classList.toggle('disabled', domItem.disabled = item.disabled),
|
||||
|
||||
// import { folderListOptionsBuilder } from 'Common/Folders';
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ PackageAdminStore.fetch = () => {
|
|||
|
||||
const loading = {};
|
||||
PackageAdminStore.forEach(item => {
|
||||
if (item && item.loading()) {
|
||||
if (item?.loading()) {
|
||||
loading[item.file] = item;
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -21,6 +21,6 @@ AppUserStore.focusedState.subscribe(value => {
|
|||
ThemeStore.isMobile() && leftPanelDisabled('FolderList' !== value);
|
||||
}
|
||||
let dom = elementById('V-Mail'+name);
|
||||
dom && dom.classList.toggle('focused', name === value);
|
||||
dom?.classList.toggle('focused', name === value);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -33,12 +33,12 @@ ContactUserStore.sync = fResultFunc => {
|
|||
line = JSON.parse(line);
|
||||
if ('ContactsSync' === line.Action) {
|
||||
ContactUserStore.syncing(false);
|
||||
fResultFunc && fResultFunc(line.ErrorCode, line);
|
||||
fResultFunc?.(line.ErrorCode, line);
|
||||
}
|
||||
} catch (e) {
|
||||
ContactUserStore.syncing(false);
|
||||
console.error(e);
|
||||
fResultFunc && fResultFunc(Notification.UnknownError);
|
||||
fResultFunc?.(Notification.UnknownError);
|
||||
}
|
||||
}, 'ContactsSync');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,15 +80,9 @@ export const FolderUserStore = new class {
|
|||
|
||||
const
|
||||
subscribeRemoveSystemFolder = observable => {
|
||||
observable.subscribe(() => {
|
||||
const folder = getFolderFromCacheList(observable());
|
||||
folder && folder.type(FolderType.User);
|
||||
}, self, 'beforeChange');
|
||||
observable.subscribe(() => getFolderFromCacheList(observable())?.type(FolderType.User), self, 'beforeChange');
|
||||
},
|
||||
fSetSystemFolderType = type => value => {
|
||||
const folder = getFolderFromCacheList(value);
|
||||
folder && folder.type(type);
|
||||
};
|
||||
fSetSystemFolderType = type => value => getFolderFromCacheList(value)?.type(type);
|
||||
|
||||
subscribeRemoveSystemFolder(self.sentFolder);
|
||||
subscribeRemoveSystemFolder(self.draftsFolder);
|
||||
|
|
@ -134,8 +128,7 @@ export const FolderUserStore = new class {
|
|||
fSearchFunction = (list) => {
|
||||
list.forEach(folder => {
|
||||
if (
|
||||
folder &&
|
||||
folder.selectable() &&
|
||||
folder?.selectable() &&
|
||||
folder.exists &&
|
||||
timeout > folder.expires &&
|
||||
(folder.isSystemFolder() || (folder.isSubscribed() && (folder.checkable() || !bDisplaySpecSetting)))
|
||||
|
|
@ -143,7 +136,7 @@ export const FolderUserStore = new class {
|
|||
timeouts.push([folder.expires, folder.fullName]);
|
||||
}
|
||||
|
||||
if (folder && folder.subFolders.length) {
|
||||
if (folder?.subFolders.length) {
|
||||
fSearchFunction(folder.subFolders());
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export const GnuPGUserStore = new class {
|
|||
this.privateKeys([]);
|
||||
Remote.request('GnupgGetKeys',
|
||||
(iError, oData) => {
|
||||
if (oData && oData.Result) {
|
||||
if (oData?.Result) {
|
||||
this.keyring = oData.Result;
|
||||
const initKey = (key, isPrivate) => {
|
||||
const aEmails = [];
|
||||
|
|
@ -73,7 +73,7 @@ export const GnuPGUserStore = new class {
|
|||
key.view = () => {
|
||||
const fetch = pass => Remote.request('GnupgExportKey',
|
||||
(iError, oData) => {
|
||||
if (oData && oData.Result) {
|
||||
if (oData?.Result) {
|
||||
key.armor = oData.Result;
|
||||
showScreenPopup(OpenPgpKeyPopupView, [key]);
|
||||
}
|
||||
|
|
@ -111,10 +111,10 @@ export const GnuPGUserStore = new class {
|
|||
importKey(key, callback) {
|
||||
Remote.request('GnupgImportKey',
|
||||
(iError, oData) => {
|
||||
if (oData && oData.Result/* && (oData.Result.imported || oData.Result.secretimported)*/) {
|
||||
if (oData?.Result/* && (oData.Result.imported || oData.Result.secretimported)*/) {
|
||||
this.loadKeyrings();
|
||||
}
|
||||
callback && callback(iError, oData);
|
||||
callback?.(iError, oData);
|
||||
}, {
|
||||
Key: key
|
||||
}
|
||||
|
|
@ -131,10 +131,10 @@ export const GnuPGUserStore = new class {
|
|||
storeKeyPair(keyPair, callback) {
|
||||
Remote.request('PgpStoreKeyPair',
|
||||
(iError, oData) => {
|
||||
if (oData && oData.Result) {
|
||||
if (oData?.Result) {
|
||||
// this.gnupgKeyring = oData.Result;
|
||||
}
|
||||
callback && callback(iError, oData);
|
||||
callback?.(iError, oData);
|
||||
}, keyPair
|
||||
);
|
||||
}
|
||||
|
|
@ -187,7 +187,7 @@ export const GnuPGUserStore = new class {
|
|||
}
|
||||
if (null !== params.Passphrase) {
|
||||
const result = await Remote.post('GnupgDecrypt', null, params);
|
||||
if (result && result.Result) {
|
||||
if (result?.Result) {
|
||||
return result.Result;
|
||||
}
|
||||
}
|
||||
|
|
@ -208,7 +208,7 @@ export const GnuPGUserStore = new class {
|
|||
data.SigPart = data.SigPart.body;
|
||||
}
|
||||
let response = await Remote.post('MessagePgpVerify', null, data);
|
||||
if (response && response.Result) {
|
||||
if (response?.Result) {
|
||||
return {
|
||||
fingerprint: response.Result.fingerprint,
|
||||
success: 0 == response.Result.status // GOODSIG
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export const MessageUserStore = new class {
|
|||
|
||||
purgeMessageBodyCache() {
|
||||
const messagesDom = this.bodiesDom(),
|
||||
children = messagesDom && messagesDom.children;
|
||||
children = messagesDom?.children;
|
||||
if (children) {
|
||||
while (15 < children.length) {
|
||||
children[0].remove();
|
||||
|
|
|
|||
|
|
@ -270,8 +270,7 @@ MessagelistUserStore.setAction = (sFolderFullName, iSetAction, messages) => {
|
|||
|
||||
let folder,
|
||||
alreadyUnread = 0,
|
||||
rootUids = messages.map(oMessage => oMessage && oMessage.uid ? oMessage.uid : null)
|
||||
.validUnique(),
|
||||
rootUids = messages.map(oMessage => oMessage?.uid).validUnique(),
|
||||
length = rootUids.length;
|
||||
|
||||
if (sFolderFullName && length) {
|
||||
|
|
@ -333,7 +332,7 @@ MessagelistUserStore.removeMessagesFromList = (
|
|||
? messageList.filter(item => item && uidForRemove.includes(pInt(item.uid)))
|
||||
: [];
|
||||
|
||||
messages.forEach(item => item && item.isUnseen() && ++unseenCount);
|
||||
messages.forEach(item => item?.isUnseen() && ++unseenCount);
|
||||
|
||||
if (fromFolder) {
|
||||
fromFolder.hash = '';
|
||||
|
|
@ -387,7 +386,7 @@ MessagelistUserStore.removeMessagesFromList = (
|
|||
if (MessagelistUserStore.threadUid()) {
|
||||
if (
|
||||
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());
|
||||
let setHash;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { fireEvent } from 'Common/Globals';
|
|||
* Might not work due to the new ServiceWorkerRegistration.showNotification
|
||||
*/
|
||||
const HTML5Notification = window.Notification,
|
||||
HTML5NotificationStatus = () => (HTML5Notification && HTML5Notification.permission) || 'denied',
|
||||
HTML5NotificationStatus = () => HTML5Notification?.permission || 'denied',
|
||||
NotificationsDenied = () => 'denied' === HTML5NotificationStatus(),
|
||||
NotificationsGranted = () => 'granted' === HTML5NotificationStatus(),
|
||||
dispatchMessage = data => {
|
||||
|
|
@ -26,7 +26,7 @@ if (WorkerNotifications && ServiceWorkerRegistration && ServiceWorkerRegistratio
|
|||
/* Listen for close requests from the ServiceWorker */
|
||||
WorkerNotifications.addEventListener('message', event => {
|
||||
const obj = JSON.parse(event.data);
|
||||
obj && 'notificationclick' === obj.action && dispatchMessage(obj.data);
|
||||
'notificationclick' === obj?.action && dispatchMessage(obj.data);
|
||||
});
|
||||
} else {
|
||||
WorkerNotifications = null;
|
||||
|
|
@ -60,7 +60,7 @@ export const NotificationUserStore = new class {
|
|||
icon: imageSrc || Links.staticLink('css/images/icon-message-notification.png'),
|
||||
data: messageData
|
||||
};
|
||||
if (messageData && messageData.Uid) {
|
||||
if (messageData?.Uid) {
|
||||
options.tag = messageData.Uid;
|
||||
}
|
||||
if (WorkerNotifications) {
|
||||
|
|
@ -83,7 +83,7 @@ export const NotificationUserStore = new class {
|
|||
.catch(e => console.error(e));
|
||||
} else {
|
||||
const notification = new HTML5Notification(title, options);
|
||||
notification.show && notification.show();
|
||||
notification.show?.();
|
||||
notification.onclick = messageData ? () => dispatchMessage(messageData) : null;
|
||||
setTimeout(() => notification.close(), 7000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -196,7 +196,7 @@ export const OpenPGPUserStore = new class {
|
|||
const publicKey = findOpenPGPKey(this.publicKeys, sender/*, sign*/);
|
||||
return await openpgp.decrypt({
|
||||
message,
|
||||
verificationKeys: publicKey && publicKey.key,
|
||||
verificationKeys: publicKey?.key,
|
||||
// expectSigned: true,
|
||||
// signature: '', // Detached signature
|
||||
decryptionKeys: decryptedKey
|
||||
|
|
|
|||
|
|
@ -169,7 +169,7 @@ export const
|
|||
}
|
||||
);
|
||||
if (result) {
|
||||
if (result.error && result.error.message) {
|
||||
if (result.error?.message) {
|
||||
if ('PWD_DIALOG_CANCEL' !== result.error.code) {
|
||||
alert(result.error.code + ': ' + result.error.message);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ export class AccountPopupView extends AbstractViewPopup {
|
|||
this.submitRequest(false);
|
||||
if (iError) {
|
||||
this.submitError(getNotification(iError));
|
||||
this.submitErrorAdditional((data && data.ErrorMessageAdditional) || '');
|
||||
this.submitErrorAdditional(data?.ErrorMessageAdditional);
|
||||
} else {
|
||||
rl.app.accountsAndIdentities();
|
||||
this.close();
|
||||
|
|
@ -54,7 +54,7 @@ export class AccountPopupView extends AbstractViewPopup {
|
|||
}
|
||||
|
||||
onShow(account) {
|
||||
if (account && account.isAdditional()) {
|
||||
if (account?.isAdditional()) {
|
||||
this.isNew(false);
|
||||
this.email(account.email);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -213,8 +213,8 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
super('Compose');
|
||||
|
||||
const fEmailOutInHelper = (context, identity, name, isIn) => {
|
||||
if (identity && context && identity[name]() && (isIn ? true : context[name]())) {
|
||||
const identityEmail = identity[name]();
|
||||
const identityEmail = context && identity?.[name]();
|
||||
if (identityEmail && (isIn ? true : context[name]())) {
|
||||
let list = context[name]().trim().split(',');
|
||||
|
||||
list = list.filter(email => {
|
||||
|
|
@ -222,9 +222,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
return email && identityEmail.trim() !== email;
|
||||
});
|
||||
|
||||
if (isIn) {
|
||||
list.push(identityEmail);
|
||||
}
|
||||
isIn && list.push(identityEmail);
|
||||
|
||||
context[name](list.join(','));
|
||||
}
|
||||
|
|
@ -355,7 +353,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
},
|
||||
|
||||
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,
|
||||
attachmentsInErrorCount: () => this.attachmentsInError.length,
|
||||
|
|
@ -511,7 +509,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
alternative.children.push(data);
|
||||
data = alternative;
|
||||
}
|
||||
if (sign && !draft && sign[1]) {
|
||||
if (!draft && sign?.[1]) {
|
||||
if ('openpgp' == sign[0]) {
|
||||
// Doesn't sign attachments
|
||||
params.Html = params.Text = '';
|
||||
|
|
@ -611,7 +609,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
this.savedErrorDesc(i18n('COMPOSE/SAVED_ERROR_ON_SEND').trim());
|
||||
} else {
|
||||
this.sendError(true);
|
||||
this.sendErrorDesc(getNotification(iError, data && data.ErrorMessage)
|
||||
this.sendErrorDesc(getNotification(iError, data?.ErrorMessage)
|
||||
|| getNotification(Notification.CantSendMessage));
|
||||
}
|
||||
} else {
|
||||
|
|
@ -762,7 +760,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
(iError, data) => {
|
||||
if (!iError && isArray(data.Result)) {
|
||||
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)
|
||||
);
|
||||
} else if (Notification.RequestAborted !== iError) {
|
||||
|
|
@ -777,7 +775,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
}
|
||||
|
||||
selectIdentity(identity) {
|
||||
identity = identity && identity.item;
|
||||
identity = identity?.item;
|
||||
if (identity) {
|
||||
this.currentIdentity(identity);
|
||||
this.setSignatureFromIdentity(identity);
|
||||
|
|
@ -1153,7 +1151,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
});
|
||||
} else {
|
||||
this.attachments.forEach(attachment => {
|
||||
if (attachment && attachment.fromMessage) {
|
||||
if (attachment?.fromMessage) {
|
||||
attachment
|
||||
.waiting(false)
|
||||
.uploading(false)
|
||||
|
|
@ -1180,7 +1178,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
if (!this.to()) {
|
||||
this.to.focused(true);
|
||||
} else if (!this.to.focused()) {
|
||||
this.oEditor && this.oEditor.focus();
|
||||
this.oEditor?.focus();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
|
@ -1266,7 +1264,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
})
|
||||
.on('onComplete', (id, result, data) => {
|
||||
const attachment = this.getAttachmentById(id),
|
||||
response = (data && data.Result) || {},
|
||||
response = data?.Result || {},
|
||||
errorCode = response.ErrorCode,
|
||||
attachmentJson = result && response.Attachment;
|
||||
|
||||
|
|
@ -1354,7 +1352,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
prepareAttachmentsForSendOrSave() {
|
||||
const result = {};
|
||||
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];
|
||||
}
|
||||
});
|
||||
|
|
@ -1381,7 +1379,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
oJua || attachment.waiting(false).uploading(true);
|
||||
attachment.cancel = () => {
|
||||
this.attachments.remove(attachment);
|
||||
oJua && oJua.cancel(attachment.id);
|
||||
oJua?.cancel(attachment.id);
|
||||
};
|
||||
this.attachments.push(attachment);
|
||||
view && this.attachmentsArea();
|
||||
|
|
@ -1435,7 +1433,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
isEmptyForm(includeAttachmentInProgress = true) {
|
||||
const withoutAttachment = includeAttachmentInProgress
|
||||
? !this.attachments.length
|
||||
: !this.attachments.some(item => item && item.complete());
|
||||
: !this.attachments.some(item => item?.complete());
|
||||
|
||||
return (
|
||||
!this.to.length &&
|
||||
|
|
@ -1491,7 +1489,7 @@ export class ComposePopupView extends AbstractViewPopup {
|
|||
this.sending(false);
|
||||
this.saving(false);
|
||||
|
||||
this.oEditor && this.oEditor.clear();
|
||||
this.oEditor?.clear();
|
||||
|
||||
this.dropMailvelope();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
contactHasValidName: () => !!this.viewProperties.find(prop => propertyIsName(prop) && prop.isValid()),
|
||||
|
||||
contactsCheckedOrSelected: () => {
|
||||
const checked = ContactUserStore.filter(item => item.checked && item.checked()),
|
||||
const checked = ContactUserStore.filter(item => item.checked?.()),
|
||||
selected = this.currentContact();
|
||||
|
||||
return selected
|
||||
|
|
@ -120,7 +120,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
|
||||
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());
|
||||
|
|
@ -164,7 +164,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
const data = oItem.getNameAndEmailHelper(),
|
||||
email = data ? new EmailModel(data[0], data[1]) : null;
|
||||
|
||||
if (email && email.validate()) {
|
||||
if (email?.validate()) {
|
||||
return email;
|
||||
}
|
||||
}
|
||||
|
|
@ -344,7 +344,7 @@ export class ContactsPopupView extends AbstractViewPopup {
|
|||
if (this.contactsCheckedOrSelected().length) {
|
||||
Remote.request('ContactsDelete',
|
||||
(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);
|
||||
} else {
|
||||
setTimeout(() => this.reloadContactList(this.bDropPageAfterDelete), 500);
|
||||
|
|
|
|||
|
|
@ -248,7 +248,7 @@ export class DomainPopupView extends AbstractViewPopup {
|
|||
if (oDomain) {
|
||||
this.enableSmartPorts(false);
|
||||
this.edit(true);
|
||||
forEachObjectEntry(oDomain, (key, value) => this[key] && this[key](value));
|
||||
forEachObjectEntry(oDomain, (key, value) => this[key]?.(value));
|
||||
this.enableSmartPorts(true);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,9 +63,7 @@ export class IdentityPopupView extends AbstractViewPopup {
|
|||
|
||||
submitForm() {
|
||||
if (!this.submitRequest()) {
|
||||
if (this.signature && this.signature.__fetchEditorValue) {
|
||||
this.signature.__fetchEditorValue();
|
||||
}
|
||||
this.signature?.__fetchEditorValue?.();
|
||||
|
||||
if (!this.emailHasError()) {
|
||||
this.emailHasError(!this.email().trim());
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export class LanguagesPopupView extends AbstractViewPopup {
|
|||
}
|
||||
|
||||
changeLanguage(lang) {
|
||||
this.fLang && this.fLang(lang);
|
||||
this.fLang?.(lang);
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ export class OpenPgpGeneratePopupView extends AbstractViewPopup {
|
|||
|
||||
showError(e) {
|
||||
console.log(e);
|
||||
if (e && e.message) {
|
||||
if (e?.message) {
|
||||
this.submitError(e.message);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,9 +114,9 @@ export class LoginUserView extends AbstractViewLogin {
|
|||
if (Notification.InvalidInputArgument == iError) {
|
||||
iError = Notification.AuthError;
|
||||
}
|
||||
this.submitError(getNotification(iError, (oData ? oData.ErrorMessage : ''),
|
||||
this.submitError(getNotification(iError, oData?.ErrorMessage,
|
||||
Notification.UnknownNotification));
|
||||
this.submitErrorAdditional((oData && oData.ErrorMessageAdditional) || '');
|
||||
this.submitErrorAdditional(oData?.ErrorMessageAdditional);
|
||||
} else {
|
||||
rl.setData(oData.Result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ export class MailFolderList extends AbstractViewLeft {
|
|||
}
|
||||
|
||||
el = eqs(event, 'a');
|
||||
if (el && el.matches('.selectable')) {
|
||||
if (el?.matches('.selectable')) {
|
||||
event.preventDefault();
|
||||
const folder = ko.dataFor(el);
|
||||
if (folder) {
|
||||
|
|
@ -170,10 +170,10 @@ export class MailFolderList extends AbstractViewLeft {
|
|||
|
||||
AppUserStore.focusedState.subscribe(value => {
|
||||
let el = qs('li a.focused');
|
||||
el && el.classList.remove('focused');
|
||||
el?.classList.remove('focused');
|
||||
if (Scope.FolderList === value) {
|
||||
el = qs('li a.selected');
|
||||
el && el.classList.add('focused');
|
||||
el?.classList.add('focused');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -210,7 +210,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
const sFolder = e.detail.Folder, iUid = e.detail.Uid;
|
||||
|
||||
const message = MessagelistUserStore.find(
|
||||
item => item && sFolder === item.folder && iUid == item.uid
|
||||
item => sFolder === item?.folder && iUid == item?.uid
|
||||
);
|
||||
|
||||
if ('INBOX' === sFolder) {
|
||||
|
|
@ -326,7 +326,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
|
||||
moveNewCommand(vm, event) {
|
||||
if (this.newMoveToFolder && this.mobileCheckedStateShow()) {
|
||||
if (vm && event && event.preventDefault) {
|
||||
if (vm && event?.preventDefault) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
|
@ -428,7 +428,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
|
||||
getDragData(event) {
|
||||
const item = ko.dataFor(doc.elementFromPoint(event.clientX, event.clientY));
|
||||
item && item.checked && item.checked(true);
|
||||
item?.checked?.(true);
|
||||
const uids = MessagelistUserStore.listCheckedOrSelectedUidsWithSubMails();
|
||||
item && !uids.includes(item.uid) && uids.push(item.uid);
|
||||
return uids.length ? {
|
||||
|
|
@ -571,7 +571,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
}
|
||||
|
||||
gotoThread(message) {
|
||||
if (message && 0 < message.threadsLen()) {
|
||||
if (0 < message?.threadsLen()) {
|
||||
MessagelistUserStore.pageBeforeThread(MessagelistUserStore.page());
|
||||
|
||||
hasher.setHash(
|
||||
|
|
@ -718,7 +718,7 @@ export class MailMessageList extends AbstractViewRight {
|
|||
|
||||
registerShortcut('t', '', [Scope.MessageList], () => {
|
||||
let message = MessagelistUserStore.selectedMessage() || MessagelistUserStore.focusedMessage();
|
||||
if (message && 0 < message.threadsLen()) {
|
||||
if (0 < message?.threadsLen()) {
|
||||
this.gotoThread(message);
|
||||
}
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -134,8 +134,8 @@ export class MailMessageView extends AbstractViewRight {
|
|||
allowAttachmentControls: () => arrayLength(attachmentsActions) && SettingsCapa('AttachmentsActions'),
|
||||
|
||||
downloadAsZipAllowed: () => this.attachmentsActions.includes('zip')
|
||||
&& (currentMessage() ? currentMessage().attachments : [])
|
||||
.filter(item => item && !item.isLinked() && item.checked() && item.download)
|
||||
&& (currentMessage()?.attachments || [])
|
||||
.filter(item => item?.download && !item?.isLinked() && item?.checked())
|
||||
.length,
|
||||
|
||||
tagsAllowed: () => FolderUserStore.currentFolder() ? FolderUserStore.currentFolder().tagsAllowed() : false,
|
||||
|
|
@ -286,7 +286,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
el = eqs(event, '.attachmentsPlace .attachmentItem .attachmentNameParent');
|
||||
if (el) {
|
||||
const attachment = ko.dataFor(el);
|
||||
if (attachment && attachment.linkDownload()) {
|
||||
if (attachment?.linkDownload()) {
|
||||
if ('message/rfc822' == attachment.mimeType) {
|
||||
// TODO
|
||||
rl.fetch(attachment.linkDownload()).then(response => {
|
||||
|
|
@ -393,7 +393,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
// toggle message blockquotes
|
||||
registerShortcut('b', '', [Scope.MessageList, Scope.MessageView], () => {
|
||||
const message = currentMessage();
|
||||
if (message && message.body) {
|
||||
if (message?.body) {
|
||||
message.body.querySelectorAll('.rlBlockquoteSwitcher').forEach(node => node.click());
|
||||
return false;
|
||||
}
|
||||
|
|
@ -411,7 +411,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
|
||||
// print
|
||||
addShortcut('p,printscreen', 'meta', [Scope.MessageView, Scope.MessageList], () => {
|
||||
currentMessage() && currentMessage().printMessage();
|
||||
currentMessage()?.printMessage();
|
||||
return false;
|
||||
});
|
||||
|
||||
|
|
@ -510,7 +510,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
|
||||
downloadAsZip() {
|
||||
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);
|
||||
if (hashes.length) {
|
||||
Remote.post('AttachmentsActions', this.downloadAsZipLoading, {
|
||||
|
|
@ -518,7 +518,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
Hashes: hashes
|
||||
})
|
||||
.then(result => {
|
||||
let hash = result && result.Result && result.Result.FileHash;
|
||||
let hash = result?.Result?.FileHash;
|
||||
if (hash) {
|
||||
download(attachmentDownload(hash), hash+'.zip');
|
||||
} else {
|
||||
|
|
@ -577,7 +577,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
if (result.data) {
|
||||
MimeToMessage(result.data, oMessage);
|
||||
oMessage.html() ? oMessage.viewHtml() : oMessage.viewPlain();
|
||||
if (result.signatures && result.signatures.length) {
|
||||
if (result.signatures?.length) {
|
||||
oMessage.pgpSigned(true);
|
||||
oMessage.pgpVerified({
|
||||
signatures: result.signatures,
|
||||
|
|
@ -596,7 +596,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
oMessage.pgpVerified(result);
|
||||
}
|
||||
/*
|
||||
if (result && result.success) {
|
||||
if (result?.success) {
|
||||
i18n('OPENPGP/GOOD_SIGNATURE', {
|
||||
USER: validKey.user + ' (' + validKey.id + ')'
|
||||
});
|
||||
|
|
@ -604,7 +604,7 @@ export class MailMessageView extends AbstractViewRight {
|
|||
} else {
|
||||
const keyIds = arrayLength(signingKeyIds) ? signingKeyIds : null,
|
||||
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', {
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export class SystemDropDownUserView extends AbstractViewRight {
|
|||
}
|
||||
|
||||
accountClick(account, event) {
|
||||
let email = account && account.email;
|
||||
let email = account?.email;
|
||||
if (email && 0 === event.button && AccountUserStore.email() != email) {
|
||||
AccountUserStore.loading(true);
|
||||
event.preventDefault();
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@
|
|||
htmlDrag = b => doc.documentElement.classList.toggle('firefox-drag', b),
|
||||
|
||||
setDragImage = (src, xOffset, yOffset) => {
|
||||
img && img.remove();
|
||||
img?.remove();
|
||||
if (src) {
|
||||
// create drag image from custom element or drag source
|
||||
img = src.cloneNode(true);
|
||||
|
|
@ -85,7 +85,7 @@
|
|||
if (dragSource) {
|
||||
clearInterval(holdInterval);
|
||||
// dispose of drag image element
|
||||
img && img.remove();
|
||||
img?.remove();
|
||||
isDragging && dispatchEvent(lastTouch, 'dragend', dragSource);
|
||||
img = dragSource = lastTouch = lastTarget = dataTransfer = holdInterval = null;
|
||||
isDragging = allowDrop = false;
|
||||
|
|
|
|||
|
|
@ -64,9 +64,8 @@ const
|
|||
keydown = event => {
|
||||
let key = (event.key || '').toLowerCase().replace(' ','space'),
|
||||
modifiers = ['alt','ctrl','meta','shift'].filter(v => event[v+'Key']).join('+');
|
||||
scope[key] && scope[key][modifiers] && scope[key][modifiers].forEach(cmd => exec(event, cmd));
|
||||
!event.defaultPrevented && _scope !== 'all' && _scopes.all[key] && _scopes.all[key][modifiers]
|
||||
&& _scopes.all[key][modifiers].forEach(cmd => exec(event, cmd));
|
||||
scope[key]?.[modifiers]?.forEach(cmd => exec(event, cmd));
|
||||
!event.defaultPrevented && _scope !== 'all' && _scopes.all[key]?.[modifiers]?.forEach(cmd => exec(event, cmd));
|
||||
};
|
||||
|
||||
win.shortcuts = shortcuts;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue