mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-29 12:09:20 +03:00
Merge branch 'master' into plugin-hooks
# Conflicts: # dev/View/User/Login.js
This commit is contained in:
commit
2ab42b1f03
547 changed files with 29045 additions and 52993 deletions
255
dev/App/User.js
255
dev/App/User.js
|
|
@ -79,7 +79,6 @@ import { AbstractApp } from 'App/Abstract';
|
|||
import { ComposePopupView } from 'View/Popup/Compose';
|
||||
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
|
||||
import { AskPopupView } from 'View/Popup/Ask';
|
||||
import { TwoFactorConfigurationPopupView } from 'View/Popup/TwoFactorConfiguration';
|
||||
|
||||
// Every 5 minutes
|
||||
const refreshFolders = 300000;
|
||||
|
|
@ -187,16 +186,18 @@ class AppUser extends AbstractApp {
|
|||
}
|
||||
MessageUserStore.listLoading(false);
|
||||
},
|
||||
FolderUserStore.currentFolderFullNameRaw(),
|
||||
iOffset,
|
||||
SettingsUserStore.messagesPerPage(),
|
||||
MessageUserStore.listSearch(),
|
||||
MessageUserStore.listThreadUid()
|
||||
{
|
||||
Folder: FolderUserStore.currentFolderFullNameRaw(),
|
||||
Offset: iOffset,
|
||||
Limit: SettingsUserStore.messagesPerPage(),
|
||||
Search: MessageUserStore.listSearch(),
|
||||
ThreadUid: MessageUserStore.listThreadUid()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
recacheInboxMessageList() {
|
||||
Remote.messageList(()=>{}, getFolderInboxName(), 0, SettingsUserStore.messagesPerPage(), '', '', true);
|
||||
Remote.messageList(null, {Folder: getFolderInboxName()}, true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -910,136 +911,124 @@ class AppUser extends AbstractApp {
|
|||
|
||||
rl.setWindowTitle();
|
||||
if (SettingsGet('Auth')) {
|
||||
if (
|
||||
Settings.capa(Capa.TwoFactor) &&
|
||||
Settings.capa(Capa.TwoFactorForce) &&
|
||||
SettingsGet('RequireTwoFactor')
|
||||
) {
|
||||
this.bootend();
|
||||
showScreenPopup(TwoFactorConfigurationPopupView, [true]);
|
||||
} else {
|
||||
rl.setWindowTitle(i18n('GLOBAL/LOADING'));
|
||||
rl.setWindowTitle(i18n('GLOBAL/LOADING'));
|
||||
|
||||
// require.ensure([], function() { // require code splitting
|
||||
this.foldersReload(value => {
|
||||
try {
|
||||
this.bootend();
|
||||
|
||||
this.foldersReload(value => {
|
||||
try {
|
||||
this.bootend();
|
||||
|
||||
if (value) {
|
||||
if (startupUrl) {
|
||||
rl.route.setHash(root(startupUrl), true);
|
||||
}
|
||||
|
||||
if (window.crypto && crypto.getRandomValues && Settings.capa(Capa.OpenPGP)) {
|
||||
const openpgpCallback = () => {
|
||||
if (!window.openpgp) {
|
||||
return false;
|
||||
}
|
||||
PgpUserStore.openpgp = openpgp;
|
||||
|
||||
if (window.Worker) {
|
||||
try {
|
||||
PgpUserStore.openpgp.initWorker({ path: openPgpWorkerJs() });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
PgpUserStore.openpgpKeyring = new openpgp.Keyring();
|
||||
PgpUserStore.capaOpenPGP(true);
|
||||
|
||||
this.reloadOpenPgpKeys();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!openpgpCallback()) {
|
||||
const script = createElement('script', {src:openPgpJs()});
|
||||
script.onload = openpgpCallback;
|
||||
script.onerror = () => console.error(script.src);
|
||||
doc.head.append(script);
|
||||
}
|
||||
} else {
|
||||
PgpUserStore.capaOpenPGP(false);
|
||||
}
|
||||
|
||||
startScreens([
|
||||
MailBoxUserScreen,
|
||||
Settings.capa(Capa.Settings) ? SettingsUserScreen : null
|
||||
// false ? AboutUserScreen : null
|
||||
]);
|
||||
|
||||
setInterval(() => {
|
||||
const cF = FolderUserStore.currentFolderFullNameRaw(),
|
||||
iF = getFolderInboxName();
|
||||
this.folderInformation(iF);
|
||||
if (iF !== cF) {
|
||||
this.folderInformation(cF);
|
||||
}
|
||||
this.folderInformationMultiply();
|
||||
}, refreshFolders);
|
||||
|
||||
// Every 15 minutes
|
||||
setInterval(this.quota, 900000);
|
||||
// Every 20 minutes
|
||||
setInterval(this.foldersReload, 1200000);
|
||||
|
||||
setTimeout(this.contactsSync, 10000);
|
||||
contactsSyncInterval = 5 <= contactsSyncInterval ? contactsSyncInterval : 20;
|
||||
contactsSyncInterval = 320 >= contactsSyncInterval ? contactsSyncInterval : 320;
|
||||
setInterval(this.contactsSync, contactsSyncInterval * 60000 + 5000);
|
||||
|
||||
this.accountsAndIdentities(true);
|
||||
|
||||
setTimeout(() => {
|
||||
const cF = FolderUserStore.currentFolderFullNameRaw();
|
||||
if (getFolderInboxName() !== cF) {
|
||||
this.folderInformation(cF);
|
||||
}
|
||||
this.folderInformationMultiply(true);
|
||||
}, 1000);
|
||||
|
||||
setTimeout(this.quota, 5000);
|
||||
setTimeout(() => Remote.appDelayStart(()=>{}), 35000);
|
||||
|
||||
// When auto-login is active
|
||||
if (
|
||||
!!SettingsGet('AccountSignMe') &&
|
||||
navigator.registerProtocolHandler &&
|
||||
Settings.capa(Capa.Composer)
|
||||
) {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
navigator.registerProtocolHandler(
|
||||
'mailto',
|
||||
location.protocol + '//' + location.host + location.pathname + '?mailto&to=%s',
|
||||
(SettingsGet('Title') || 'SnappyMail')
|
||||
);
|
||||
} catch (e) {} // eslint-disable-line no-empty
|
||||
|
||||
if (SettingsGet('MailToEmail')) {
|
||||
mailToHelper(SettingsGet('MailToEmail'));
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
['touchstart','mousedown','mousemove','keydown'].forEach(
|
||||
t => doc.addEventListener(t, SettingsUserStore.delayLogout, {passive:true})
|
||||
);
|
||||
SettingsUserStore.delayLogout();
|
||||
|
||||
setTimeout(() => this.initVerticalLayoutResizer(), 1);
|
||||
} else {
|
||||
this.logout();
|
||||
if (value) {
|
||||
if (startupUrl) {
|
||||
rl.route.setHash(root(startupUrl), true);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
// }); // require code splitting
|
||||
}
|
||||
if (window.crypto && crypto.getRandomValues && Settings.capa(Capa.OpenPGP)) {
|
||||
const openpgpCallback = () => {
|
||||
if (!window.openpgp) {
|
||||
return false;
|
||||
}
|
||||
PgpUserStore.openpgp = openpgp;
|
||||
|
||||
if (window.Worker) {
|
||||
try {
|
||||
PgpUserStore.openpgp.initWorker({ path: openPgpWorkerJs() });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
PgpUserStore.openpgpKeyring = new openpgp.Keyring();
|
||||
PgpUserStore.capaOpenPGP(true);
|
||||
|
||||
this.reloadOpenPgpKeys();
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
if (!openpgpCallback()) {
|
||||
const script = createElement('script', {src:openPgpJs()});
|
||||
script.onload = openpgpCallback;
|
||||
script.onerror = () => console.error(script.src);
|
||||
doc.head.append(script);
|
||||
}
|
||||
} else {
|
||||
PgpUserStore.capaOpenPGP(false);
|
||||
}
|
||||
|
||||
startScreens([
|
||||
MailBoxUserScreen,
|
||||
Settings.capa(Capa.Settings) ? SettingsUserScreen : null
|
||||
// false ? AboutUserScreen : null
|
||||
]);
|
||||
|
||||
setInterval(() => {
|
||||
const cF = FolderUserStore.currentFolderFullNameRaw(),
|
||||
iF = getFolderInboxName();
|
||||
this.folderInformation(iF);
|
||||
if (iF !== cF) {
|
||||
this.folderInformation(cF);
|
||||
}
|
||||
this.folderInformationMultiply();
|
||||
}, refreshFolders);
|
||||
|
||||
// Every 15 minutes
|
||||
setInterval(this.quota, 900000);
|
||||
// Every 20 minutes
|
||||
setInterval(this.foldersReload, 1200000);
|
||||
|
||||
setTimeout(this.contactsSync, 10000);
|
||||
contactsSyncInterval = 5 <= contactsSyncInterval ? contactsSyncInterval : 20;
|
||||
contactsSyncInterval = 320 >= contactsSyncInterval ? contactsSyncInterval : 320;
|
||||
setInterval(this.contactsSync, contactsSyncInterval * 60000 + 5000);
|
||||
|
||||
this.accountsAndIdentities(true);
|
||||
|
||||
setTimeout(() => {
|
||||
const cF = FolderUserStore.currentFolderFullNameRaw();
|
||||
if (getFolderInboxName() !== cF) {
|
||||
this.folderInformation(cF);
|
||||
}
|
||||
this.folderInformationMultiply(true);
|
||||
}, 1000);
|
||||
|
||||
setTimeout(this.quota, 5000);
|
||||
setTimeout(() => Remote.appDelayStart(()=>{}), 35000);
|
||||
|
||||
// When auto-login is active
|
||||
if (
|
||||
!!SettingsGet('AccountSignMe') &&
|
||||
navigator.registerProtocolHandler &&
|
||||
Settings.capa(Capa.Composer)
|
||||
) {
|
||||
setTimeout(() => {
|
||||
try {
|
||||
navigator.registerProtocolHandler(
|
||||
'mailto',
|
||||
location.protocol + '//' + location.host + location.pathname + '?mailto&to=%s',
|
||||
(SettingsGet('Title') || 'SnappyMail')
|
||||
);
|
||||
} catch (e) {} // eslint-disable-line no-empty
|
||||
|
||||
if (SettingsGet('MailToEmail')) {
|
||||
mailToHelper(SettingsGet('MailToEmail'));
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
['touchstart','mousedown','mousemove','keydown'].forEach(
|
||||
t => doc.addEventListener(t, SettingsUserStore.delayLogout, {passive:true})
|
||||
);
|
||||
SettingsUserStore.delayLogout();
|
||||
|
||||
setTimeout(() => this.initVerticalLayoutResizer(), 1);
|
||||
} else {
|
||||
this.logout();
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
this.bootend();
|
||||
startScreens([LoginUserScreen]);
|
||||
|
|
|
|||
|
|
@ -4,8 +4,6 @@
|
|||
* @enum {string}
|
||||
*/
|
||||
export const Capa = {
|
||||
TwoFactor: 'TWO_FACTOR',
|
||||
TwoFactorForce: 'TWO_FACTOR_FORCE',
|
||||
OpenPGP: 'OPEN_PGP',
|
||||
Prefetch: 'PREFETCH',
|
||||
Composer: 'COMPOSER',
|
||||
|
|
@ -86,9 +84,6 @@ export const Notification = {
|
|||
DomainNotAllowed: 109,
|
||||
AccountNotAllowed: 110,
|
||||
|
||||
AccountTwoFactorAuthRequired: 120,
|
||||
AccountTwoFactorAuthError: 121,
|
||||
|
||||
ContactsSyncError: 140,
|
||||
|
||||
CantGetMessageList: 201,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,22 @@ export const FolderType = {
|
|||
User: 99
|
||||
};
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
export const FolderSortMode = {
|
||||
DateDesc: '', // default 'REVERSE DATE'
|
||||
DateAsc: 'DATE',
|
||||
FromDesc: 'REVERSE FROM',
|
||||
FromAsc: 'FROM',
|
||||
SizeDesc: 'REVERSE SIZE',
|
||||
SizeAsc: 'SIZE',
|
||||
SubjectDesc: 'REVERSE SUBJECT',
|
||||
SubjectAsc: 'SUBJECT'
|
||||
// ToDesc: 'REVERSE TO',
|
||||
// ToAsc: 'TO',
|
||||
};
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,113 +11,109 @@ const
|
|||
sizes = ['B', 'KiB', 'MiB', 'GiB', 'TiB'],
|
||||
|
||||
exts = {
|
||||
eml: 'message/rfc822',
|
||||
mime: 'message/rfc822',
|
||||
rtx: 'text/richtext',
|
||||
vcard: 'text/vcard',
|
||||
vcf: 'text/vcard',
|
||||
htm: 'text/html',
|
||||
html: 'text/html',
|
||||
csv: 'text/csv',
|
||||
ics: 'text/calendar',
|
||||
ifb: 'text/calendar',
|
||||
xml: 'text/xml',
|
||||
json: app+'json',
|
||||
p10: app+'pkcs10',
|
||||
p7c: app+'pkcs7-mime',
|
||||
p7m: app+'pkcs7-mime',
|
||||
p7s: app+'pkcs7-signature',
|
||||
torrent: app+'x-bittorrent',
|
||||
eml: 'message/rfc822',
|
||||
mime: 'message/rfc822',
|
||||
vcard: 'text/vcard',
|
||||
vcf: 'text/vcard',
|
||||
htm: 'text/html',
|
||||
html: 'text/html',
|
||||
csv: 'text/csv',
|
||||
ics: 'text/calendar',
|
||||
xml: 'text/xml',
|
||||
json: app+'json',
|
||||
asc: app+'pgp-signature',
|
||||
p10: app+'pkcs10',
|
||||
p7c: app+'pkcs7-mime',
|
||||
p7m: app+'pkcs7-mime',
|
||||
p7s: app+'pkcs7-signature',
|
||||
torrent: app+'x-bittorrent',
|
||||
|
||||
// scripts
|
||||
js: app+'javascript',
|
||||
pl: 'text/perl',
|
||||
css: 'text/css',
|
||||
asp: 'text/asp',
|
||||
php: app+'x-httpd-php',
|
||||
phtml: app+'x-httpd-php',
|
||||
// scripts
|
||||
js: app+'javascript',
|
||||
pl: 'text/perl',
|
||||
css: 'text/css',
|
||||
asp: 'text/asp',
|
||||
php: app+'x-php',
|
||||
|
||||
// images
|
||||
jpg: 'image/jpeg',
|
||||
ico: 'image/x-icon',
|
||||
tif: 'image/tiff',
|
||||
svg: 'image/svg+xml',
|
||||
svgz: 'image/svg+xml',
|
||||
// images
|
||||
jpg: 'image/jpeg',
|
||||
ico: 'image/x-icon',
|
||||
tif: 'image/tiff',
|
||||
svg: 'image/svg+xml',
|
||||
svgz: 'image/svg+xml',
|
||||
|
||||
// archives
|
||||
zip: app+'zip',
|
||||
'7z': app+'x-7z-compressed',
|
||||
rar: app+'x-rar-compressed',
|
||||
cab: app+'vnd.ms-cab-compressed',
|
||||
gz: app+'x-gzip',
|
||||
tgz: app+'x-gzip',
|
||||
bz: app+'x-bzip',
|
||||
bz2: app+'x-bzip2',
|
||||
deb: app+'x-debian-package',
|
||||
// archives
|
||||
zip: app+'zip',
|
||||
'7z': app+'x-7z-compressed',
|
||||
rar: app+'x-rar-compressed',
|
||||
cab: app+'vnd.ms-cab-compressed',
|
||||
gz: app+'x-gzip',
|
||||
tgz: app+'x-gzip',
|
||||
bz: app+'x-bzip',
|
||||
bz2: app+'x-bzip2',
|
||||
deb: app+'x-debian-package',
|
||||
|
||||
// audio
|
||||
mp3: 'audio/mpeg',
|
||||
wav: 'audio/x-wav',
|
||||
mp4a: 'audio/mp4',
|
||||
weba: 'audio/webm',
|
||||
m3u: 'audio/x-mpegurl',
|
||||
// audio
|
||||
mp3: 'audio/mpeg',
|
||||
wav: 'audio/x-wav',
|
||||
mp4a: 'audio/mp4',
|
||||
weba: 'audio/webm',
|
||||
m3u: 'audio/x-mpegurl',
|
||||
|
||||
// video
|
||||
qt: 'video/quicktime',
|
||||
mov: 'video/quicktime',
|
||||
wmv: 'video/windows-media',
|
||||
avi: 'video/x-msvideo',
|
||||
'3gp': 'video/3gpp',
|
||||
'3g2': 'video/3gpp2',
|
||||
mp4v: 'video/mp4',
|
||||
mpg4: 'video/mp4',
|
||||
ogv: 'video/ogg',
|
||||
m4v: 'video/x-m4v',
|
||||
asf: 'video/x-ms-asf',
|
||||
asx: 'video/x-ms-asf',
|
||||
wm: 'video/x-ms-wm',
|
||||
wmx: 'video/x-ms-wmx',
|
||||
wvx: 'video/x-ms-wvx',
|
||||
movie: 'video/x-sgi-movie',
|
||||
// video
|
||||
qt: 'video/quicktime',
|
||||
mov: 'video/quicktime',
|
||||
wmv: 'video/windows-media',
|
||||
avi: 'video/x-msvideo',
|
||||
'3gp': 'video/3gpp',
|
||||
'3g2': 'video/3gpp2',
|
||||
mp4v: 'video/mp4',
|
||||
mpg4: 'video/mp4',
|
||||
ogv: 'video/ogg',
|
||||
m4v: 'video/x-m4v',
|
||||
asf: 'video/x-ms-asf',
|
||||
asx: 'video/x-ms-asf',
|
||||
wm: 'video/x-ms-wm',
|
||||
wmx: 'video/x-ms-wmx',
|
||||
wvx: 'video/x-ms-wvx',
|
||||
movie: 'video/x-sgi-movie',
|
||||
|
||||
// adobe
|
||||
pdf: app+'pdf',
|
||||
psd: 'image/vnd.adobe.photoshop',
|
||||
ai: app+'postscript',
|
||||
eps: app+'postscript',
|
||||
ps: app+'postscript',
|
||||
// adobe
|
||||
pdf: app+'pdf',
|
||||
psd: 'image/vnd.adobe.photoshop',
|
||||
ai: app+'postscript',
|
||||
eps: app+'postscript',
|
||||
ps: app+'postscript',
|
||||
|
||||
// ms office
|
||||
doc: app+'msword',
|
||||
rtf: app+'rtf',
|
||||
xls: app+'vnd.ms-excel',
|
||||
ppt: app+'vnd.ms-powerpoint',
|
||||
docx: msOffice+'wordprocessingml.document',
|
||||
xlsx: msOffice+'spreadsheetml.sheet',
|
||||
dotx: msOffice+'wordprocessingml.template',
|
||||
pptx: msOffice+'presentationml.presentation',
|
||||
// ms office
|
||||
doc: app+'msword',
|
||||
rtf: app+'rtf',
|
||||
xls: app+'vnd.ms-excel',
|
||||
ppt: app+'vnd.ms-powerpoint',
|
||||
docx: msOffice+'wordprocessingml.document',
|
||||
xlsx: msOffice+'spreadsheetml.sheet',
|
||||
dotx: msOffice+'wordprocessingml.template',
|
||||
pptx: msOffice+'presentationml.presentation',
|
||||
|
||||
// open office
|
||||
odt: openDoc+'text',
|
||||
ods: openDoc+'spreadsheet',
|
||||
odp: openDoc+'presentation'
|
||||
};
|
||||
// open office
|
||||
odt: openDoc+'text',
|
||||
ods: openDoc+'spreadsheet',
|
||||
odp: openDoc+'presentation'
|
||||
};
|
||||
|
||||
export const FileType = {
|
||||
Unknown: 'unknown',
|
||||
Text: 'text',
|
||||
Html: 'html',
|
||||
Code: 'code',
|
||||
Eml: 'eml',
|
||||
WordText: 'word-text',
|
||||
Word: 'word',
|
||||
Pdf: 'pdf',
|
||||
Image: 'image',
|
||||
Audio: 'audio',
|
||||
Video: 'video',
|
||||
Sheet: 'sheet',
|
||||
Spreadsheet: 'spreadsheet',
|
||||
Presentation: 'presentation',
|
||||
Certificate: 'certificate',
|
||||
CertificateBin: 'certificate-bin',
|
||||
Archive: 'archive'
|
||||
};
|
||||
|
||||
|
|
@ -138,7 +134,7 @@ export const FileInfo = {
|
|||
return app + 'ms-tnef';
|
||||
}
|
||||
let ext = fileName.split('.').pop();
|
||||
if (/^(txt|text|def|list|in|ini|log|sql|cfg|conf|asc)$/.test(ext))
|
||||
if (/^(txt|text|def|list|in|ini|log|sql|cfg|conf)$/.test(ext))
|
||||
return 'text/plain';
|
||||
if (/^(mpe?g|mpe|m1v|m2v)$/.test(ext))
|
||||
return 'video/mpeg';
|
||||
|
|
@ -186,15 +182,12 @@ export const FileInfo = {
|
|||
case 'video' == mimeTypeParts[0] || 'mkv' == ext || 'avi' == ext:
|
||||
result = FileType.Video;
|
||||
break;
|
||||
case ['php', 'js', 'css'].includes(ext):
|
||||
case ['php', 'js', 'css', 'xml', 'html'].includes(ext) || 'text/html' == mimeType:
|
||||
result = FileType.Code;
|
||||
break;
|
||||
case 'eml' == ext || ['message/delivery-status', 'message/rfc822'].includes(mimeType):
|
||||
result = FileType.Eml;
|
||||
break;
|
||||
case 'text/html' == mimeType || 'html' == ext:
|
||||
result = FileType.Html;
|
||||
break;
|
||||
case 'text' == mimeTypeParts[0] || 'txt' == ext || 'log' == ext:
|
||||
result = FileType.Text;
|
||||
break;
|
||||
|
|
@ -204,19 +197,17 @@ export const FileInfo = {
|
|||
case 'pdf' == type || 'pdf' == ext:
|
||||
result = FileType.Pdf;
|
||||
break;
|
||||
case [app+'pgp-signature', app+'pgp-keys'].includes(mimeType) ||
|
||||
['asc', 'pem', 'ppk'].includes(ext):
|
||||
case [app+'pgp-signature', app+'pgp-keys'].includes(mimeType)
|
||||
|| ['asc', 'pem', 'ppk'].includes(ext)
|
||||
|| [app+'pkcs7-signature'].includes(mimeType) || 'p7s' == ext:
|
||||
result = FileType.Certificate;
|
||||
break;
|
||||
case [app+'pkcs7-signature'].includes(mimeType) || 'p7s' == ext:
|
||||
result = FileType.CertificateBin;
|
||||
break;
|
||||
case match(msOffice+'.wordprocessingml') || match(openDoc+'.text') || match('vnd.ms-word')
|
||||
|| ['rtf', 'msword', 'vnd.msword'].includes(type):
|
||||
result = FileType.WordText;
|
||||
result = FileType.Word;
|
||||
break;
|
||||
case match(msOffice+'.spreadsheetml') || match(openDoc+'.spreadsheet') || match('ms-excel'):
|
||||
result = FileType.Sheet;
|
||||
result = FileType.Spreadsheet;
|
||||
break;
|
||||
case match(msOffice+'.presentationml') || match(openDoc+'.presentation') || match('ms-powerpoint'):
|
||||
result = FileType.Presentation;
|
||||
|
|
@ -232,45 +223,23 @@ export const FileInfo = {
|
|||
* @returns {string}
|
||||
*/
|
||||
getTypeIconClass: fileType => {
|
||||
let result = ['icon-file', ''];
|
||||
let result = 'icon-file';
|
||||
switch (fileType) {
|
||||
case FileType.Text:
|
||||
case FileType.Eml:
|
||||
case FileType.WordText:
|
||||
result[0] += '-text';
|
||||
break;
|
||||
case FileType.Html:
|
||||
case FileType.Code:
|
||||
result[0] += '-code';
|
||||
break;
|
||||
case FileType.Image:
|
||||
result[0] += '-image';
|
||||
break;
|
||||
case FileType.Audio:
|
||||
result[0] += '-music';
|
||||
break;
|
||||
case FileType.Video:
|
||||
result[0] += '-movie';
|
||||
break;
|
||||
case FileType.Archive:
|
||||
result[0] += '-zip';
|
||||
break;
|
||||
case FileType.Certificate:
|
||||
case FileType.CertificateBin:
|
||||
result[0] += '-certificate';
|
||||
break;
|
||||
case FileType.Sheet:
|
||||
result[0] += '-excel';
|
||||
break;
|
||||
case FileType.Presentation:
|
||||
result[0] += '-chart-graph';
|
||||
break;
|
||||
case FileType.Pdf:
|
||||
result = ['icon-none', 'pdf'];
|
||||
break;
|
||||
// no default
|
||||
case FileType.Word:
|
||||
return result + '-text';
|
||||
case FileType.Code:
|
||||
case FileType.Image:
|
||||
case FileType.Audio:
|
||||
case FileType.Video:
|
||||
case FileType.Archive:
|
||||
case FileType.Certificate:
|
||||
case FileType.Spreadsheet:
|
||||
case FileType.Presentation:
|
||||
return result + '-' + fileType;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
|
|
@ -283,7 +252,7 @@ export const FileInfo = {
|
|||
getCombinedIconClass: data => {
|
||||
if (isNonEmptyArray(data)) {
|
||||
let icons = data
|
||||
.map(item => item ? FileInfo.getIconClass(FileInfo.getExtension(item[0]), item[1])[0] : '')
|
||||
.map(item => item ? FileInfo.getIconClass(FileInfo.getExtension(item[0]), item[1]) : '')
|
||||
.validUnique();
|
||||
|
||||
return (icons && 1 === icons.length && 'icon-file' !== icons[0])
|
||||
|
|
@ -297,7 +266,7 @@ export const FileInfo = {
|
|||
friendlySize: bytes => {
|
||||
bytes = parseInt(bytes, 10) || 0;
|
||||
let i = Math.floor(Math.log(bytes) / Math.log(1024));
|
||||
return (bytes / Math.pow(1024, i)).toFixed(2>i ? 0 : 1) + sizes[i];
|
||||
return (bytes / Math.pow(1024, i)).toFixed(2>i ? 0 : 1) + ' ' + sizes[i];
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -179,12 +179,13 @@ export function mailBox(folder, page = 1, search = '', threadUid = '') {
|
|||
}
|
||||
|
||||
if (1 < page) {
|
||||
result = result.replace(/[/]+$/, '') + '/p' + page;
|
||||
result = result.replace(/\/+$/, '') + '/p' + page;
|
||||
}
|
||||
|
||||
if (search) {
|
||||
result = result.replace(/[/]+$/, '') + '/' + encodeURI(search);
|
||||
result = result.replace(/\/+$/, '') + '/' + encodeURI(search);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Notification, UploadErrorCode } from 'Common/Enums';
|
|||
import { langLink } from 'Common/Links';
|
||||
import { doc, createElement } from 'Common/Globals';
|
||||
|
||||
let I18N_DATA = window.rainloopI18N || {};
|
||||
let I18N_DATA = window.snappymailI18N || {};
|
||||
|
||||
export const trigger = ko.observable(false);
|
||||
|
||||
|
|
@ -14,14 +14,16 @@ export const trigger = ko.observable(false);
|
|||
* @returns {string}
|
||||
*/
|
||||
export function i18n(key, valueList, defaulValue) {
|
||||
let result = I18N_DATA[key] || defaulValue || key;
|
||||
|
||||
let path = key.split('/');
|
||||
if (!I18N_DATA[path[0]] || !path[1]) {
|
||||
return defaulValue || key;
|
||||
}
|
||||
let result = I18N_DATA[path[0]][path[1]] || defaulValue || key;
|
||||
if (valueList) {
|
||||
Object.entries(valueList).forEach(([key, value]) => {
|
||||
result = result.replace('%' + key + '%', value);
|
||||
});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +77,7 @@ function getNotificationMessage(code) {
|
|||
let key = getKeyByValue(Notification, code);
|
||||
if (key) {
|
||||
key = i18nKey(key).replace('_NOTIFICATION', '_ERROR');
|
||||
return I18N_DATA['NOTIFICATIONS/' + key];
|
||||
return I18N_DATA.NOTIFICATIONS[key];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,13 +127,13 @@ export function reload(admin, language) {
|
|||
const script = createElement('script');
|
||||
script.onload = () => {
|
||||
// reload the data
|
||||
if (window.rainloopI18N) {
|
||||
I18N_DATA = window.rainloopI18N || {};
|
||||
if (window.snappymailI18N) {
|
||||
I18N_DATA = window.snappymailI18N;
|
||||
i18nToNodes(doc);
|
||||
dispatchEvent(new CustomEvent('reload-time'));
|
||||
trigger(!trigger());
|
||||
}
|
||||
window.rainloopI18N = null;
|
||||
window.snappymailI18N = null;
|
||||
script.remove();
|
||||
resolve();
|
||||
};
|
||||
|
|
@ -150,7 +152,7 @@ export function reload(admin, language) {
|
|||
*/
|
||||
export function convertLangName(language, isEng = false) {
|
||||
return i18n(
|
||||
'LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/LANG_' + language.toUpperCase().replace(/[^a-zA-Z0-9]+/g, '_'),
|
||||
'LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/' + language,
|
||||
null,
|
||||
language
|
||||
);
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ class AbstractCheckbox extends AbstractComponent {
|
|||
this.inline = !!params.inline;
|
||||
|
||||
this.labeled = undefined !== params.label;
|
||||
this.labelAnimated = !!params.labelAnimated;
|
||||
}
|
||||
|
||||
click() {
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ import { AbstractModel } from 'Knoin/AbstractModel';
|
|||
|
||||
import { SMAudio } from 'Common/Audio';
|
||||
|
||||
const bAllowPdfPreview = undefined !== navigator.mimeTypes['application/pdf'];
|
||||
|
||||
export class AttachmentModel extends AbstractModel {
|
||||
constructor() {
|
||||
super();
|
||||
|
|
@ -92,27 +90,21 @@ export class AttachmentModel extends AbstractModel {
|
|||
* @returns {boolean}
|
||||
*/
|
||||
isText() {
|
||||
return (
|
||||
FileType.Text === this.fileType ||
|
||||
FileType.Eml === this.fileType ||
|
||||
FileType.Certificate === this.fileType ||
|
||||
FileType.Html === this.fileType ||
|
||||
FileType.Code === this.fileType
|
||||
);
|
||||
return FileType.Text === this.fileType || FileType.Eml === this.fileType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isPdf() {
|
||||
return FileType.Pdf === this.fileType;
|
||||
pdfPreview() {
|
||||
return null != navigator.mimeTypes['application/pdf'] && FileType.Pdf === this.fileType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
hasPreview() {
|
||||
return this.isImage() || (this.isPdf() && bAllowPdfPreview) || this.isText();
|
||||
return this.isImage() || this.pdfPreview() || this.isText();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -155,13 +147,6 @@ export class AttachmentModel extends AbstractModel {
|
|||
return link ? 'background:url(' + link + ')' : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
linkPreviewAsPlain() {
|
||||
return serverRequestRaw('ViewAsPlain', this.download);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
|
|
@ -169,11 +154,11 @@ export class AttachmentModel extends AbstractModel {
|
|||
let result = '';
|
||||
switch (true) {
|
||||
case this.isImage():
|
||||
case this.isPdf() && bAllowPdfPreview:
|
||||
case this.pdfPreview():
|
||||
result = this.linkPreview();
|
||||
break;
|
||||
case this.isText():
|
||||
result = this.linkPreviewAsPlain();
|
||||
result = serverRequestRaw('ViewAsPlain', this.download);
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
|
|
@ -181,18 +166,6 @@ export class AttachmentModel extends AbstractModel {
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
generateTransferDownloadUrl() {
|
||||
let link = this.linkDownload();
|
||||
if ('http' !== link.substr(0, 4)) {
|
||||
link = location.protocol + '//' + location.host + location.pathname + link;
|
||||
}
|
||||
|
||||
return this.mimeType + ':' + this.fileName + ':' + link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AttachmentModel} attachment
|
||||
* @param {*} event
|
||||
|
|
@ -201,7 +174,11 @@ export class AttachmentModel extends AbstractModel {
|
|||
eventDragStart(attachment, event) {
|
||||
const localEvent = event.originalEvent || event;
|
||||
if (attachment && localEvent && localEvent.dataTransfer && localEvent.dataTransfer.setData) {
|
||||
localEvent.dataTransfer.setData('DownloadURL', this.generateTransferDownloadUrl());
|
||||
let link = this.linkDownload();
|
||||
if ('http' !== link.substr(0, 4)) {
|
||||
link = location.protocol + '//' + location.host + location.pathname + link;
|
||||
}
|
||||
localEvent.dataTransfer.setData('DownloadURL', this.mimeType + ':' + this.fileName + ':' + link);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -211,13 +188,6 @@ export class AttachmentModel extends AbstractModel {
|
|||
* @returns {string}
|
||||
*/
|
||||
iconClass() {
|
||||
return FileInfo.getTypeIconClass(this.fileType)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
iconText() {
|
||||
return FileInfo.getTypeIconClass(this.fileType)[1];
|
||||
return FileInfo.getTypeIconClass(this.fileType);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,13 +96,6 @@ export class ComposeAttachmentModel extends AbstractModel {
|
|||
* @returns {string}
|
||||
*/
|
||||
iconClass() {
|
||||
return FileInfo.getIconClass(this.fileExt(), this.mimeType())[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {string}
|
||||
*/
|
||||
iconText() {
|
||||
return FileInfo.getIconClass(this.fileExt(), this.mimeType())[1];
|
||||
return FileInfo.getIconClass(this.fileExt(), this.mimeType());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import * as Local from 'Storage/Client';
|
|||
|
||||
import { AppUserStore } from 'Stores/User/App';
|
||||
import { FolderUserStore } from 'Stores/User/Folder';
|
||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||
|
||||
import ko from 'ko';
|
||||
|
||||
|
|
@ -113,6 +114,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
|||
AppUserStore.threadsAllowed(!!(Settings.app('useImapThread') && this.IsThreadsSupported));
|
||||
|
||||
FolderUserStore.folderListOptimized(!!this.Optimized);
|
||||
FolderUserStore.sortSupported(!!this.IsSortSupported);
|
||||
|
||||
let update = false;
|
||||
|
||||
|
|
@ -123,8 +125,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
|||
SettingsGet('DraftFolder') +
|
||||
SettingsGet('SpamFolder') +
|
||||
SettingsGet('TrashFolder') +
|
||||
SettingsGet('ArchiveFolder') +
|
||||
SettingsGet('NullFolder'))
|
||||
SettingsGet('ArchiveFolder'))
|
||||
) {
|
||||
Settings.set('SentFolder', this.SystemFolders[ServerFolderType.SENT] || null);
|
||||
Settings.set('DraftFolder', this.SystemFolders[ServerFolderType.DRAFTS] || null);
|
||||
|
|
@ -147,8 +148,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
|
|||
DraftFolder: FolderUserStore.draftFolder(),
|
||||
SpamFolder: FolderUserStore.spamFolder(),
|
||||
TrashFolder: FolderUserStore.trashFolder(),
|
||||
ArchiveFolder: FolderUserStore.archiveFolder(),
|
||||
NullFolder: 'NullFolder'
|
||||
ArchiveFolder: FolderUserStore.archiveFolder()
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -301,7 +301,10 @@ export class FolderModel extends AbstractModel {
|
|||
|
||||
canBeDeleted: () => !folder.isSystemFolder() && !folder.subFolders.length,
|
||||
|
||||
canBeSubscribed: () => !folder.isSystemFolder() && folder.selectable && Settings.app('useImapSubscribe'),
|
||||
canBeSubscribed: () => !folder.isSystemFolder()
|
||||
&& SettingsUserStore.hideUnsubscribed()
|
||||
&& folder.selectable
|
||||
&& Settings.app('useImapSubscribe'),
|
||||
|
||||
canBeSelected: () => !folder.isSystemFolder() && folder.selectable,
|
||||
|
||||
|
|
|
|||
|
|
@ -45,6 +45,9 @@ export class MessageModel extends AbstractModel {
|
|||
this.addObservables({
|
||||
subject: '',
|
||||
size: 0,
|
||||
spamScore: 0,
|
||||
spamResult: '',
|
||||
isSpam: false,
|
||||
dateTimeStampInUTC: 0,
|
||||
priority: MessagePriority.Normal,
|
||||
|
||||
|
|
@ -116,6 +119,9 @@ export class MessageModel extends AbstractModel {
|
|||
this._reset();
|
||||
this.subject('');
|
||||
this.size(0);
|
||||
this.spamScore(0);
|
||||
this.spamResult('');
|
||||
this.isSpam(false);
|
||||
this.dateTimeStampInUTC(0);
|
||||
this.priority(MessagePriority.Normal);
|
||||
|
||||
|
|
@ -211,10 +217,10 @@ export class MessageModel extends AbstractModel {
|
|||
|
||||
/**
|
||||
* @param {boolean} friendlyView
|
||||
* @param {boolean=} wrapWithLink = false
|
||||
* @param {boolean=} wrapWithLink
|
||||
* @returns {string}
|
||||
*/
|
||||
fromToLine(friendlyView, wrapWithLink = false) {
|
||||
fromToLine(friendlyView, wrapWithLink) {
|
||||
return this.from.toString(friendlyView, wrapWithLink);
|
||||
}
|
||||
|
||||
|
|
@ -232,37 +238,37 @@ export class MessageModel extends AbstractModel {
|
|||
|
||||
/**
|
||||
* @param {boolean} friendlyView
|
||||
* @param {boolean=} wrapWithLink = false
|
||||
* @param {boolean=} wrapWithLink
|
||||
* @returns {string}
|
||||
*/
|
||||
toToLine(friendlyView, wrapWithLink = false) {
|
||||
toToLine(friendlyView, wrapWithLink) {
|
||||
return this.to.toString(friendlyView, wrapWithLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} friendlyView
|
||||
* @param {boolean=} wrapWithLink = false
|
||||
* @param {boolean=} wrapWithLink
|
||||
* @returns {string}
|
||||
*/
|
||||
ccToLine(friendlyView, wrapWithLink = false) {
|
||||
ccToLine(friendlyView, wrapWithLink) {
|
||||
return this.cc.toString(friendlyView, wrapWithLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} friendlyView
|
||||
* @param {boolean=} wrapWithLink = false
|
||||
* @param {boolean=} wrapWithLink
|
||||
* @returns {string}
|
||||
*/
|
||||
bccToLine(friendlyView, wrapWithLink = false) {
|
||||
bccToLine(friendlyView, wrapWithLink) {
|
||||
return this.bcc.toString(friendlyView, wrapWithLink);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} friendlyView
|
||||
* @param {boolean=} wrapWithLink = false
|
||||
* @param {boolean=} wrapWithLink
|
||||
* @returns {string}
|
||||
*/
|
||||
replyToToLine(friendlyView, wrapWithLink = false) {
|
||||
replyToToLine(friendlyView, wrapWithLink) {
|
||||
return this.replyTo.toString(friendlyView, wrapWithLink);
|
||||
}
|
||||
|
||||
|
|
@ -318,7 +324,7 @@ export class MessageModel extends AbstractModel {
|
|||
* @param {boolean=} last = false
|
||||
* @returns {Array}
|
||||
*/
|
||||
replyEmails(excludeEmails, last = false) {
|
||||
replyEmails(excludeEmails, last) {
|
||||
const result = [],
|
||||
unic = undefined === excludeEmails ? {} : excludeEmails;
|
||||
|
||||
|
|
@ -339,7 +345,7 @@ export class MessageModel extends AbstractModel {
|
|||
* @param {boolean=} last = false
|
||||
* @returns {Array.<Array>}
|
||||
*/
|
||||
replyAllEmails(excludeEmails, last = false) {
|
||||
replyAllEmails(excludeEmails, last) {
|
||||
let data = [];
|
||||
const toResult = [],
|
||||
ccResult = [],
|
||||
|
|
@ -364,7 +370,7 @@ export class MessageModel extends AbstractModel {
|
|||
/**
|
||||
* @param {boolean=} print = false
|
||||
*/
|
||||
viewPopupMessage(print = false) {
|
||||
viewPopupMessage(print) {
|
||||
const timeStampInUTC = this.dateTimeStampInUTC() || 0,
|
||||
ccLine = this.ccToLine(false),
|
||||
m = 0 < timeStampInUTC ? new Date(timeStampInUTC * 1000) : null,
|
||||
|
|
@ -414,6 +420,9 @@ export class MessageModel extends AbstractModel {
|
|||
this.subject(message.subject());
|
||||
|
||||
this.size(message.size());
|
||||
this.spamScore(message.spamScore());
|
||||
this.spamResult(message.spamResult());
|
||||
this.isSpam(message.isSpam());
|
||||
this.dateTimeStampInUTC(message.dateTimeStampInUTC());
|
||||
this.priority(message.priority());
|
||||
|
||||
|
|
|
|||
|
|
@ -55,76 +55,17 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
|||
* @param {string} sPassword
|
||||
* @param {boolean} bSignMe
|
||||
* @param {string=} sLanguage
|
||||
* @param {string=} sAdditionalCode
|
||||
* @param {boolean=} bAdditionalCodeSignMe
|
||||
*/
|
||||
login(fCallback, sEmail, sPassword, bSignMe, sLanguage, sAdditionalCode, bAdditionalCodeSignMe) {
|
||||
login(fCallback, sEmail, sPassword, bSignMe, sLanguage) {
|
||||
this.defaultRequest(fCallback, 'Login', {
|
||||
Email: sEmail,
|
||||
Login: '',
|
||||
Password: sPassword,
|
||||
Language: sLanguage || '',
|
||||
AdditionalCode: sAdditionalCode || '',
|
||||
AdditionalCodeSignMe: bAdditionalCodeSignMe ? 1 : 0,
|
||||
SignMe: bSignMe ? 1 : 0
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
getTwoFactor(fCallback) {
|
||||
this.defaultRequest(fCallback, 'GetTwoFactorInfo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
createTwoFactor(fCallback) {
|
||||
this.defaultRequest(fCallback, 'CreateTwoFactorSecret');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
clearTwoFactor(fCallback) {
|
||||
this.defaultRequest(fCallback, 'ClearTwoFactorInfo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
showTwoFactorSecret(fCallback) {
|
||||
this.defaultRequest(fCallback, 'ShowTwoFactorSecret');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
* @param {string} sCode
|
||||
*/
|
||||
testTwoFactor(fCallback, sCode) {
|
||||
this.defaultRequest(fCallback, 'TestTwoFactorInfo', {
|
||||
Code: sCode
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
* @param {boolean} bEnable
|
||||
*/
|
||||
enableTwoFactor(fCallback, bEnable) {
|
||||
this.defaultRequest(fCallback, 'EnableTwoFactor', {
|
||||
Enable: bEnable ? 1 : 0
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
clearTwoFactorInfo(fCallback) {
|
||||
this.defaultRequest(fCallback, 'ClearTwoFactorInfo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {?Function} fCallback
|
||||
*/
|
||||
|
|
@ -297,54 +238,44 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
|||
|
||||
/**
|
||||
* @param {Function} fCallback
|
||||
* @param {string} sFolderFullNameRaw
|
||||
* @param {number=} iOffset = 0
|
||||
* @param {number=} iLimit = 20
|
||||
* @param {string=} sSearch = ''
|
||||
* @param {string=} sThreadUid = ''
|
||||
* @param {object} params
|
||||
* @param {boolean=} bSilent = false
|
||||
*/
|
||||
messageList(fCallback, sFolderFullNameRaw, iOffset = 0, iLimit = 20, sSearch = '', sThreadUid = '', bSilent = false) {
|
||||
sFolderFullNameRaw = pString(sFolderFullNameRaw);
|
||||
|
||||
const folderHash = getFolderHash(sFolderFullNameRaw),
|
||||
useThreads = AppUserStore.threadsAllowed() && SettingsUserStore.useThreads(),
|
||||
messageList(fCallback, params, bSilent = false) {
|
||||
const
|
||||
sFolderFullNameRaw = pString(params.Folder),
|
||||
folderHash = getFolderHash(sFolderFullNameRaw),
|
||||
useThreads = AppUserStore.threadsAllowed() && SettingsUserStore.useThreads() ? 1 : 0,
|
||||
inboxUidNext = getFolderInboxName() === sFolderFullNameRaw ? getFolderUidNext(sFolderFullNameRaw) : '';
|
||||
|
||||
let params = {}, sGetAdd = '';
|
||||
params.Folder = sFolderFullNameRaw;
|
||||
params.ThreadUid = useThreads ? params.ThreadUid : '';
|
||||
params = Object.assign({
|
||||
Folder: '',
|
||||
Offset: 0,
|
||||
Limit: SettingsUserStore.messagesPerPage(),
|
||||
Search: '',
|
||||
UidNext: inboxUidNext,
|
||||
UseThreads: useThreads,
|
||||
ThreadUid: '',
|
||||
Sort: FolderUserStore.sortMode()
|
||||
}, params);
|
||||
|
||||
if (folderHash && (!sSearch || !sSearch.includes('is:'))) {
|
||||
let sGetAdd = '';
|
||||
|
||||
if (folderHash && (!params.Search || !params.Search.includes('is:'))) {
|
||||
sGetAdd = 'MessageList/' +
|
||||
SUB_QUERY_PREFIX +
|
||||
'/' +
|
||||
urlsafeArray([
|
||||
sFolderFullNameRaw,
|
||||
iOffset,
|
||||
iLimit,
|
||||
sSearch,
|
||||
SettingsGet('ProjectHash'),
|
||||
folderHash,
|
||||
inboxUidNext,
|
||||
useThreads ? 1 : 0,
|
||||
useThreads ? sThreadUid : ''
|
||||
]);
|
||||
} else {
|
||||
params = {
|
||||
Folder: sFolderFullNameRaw,
|
||||
Offset: iOffset,
|
||||
Limit: iLimit,
|
||||
Search: sSearch,
|
||||
UidNext: inboxUidNext,
|
||||
UseThreads: useThreads ? 1 : 0,
|
||||
ThreadUid: useThreads ? sThreadUid : ''
|
||||
};
|
||||
urlsafeArray([SettingsGet('ProjectHash'),folderHash].concat(Object.values(params)));
|
||||
params = {};
|
||||
}
|
||||
|
||||
this.defaultRequest(
|
||||
fCallback,
|
||||
'MessageList',
|
||||
params,
|
||||
sSearch ? 300000 : 30000,
|
||||
30000,
|
||||
sGetAdd,
|
||||
bSilent ? [] : ['MessageList']
|
||||
);
|
||||
|
|
@ -562,7 +493,7 @@ class RemoteUserFetch extends AbstractFetchRemote {
|
|||
* @param {Object} oData
|
||||
*/
|
||||
sendMessage(fCallback, oData) {
|
||||
this.defaultRequest(fCallback, 'SendMessage', oData, 300000);
|
||||
this.defaultRequest(fCallback, 'SendMessage', oData, 30000);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ export class MailBoxUserScreen extends AbstractScreen {
|
|||
|
||||
FolderUserStore.currentFolder(folder);
|
||||
|
||||
MessageUserStore.listPage(page);
|
||||
MessageUserStore.listPage(1 > page ? 1 : page);
|
||||
MessageUserStore.listSearch(search);
|
||||
MessageUserStore.listThreadUid(threadUid);
|
||||
|
||||
|
|
@ -119,23 +119,15 @@ export class MailBoxUserScreen extends AbstractScreen {
|
|||
*/
|
||||
routes() {
|
||||
const
|
||||
fNormS = (request, vals) => {
|
||||
if (request) {
|
||||
vals[0] = decodeURI(pString(vals[0]));
|
||||
vals[1] = pInt(vals[1]);
|
||||
} else {
|
||||
vals[0] = getFolderInboxName();
|
||||
vals[1] = 1;
|
||||
}
|
||||
return [vals[0], 1 > vals[1] ? 1 : vals[1], decodeURI(pString(vals[2]))];
|
||||
},
|
||||
fNormD = (request, vals) =>
|
||||
[decodeURI(request ? pString(vals[0]) : getFolderInboxName()), 1, decodeURI(pString(vals[1]))];
|
||||
folder = (request, vals) => request ? decodeURI(pString(vals[0])) : getFolderInboxName(),
|
||||
fNormS = (request, vals) => [folder(request, vals), request ? pInt(vals[1]) : 1, decodeURI(pString(vals[2]))];
|
||||
|
||||
return [
|
||||
[/^([^/]*)$/, { 'normalize_': fNormS }],
|
||||
[/^([a-zA-Z0-9~]+)\/(.+)\/?$/, { 'normalize_': fNormD }],
|
||||
[/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)(?:\/(.+)\/?)?$/, { 'normalize_': fNormS }]
|
||||
[/^([^/]*)$/, { normalize_: fNormS }],
|
||||
[/^([a-zA-Z0-9~]+)\/(.+)\/?$/, { normalize_: (request, vals) =>
|
||||
[folder(request, vals), 1, decodeURI(pString(vals[1]))]
|
||||
}],
|
||||
[/^([a-zA-Z0-9~]+)\/p([1-9][0-9]*)(?:\/(.+)\/?)?$/, { normalize_: fNormS }]
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ export class SettingsUserScreen extends AbstractSettingsScreen {
|
|||
settingsAddViewModel(FiltersUserSettings, 'SettingsFilters', 'SETTINGS_LABELS/LABEL_FILTERS_NAME', 'filters');
|
||||
}
|
||||
|
||||
if (Settings.capa(Capa.AutoLogout) || Settings.capa(Capa.TwoFactor)) {
|
||||
if (Settings.capa(Capa.AutoLogout)) {
|
||||
settingsAddViewModel(SecurityUserSettings, 'SettingsSecurity', 'SETTINGS_LABELS/LABEL_SECURITY_NAME', 'security');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export class ContactsAdminSettings {
|
|||
addObservablesTo(this, {
|
||||
enableContacts: !!SettingsGet('ContactsEnable'),
|
||||
contactsSync: !!SettingsGet('ContactsSync'),
|
||||
contactsType: '',
|
||||
contactsType: SettingsGet('ContactsPdoType'),
|
||||
|
||||
pdoDsn: SettingsGet('ContactsPdoDsn'),
|
||||
pdoUser: SettingsGet('ContactsPdoUser'),
|
||||
|
|
@ -69,8 +69,6 @@ export class ContactsAdminSettings {
|
|||
})
|
||||
.extend({ notify: 'always' });
|
||||
|
||||
this.contactsType(SettingsGet('ContactsPdoType'));
|
||||
|
||||
addSubscribablesTo(this, {
|
||||
enableContacts: value =>
|
||||
Remote.saveAdminConfig(null, {
|
||||
|
|
|
|||
|
|
@ -53,7 +53,11 @@ export class GeneralAdminSettings {
|
|||
|
||||
this.weakPassword = rl.app.weakPassword;
|
||||
|
||||
// fetch('./data/VERSION?' + Math.random()).then(response => this.dataFolderAccess(response.ok));
|
||||
/** https://github.com/RainLoop/rainloop-webmail/issues/1924
|
||||
if (this.weakPassword) {
|
||||
fetch('./data/VERSION?' + Math.random()).then(response => this.dataFolderAccess(response.ok));
|
||||
}
|
||||
*/
|
||||
|
||||
this.mainAttachmentLimit = ko
|
||||
.observable(pInt(SettingsGet('AttachmentLimit')) / (1024 * 1024))
|
||||
|
|
|
|||
|
|
@ -16,10 +16,6 @@ export class SecurityAdminSettings {
|
|||
verifySslCertificate: !!SettingsGet('VerifySslCertificate'),
|
||||
allowSelfSigned: !!SettingsGet('AllowSelfSigned'),
|
||||
|
||||
isTwoFactorDropperShown: false,
|
||||
twoFactorDropperUser: '',
|
||||
twoFactorDropperUserFocused: false,
|
||||
|
||||
adminLogin: SettingsGet('AdminLogin'),
|
||||
adminLoginError: false,
|
||||
adminPassword: '',
|
||||
|
|
@ -30,9 +26,7 @@ export class SecurityAdminSettings {
|
|||
adminPasswordUpdateError: false,
|
||||
adminPasswordUpdateSuccess: false,
|
||||
|
||||
capaOpenPGP: Settings.capa(Capa.OpenPGP),
|
||||
capaTwoFactorAuth: Settings.capa(Capa.TwoFactor),
|
||||
capaTwoFactorAuthForce: Settings.capa(Capa.TwoFactorForce)
|
||||
capaOpenPGP: Settings.capa(Capa.OpenPGP)
|
||||
});
|
||||
|
||||
addSubscribablesTo(this, {
|
||||
|
|
@ -60,18 +54,6 @@ export class SecurityAdminSettings {
|
|||
CapaOpenPGP: value ? 1 : 0
|
||||
}),
|
||||
|
||||
capaTwoFactorAuth: value => {
|
||||
value || this.capaTwoFactorAuthForce(false);
|
||||
Remote.saveAdminConfig(null, {
|
||||
CapaTwoFactorAuth: value ? 1 : 0
|
||||
});
|
||||
},
|
||||
|
||||
capaTwoFactorAuthForce: value =>
|
||||
Remote.saveAdminConfig(null, {
|
||||
CapaTwoFactorAuthForce: value ? 1 : 0
|
||||
}),
|
||||
|
||||
useLocalProxyForExternalImages: value =>
|
||||
Remote.saveAdminConfig(null, {
|
||||
UseLocalProxyForExternalImages: value ? 1 : 0
|
||||
|
|
@ -120,15 +102,6 @@ export class SecurityAdminSettings {
|
|||
return true;
|
||||
}
|
||||
|
||||
showTwoFactorDropper() {
|
||||
this.twoFactorDropperUser('');
|
||||
this.isTwoFactorDropperShown(true);
|
||||
|
||||
setTimeout(() => {
|
||||
this.twoFactorDropperUserFocused(true);
|
||||
}, 50);
|
||||
}
|
||||
|
||||
onNewAdminPasswordResponse(iError, data) {
|
||||
if (iError) {
|
||||
this.adminPasswordUpdateError(true);
|
||||
|
|
@ -147,9 +120,5 @@ export class SecurityAdminSettings {
|
|||
this.adminPassword('');
|
||||
this.adminPasswordNew('');
|
||||
this.adminPasswordNew2('');
|
||||
|
||||
this.isTwoFactorDropperShown(false);
|
||||
this.twoFactorDropperUser('');
|
||||
this.twoFactorDropperUserFocused(false);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import ko from 'ko';
|
|||
|
||||
import { Notification } from 'Common/Enums';
|
||||
import { ClientSideKeyName } from 'Common/EnumsUser';
|
||||
import { Settings } from 'Common/Globals';
|
||||
import { getNotification } from 'Common/Translator';
|
||||
|
||||
import { removeFolderFromCacheList } from 'Common/Cache';
|
||||
|
|
@ -9,6 +10,7 @@ import { removeFolderFromCacheList } from 'Common/Cache';
|
|||
import * as Local from 'Storage/Client';
|
||||
|
||||
import { FolderUserStore } from 'Stores/User/Folder';
|
||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||
|
||||
import Remote from 'Remote/User/Fetch';
|
||||
|
||||
|
|
@ -23,6 +25,7 @@ export class FoldersUserSettings {
|
|||
this.folderList = FolderUserStore.folderList;
|
||||
this.folderListOptimized = FolderUserStore.folderListOptimized;
|
||||
this.folderListError = FolderUserStore.folderListError;
|
||||
this.hideUnsubscribed = SettingsUserStore.hideUnsubscribed;
|
||||
|
||||
this.loading = ko.computed(() => {
|
||||
const loading = FolderUserStore.foldersLoading(),
|
||||
|
|
@ -36,6 +39,9 @@ export class FoldersUserSettings {
|
|||
this.folderForDeletion = ko.observable(null).deleteAccessHelper();
|
||||
|
||||
this.folderForEdit = ko.observable(null).extend({ toggleSubscribeProperty: [this, 'edited'] });
|
||||
|
||||
this.useImapSubscribe = Settings.app('useImapSubscribe');
|
||||
this.hideUnsubscribed.subscribe(value => Remote.saveSetting('HideUnsubscribed', value ? 1 : 0));
|
||||
}
|
||||
|
||||
folderEditOnEnter(folder) {
|
||||
|
|
|
|||
|
|
@ -5,18 +5,13 @@ import { Capa, SaveSettingsStep } from 'Common/Enums';
|
|||
import { Settings } from 'Common/Globals';
|
||||
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
|
||||
|
||||
import { showScreenPopup } from 'Knoin/Knoin';
|
||||
|
||||
import { SettingsUserStore } from 'Stores/User/Settings';
|
||||
|
||||
import Remote from 'Remote/User/Fetch';
|
||||
|
||||
import { TwoFactorConfigurationPopupView } from 'View/Popup/TwoFactorConfiguration';
|
||||
|
||||
export class SecurityUserSettings {
|
||||
constructor() {
|
||||
this.capaAutoLogout = Settings.capa(Capa.AutoLogout);
|
||||
this.capaTwoFactor = Settings.capa(Capa.TwoFactor);
|
||||
|
||||
this.autoLogout = SettingsUserStore.autoLogout;
|
||||
this.autoLogoutTrigger = ko.observable(SaveSettingsStep.Idle);
|
||||
|
|
@ -43,8 +38,4 @@ export class SecurityUserSettings {
|
|||
));
|
||||
}
|
||||
}
|
||||
|
||||
configureTwoFactor() {
|
||||
showScreenPopup(TwoFactorConfigurationPopupView);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { FolderType } from 'Common/EnumsUser';
|
||||
import { FolderType, FolderSortMode } from 'Common/EnumsUser';
|
||||
import { UNUSED_OPTION_VALUE } from 'Common/Consts';
|
||||
import { addObservablesTo, addSubscribablesTo } from 'Common/Utils';
|
||||
import { folderListOptionsBuilder } from 'Common/UtilsUser';
|
||||
|
|
@ -19,6 +19,12 @@ export const FolderUserStore = new class {
|
|||
*/
|
||||
displaySpecSetting: false,
|
||||
|
||||
/**
|
||||
* If the IMAP server supports SORT
|
||||
*/
|
||||
sortSupported: false,
|
||||
// sortMode: '',
|
||||
|
||||
sentFolder: '',
|
||||
draftFolder: '',
|
||||
spamFolder: '',
|
||||
|
|
@ -36,6 +42,8 @@ export const FolderUserStore = new class {
|
|||
foldersInboxUnreadCount: 0
|
||||
});
|
||||
|
||||
this.sortMode = ko.observable('').extend({ limitedList: Object.values(FolderSortMode) });
|
||||
|
||||
this.namespace = '';
|
||||
|
||||
this.folderList = ko.observableArray();
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export const SettingsUserStore = new class {
|
|||
allowDraftAutosave: !!SettingsGet('AllowDraftAutosave'),
|
||||
useThreads: !!SettingsGet('UseThreads'),
|
||||
replySameFolder: !!SettingsGet('ReplySameFolder'),
|
||||
hideUnsubscribed: !!SettingsGet('HideUnsubscribed'),
|
||||
|
||||
autoLogout: pInt(SettingsGet('AutoLogout'))
|
||||
});
|
||||
|
|
|
|||
|
|
@ -42,7 +42,6 @@
|
|||
@import "Filter.less";
|
||||
@import "Template.less";
|
||||
@import "OpenPgpKey.less";
|
||||
@import "TwoFactor.less";
|
||||
@import "Identity.less";
|
||||
@import "AdvancedSearch.less";
|
||||
@import "Attachmnets.less";
|
||||
|
|
|
|||
|
|
@ -29,11 +29,10 @@
|
|||
}
|
||||
|
||||
.checkboxAttachment {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 1px 4px 0 5px;
|
||||
bottom: 6px;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
}
|
||||
|
||||
.attachmentSize {
|
||||
|
|
@ -104,16 +103,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.attachmentIconText {
|
||||
display: inline-block;
|
||||
font-size: 28px;
|
||||
width: 60px;
|
||||
height: 56px;
|
||||
color: #aaa;
|
||||
line-height: 56px;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
/*
|
||||
.attachmentIconParent.hasPreview.isImage {
|
||||
.iconMain {
|
||||
|
|
|
|||
|
|
@ -18,14 +18,9 @@
|
|||
}
|
||||
|
||||
.attachmentAreaParent {
|
||||
padding: 10px 10px 6px 10px;
|
||||
background: #ddd;
|
||||
border-top: 1px solid #ccc;
|
||||
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.attachmentAreaParent {
|
||||
padding: 10px 10px 6px 10px;
|
||||
|
||||
.no-attachments-desc {
|
||||
padding: 50px 10px;
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
}
|
||||
|
||||
.controls {
|
||||
.inputLoginForm, .inputEmail, .inputLogin, .inputPassword, .inputAdditionalCode {
|
||||
.inputLoginForm, .inputEmail, .inputLogin, .inputPassword {
|
||||
font-size: 18px;
|
||||
height: 40px;
|
||||
line-height: 20px;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,11 @@ html.rl-no-preview-pane {
|
|||
}
|
||||
}
|
||||
|
||||
#sort-list-dropdown-id {
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
.messageList {
|
||||
|
||||
.toolbar {
|
||||
|
|
@ -254,9 +259,9 @@ html.rl-no-preview-pane {
|
|||
padding: 0 10px 0 5px;
|
||||
}
|
||||
|
||||
time {
|
||||
time, .sizeParent {
|
||||
margin: 0 5px;
|
||||
color: #999;
|
||||
opacity: 0.6;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
@ -472,7 +477,7 @@ html .messageList .line-loading {
|
|||
line-height: 16px;
|
||||
margin-left: 30px;
|
||||
order: 1;
|
||||
width: calc(100% - 60px);
|
||||
width: calc(100% - 120px);
|
||||
}
|
||||
|
||||
.senderParent {
|
||||
|
|
@ -483,9 +488,13 @@ html .messageList .line-loading {
|
|||
order: 1;
|
||||
}
|
||||
|
||||
.attachmentParent {
|
||||
.sizeParent {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
.attachmentParent {
|
||||
order: 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -136,15 +136,8 @@
|
|||
}
|
||||
|
||||
.informationFull {
|
||||
margin-top: 10px;
|
||||
border: 1px solid #999;
|
||||
border-radius: 5px;
|
||||
padding: 8px 0;
|
||||
overflow: hidden;
|
||||
margin-top: 30px;
|
||||
|
||||
.size {
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
|
|
@ -155,7 +148,7 @@
|
|||
}
|
||||
|
||||
td {
|
||||
padding: 0 10px;
|
||||
padding: 4px;
|
||||
vertical-align: top;
|
||||
min-width: 43px;
|
||||
}
|
||||
|
|
@ -163,17 +156,15 @@
|
|||
td:first-child {
|
||||
border-right: 1px solid #999;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
width: 1%;
|
||||
}
|
||||
|
||||
.uiLine {
|
||||
}
|
||||
|
||||
.uiLabel {
|
||||
.labelTo {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.uiLabelValue {
|
||||
td + td {
|
||||
word-break: break-all;
|
||||
}
|
||||
}
|
||||
|
|
@ -273,13 +264,9 @@
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.checkboxAttachment {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.selection-mode {
|
||||
&:not(.selection-mode) {
|
||||
.checkboxAttachment {
|
||||
display: inline-block;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
}
|
||||
|
||||
.list-table {
|
||||
margin-top: 40px;
|
||||
margin-top: 1em;
|
||||
|
||||
.folder-padding {
|
||||
display: inline-block;
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
.b-two-factor-content {
|
||||
|
||||
width: 750px;
|
||||
|
||||
.modal-body {
|
||||
min-height: 100px;
|
||||
}
|
||||
}
|
||||
|
|
@ -64,8 +64,7 @@ class FolderSystemPopupView extends AbstractViewPopup {
|
|||
DraftFolder: FolderUserStore.draftFolder(),
|
||||
SpamFolder: FolderUserStore.spamFolder(),
|
||||
TrashFolder: FolderUserStore.trashFolder(),
|
||||
ArchiveFolder: FolderUserStore.archiveFolder(),
|
||||
NullFolder: 'NullFolder'
|
||||
ArchiveFolder: FolderUserStore.archiveFolder()
|
||||
});
|
||||
}).debounce(1000),
|
||||
fCallback = () => {
|
||||
|
|
|
|||
|
|
@ -1,193 +0,0 @@
|
|||
import { Capa } from 'Common/Enums';
|
||||
import { Settings } from 'Common/Globals';
|
||||
import { pString } from 'Common/Utils';
|
||||
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
|
||||
|
||||
import Remote from 'Remote/User/Fetch';
|
||||
|
||||
import { showScreenPopup } from 'Knoin/Knoin';
|
||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||
|
||||
import { TwoFactorTestPopupView } from 'View/Popup/TwoFactorTest';
|
||||
|
||||
class TwoFactorConfigurationPopupView extends AbstractViewPopup {
|
||||
constructor() {
|
||||
super('TwoFactorConfiguration');
|
||||
|
||||
this.addObservables({
|
||||
lock: false,
|
||||
|
||||
processing: false,
|
||||
clearing: false,
|
||||
secreting: false,
|
||||
|
||||
viewUser: '',
|
||||
twoFactorStatus: false,
|
||||
|
||||
twoFactorTested: false,
|
||||
|
||||
viewSecret: '',
|
||||
viewBackupCodes: '',
|
||||
viewUrlTitle: '',
|
||||
viewUrl: '',
|
||||
|
||||
viewEnable_: false
|
||||
});
|
||||
|
||||
this.capaTwoFactor = Settings.capa(Capa.TwoFactor);
|
||||
|
||||
const fn = iError => iError && this.viewEnable_(false);
|
||||
this.addComputables({
|
||||
viewEnable: {
|
||||
read: this.viewEnable_,
|
||||
write: (value) => {
|
||||
value = !!value;
|
||||
if (value && this.twoFactorTested()) {
|
||||
this.viewEnable_(value);
|
||||
Remote.enableTwoFactor(fn, value);
|
||||
} else {
|
||||
if (!value) {
|
||||
this.viewEnable_(value);
|
||||
}
|
||||
Remote.enableTwoFactor(fn, false);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
viewTwoFactorEnableTooltip: () => {
|
||||
translatorTrigger();
|
||||
return this.twoFactorTested() || this.viewEnable_()
|
||||
? ''
|
||||
: i18n('POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_TEST_BEFORE_DESC');
|
||||
},
|
||||
|
||||
viewTwoFactorStatus: () => {
|
||||
translatorTrigger();
|
||||
return i18n(
|
||||
this.twoFactorStatus()
|
||||
? 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_CONFIGURED_DESC'
|
||||
: 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_NOT_CONFIGURED_DESC'
|
||||
);
|
||||
},
|
||||
|
||||
twoFactorAllowedEnable: () => this.viewEnable() || this.twoFactorTested()
|
||||
});
|
||||
|
||||
this.onResult = this.onResult.bind(this);
|
||||
this.onShowSecretResult = this.onShowSecretResult.bind(this);
|
||||
}
|
||||
|
||||
showSecret() {
|
||||
this.secreting(true);
|
||||
Remote.showTwoFactorSecret(this.onShowSecretResult);
|
||||
}
|
||||
|
||||
hideSecret() {
|
||||
this.viewSecret('');
|
||||
this.viewBackupCodes('');
|
||||
this.viewUrlTitle('');
|
||||
this.viewUrl('');
|
||||
}
|
||||
|
||||
createTwoFactor() {
|
||||
this.processing(true);
|
||||
Remote.createTwoFactor(this.onResult);
|
||||
}
|
||||
|
||||
logout() {
|
||||
rl.app.logout();
|
||||
}
|
||||
|
||||
testTwoFactor() {
|
||||
showScreenPopup(TwoFactorTestPopupView, [this.twoFactorTested]);
|
||||
}
|
||||
|
||||
clearTwoFactor() {
|
||||
this.viewSecret('');
|
||||
this.viewBackupCodes('');
|
||||
this.viewUrlTitle('');
|
||||
this.viewUrl('');
|
||||
|
||||
this.twoFactorTested(false);
|
||||
|
||||
this.clearing(true);
|
||||
Remote.clearTwoFactor(this.onResult);
|
||||
}
|
||||
|
||||
onShow(bLock) {
|
||||
this.lock(!!bLock);
|
||||
|
||||
this.viewSecret('');
|
||||
this.viewBackupCodes('');
|
||||
this.viewUrlTitle('');
|
||||
this.viewUrl('');
|
||||
}
|
||||
|
||||
onHide() {
|
||||
if (this.lock()) {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
|
||||
getQr() {
|
||||
return (
|
||||
'otpauth://totp/' +
|
||||
encodeURIComponent(this.viewUser()) +
|
||||
'?secret=' +
|
||||
encodeURIComponent(this.viewSecret()) +
|
||||
'&issuer=' +
|
||||
encodeURIComponent('')
|
||||
);
|
||||
}
|
||||
|
||||
onResult(iError, oData) {
|
||||
this.processing(false);
|
||||
this.clearing(false);
|
||||
|
||||
if (iError) {
|
||||
this.viewUser('');
|
||||
this.viewEnable_(false);
|
||||
this.twoFactorStatus(false);
|
||||
this.twoFactorTested(false);
|
||||
|
||||
this.viewSecret('');
|
||||
this.viewBackupCodes('');
|
||||
this.viewUrlTitle('');
|
||||
this.viewUrl('');
|
||||
} else {
|
||||
this.viewUser(pString(oData.Result.User));
|
||||
this.viewEnable_(!!oData.Result.Enable);
|
||||
this.twoFactorStatus(!!oData.Result.IsSet);
|
||||
this.twoFactorTested(!!oData.Result.Tested);
|
||||
|
||||
this.viewSecret(pString(oData.Result.Secret));
|
||||
this.viewBackupCodes(pString(oData.Result.BackupCodes).replace(/[\s]+/g, ' '));
|
||||
|
||||
this.viewUrlTitle(pString(oData.Result.UrlTitle));
|
||||
this.viewUrl(qr.toDataURL({ level: 'M', size: 8, value: this.getQr() }));
|
||||
}
|
||||
}
|
||||
|
||||
onShowSecretResult(iError, data) {
|
||||
this.secreting(false);
|
||||
|
||||
if (iError) {
|
||||
this.viewSecret('');
|
||||
this.viewUrlTitle('');
|
||||
this.viewUrl('');
|
||||
} else {
|
||||
this.viewSecret(pString(data.Result.Secret));
|
||||
this.viewUrlTitle(pString(data.Result.UrlTitle));
|
||||
this.viewUrl(qr.toDataURL({ level: 'M', size: 6, value: this.getQr() }));
|
||||
}
|
||||
}
|
||||
|
||||
onBuild() {
|
||||
if (this.capaTwoFactor) {
|
||||
this.processing(true);
|
||||
Remote.getTwoFactor(this.onResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { TwoFactorConfigurationPopupView, TwoFactorConfigurationPopupView as default };
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
import Remote from 'Remote/User/Fetch';
|
||||
|
||||
import { decorateKoCommands } from 'Knoin/Knoin';
|
||||
import { AbstractViewPopup } from 'Knoin/AbstractViews';
|
||||
|
||||
class TwoFactorTestPopupView extends AbstractViewPopup {
|
||||
constructor() {
|
||||
super('TwoFactorTest');
|
||||
|
||||
this.addObservables({
|
||||
code: '',
|
||||
codeStatus: null,
|
||||
|
||||
testing: false
|
||||
});
|
||||
|
||||
this.koTestedTrigger = null;
|
||||
|
||||
decorateKoCommands(this, {
|
||||
testCodeCommand: self => self.code() && !self.testing()
|
||||
});
|
||||
}
|
||||
|
||||
testCodeCommand() {
|
||||
this.testing(true);
|
||||
Remote.testTwoFactor(iError => {
|
||||
this.testing(false);
|
||||
this.codeStatus(!iError);
|
||||
|
||||
if (this.koTestedTrigger && this.codeStatus()) {
|
||||
this.koTestedTrigger(true);
|
||||
}
|
||||
}, this.code());
|
||||
}
|
||||
|
||||
clearPopup() {
|
||||
this.code('');
|
||||
this.codeStatus(null);
|
||||
this.testing(false);
|
||||
|
||||
this.koTestedTrigger = null;
|
||||
}
|
||||
|
||||
onShow(koTestedTrigger) {
|
||||
this.clearPopup();
|
||||
|
||||
this.koTestedTrigger = koTestedTrigger;
|
||||
}
|
||||
}
|
||||
|
||||
export { TwoFactorTestPopupView, TwoFactorTestPopupView as default };
|
||||
|
|
@ -43,7 +43,6 @@ class LoginUserView extends AbstractViewCenter {
|
|||
email: SettingsGet('DevEmail'),
|
||||
password: SettingsGet('DevPassword'),
|
||||
signMe: false,
|
||||
additionalCode: '',
|
||||
|
||||
emailError: false,
|
||||
passwordError: false,
|
||||
|
|
@ -56,9 +55,6 @@ class LoginUserView extends AbstractViewCenter {
|
|||
|
||||
langRequest: false,
|
||||
|
||||
additionalCodeError: false,
|
||||
additionalCodeSignMe: false,
|
||||
additionalCodeVisibility: false,
|
||||
signMeType: LoginSignMeType.Unused
|
||||
});
|
||||
|
||||
|
|
@ -84,15 +80,10 @@ class LoginUserView extends AbstractViewCenter {
|
|||
this.addSubscribables({
|
||||
email: () => {
|
||||
this.emailError(false);
|
||||
this.additionalCode('');
|
||||
this.additionalCodeVisibility(false);
|
||||
},
|
||||
|
||||
password: () => this.passwordError(false),
|
||||
|
||||
additionalCode: () => this.additionalCodeError(false),
|
||||
additionalCodeVisibility: () => this.additionalCodeError(false),
|
||||
|
||||
submitError: value => value || this.submitErrorAddidional(''),
|
||||
|
||||
signMeType: iValue => this.signMe(LoginSignMeType.DefaultOn === iValue),
|
||||
|
|
@ -121,16 +112,13 @@ class LoginUserView extends AbstractViewCenter {
|
|||
submitCommand(self, event) {
|
||||
let email = this.email().trim(),
|
||||
valid = event.target.form.reportValidity() && email,
|
||||
pass = this.password(),
|
||||
totp = this.additionalCodeVisibility(),
|
||||
code = totp ? this.additionalCode() : '';
|
||||
pass = this.password();
|
||||
|
||||
this.emailError(!email);
|
||||
this.passwordError(!pass);
|
||||
this.additionalCodeError(totp && !code);
|
||||
|
||||
let pluginResultCode = 0, pluginResultMessage = '';
|
||||
Plugins.runHook('user-login-submit', [(iResultCode, sResultMessage) => {
|
||||
runHook('user-login-submit', [(iResultCode, sResultMessage) => {
|
||||
pluginResultCode = iResultCode;
|
||||
pluginResultMessage = sResultMessage;
|
||||
}]);
|
||||
|
|
@ -156,13 +144,6 @@ class LoginUserView extends AbstractViewCenter {
|
|||
}
|
||||
this.submitError(getNotification(iError, oData.ErrorMessage, Notification.UnknownNotification));
|
||||
this.submitErrorAddidional((oData && oData.ErrorMessageAdditional) || '');
|
||||
} else if (oData.TwoFactorAuth) {
|
||||
this.submitRequest(false);
|
||||
this.additionalCode('');
|
||||
this.additionalCodeVisibility(true);
|
||||
let input = this.querySelector('.inputAdditionalCode');
|
||||
input.required = true;
|
||||
setTimeout(() => input.focus(), 100);
|
||||
} else {
|
||||
rl.route.reload();
|
||||
}
|
||||
|
|
@ -170,9 +151,7 @@ class LoginUserView extends AbstractViewCenter {
|
|||
email,
|
||||
pass,
|
||||
!!this.signMe(),
|
||||
this.bSendLanguage ? this.language() : '',
|
||||
code,
|
||||
!!(totp && this.additionalCodeSignMe())
|
||||
this.bSendLanguage ? this.language() : ''
|
||||
);
|
||||
|
||||
Local.set(ClientSideKeyName.LastSignMe, this.signMe() ? '-1-' : '-0-');
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ export class FolderListMailBoxUserView extends AbstractViewLeft {
|
|||
|
||||
this.composeInEdit = AppUserStore.composeInEdit;
|
||||
|
||||
this.messageList = MessageUserStore.list;
|
||||
this.folderList = FolderUserStore.folderList;
|
||||
this.folderListSystem = FolderUserStore.folderListSystem;
|
||||
this.foldersChanging = FolderUserStore.foldersChanging;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,6 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
constructor() {
|
||||
super('User/MailBox/MessageList', 'MailMessageList');
|
||||
|
||||
this.sLastUid = null;
|
||||
this.bPrefetch = false;
|
||||
this.emptySubjectValue = '';
|
||||
|
||||
|
|
@ -69,43 +68,34 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
|
||||
this.popupVisibility = ko.computed(() => 0 < popupVisibilityNames().length);
|
||||
|
||||
this.message = MessageUserStore.message;
|
||||
this.messageList = MessageUserStore.list;
|
||||
this.messageListDisableAutoSelect = MessageUserStore.listDisableAutoSelect;
|
||||
|
||||
this.folderList = FolderUserStore.folderList;
|
||||
this.sortSupported = FolderUserStore.sortSupported;
|
||||
|
||||
this.composeInEdit = AppUserStore.composeInEdit;
|
||||
this.leftPanelDisabled = leftPanelDisabled;
|
||||
|
||||
this.selectorMessageSelected = MessageUserStore.selectorMessageSelected;
|
||||
this.selectorMessageFocused = MessageUserStore.selectorMessageFocused;
|
||||
this.isMessageSelected = MessageUserStore.isMessageSelected;
|
||||
this.messageListSearch = MessageUserStore.listSearch;
|
||||
this.messageListThreadUid = MessageUserStore.listThreadUid;
|
||||
this.messageListError = MessageUserStore.listError;
|
||||
this.folderMenuForMove = FolderUserStore.folderMenuForMove;
|
||||
|
||||
this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList;
|
||||
|
||||
this.mainMessageListSearch = MessageUserStore.mainMessageListSearch;
|
||||
this.messageListEndFolder = MessageUserStore.listEndFolder;
|
||||
this.messageListEndThreadUid = MessageUserStore.listEndThreadUid;
|
||||
|
||||
this.messageListCheckedOrSelected = MessageUserStore.listCheckedOrSelected;
|
||||
this.messageListCheckedOrSelectedUidsWithSubMails = MessageUserStore.listCheckedOrSelectedUidsWithSubMails;
|
||||
this.messageListCompleteLoadingThrottle = MessageUserStore.listCompleteLoading;
|
||||
this.messageListCompleteLoadingThrottleForAnimation = MessageUserStore.listLoadingAnimation;
|
||||
|
||||
initOnStartOrLangChange(() => this.emptySubjectValue = i18n('MESSAGE_LIST/EMPTY_SUBJECT_TEXT'));
|
||||
|
||||
this.userQuota = QuotaUserStore.quota;
|
||||
this.userUsageSize = QuotaUserStore.usage;
|
||||
this.userUsageProc = QuotaUserStore.percentage;
|
||||
|
||||
this.addObservables({
|
||||
moveDropdownTrigger: false,
|
||||
moreDropdownTrigger: false,
|
||||
sortDropdownTrigger: false,
|
||||
|
||||
dragOverArea: null,
|
||||
dragOverBodyArea: null,
|
||||
|
|
@ -137,7 +127,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
},
|
||||
|
||||
inputProxyMessageListSearch: {
|
||||
read: this.mainMessageListSearch,
|
||||
read: MessageUserStore.mainMessageListSearch,
|
||||
write: value => this.sLastSearchValue = value
|
||||
},
|
||||
|
||||
|
|
@ -146,19 +136,19 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
return c && MessageUserStore.list.length > c;
|
||||
},
|
||||
|
||||
hasMessages: () => 0 < this.messageList.length,
|
||||
hasMessages: () => 0 < MessageUserStore.list.length,
|
||||
|
||||
isSpamFolder: () => (FolderUserStore.spamFolder() || 0) === this.messageListEndFolder(),
|
||||
isSpamFolder: () => (FolderUserStore.spamFolder() || 0) === MessageUserStore.listEndFolder(),
|
||||
|
||||
isSpamDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.spamFolder(),
|
||||
|
||||
isTrashFolder: () => (FolderUserStore.trashFolder() || 0) === this.messageListEndFolder(),
|
||||
isTrashFolder: () => (FolderUserStore.trashFolder() || 0) === MessageUserStore.listEndFolder(),
|
||||
|
||||
isDraftFolder: () => (FolderUserStore.draftFolder() || 0) === this.messageListEndFolder(),
|
||||
isDraftFolder: () => (FolderUserStore.draftFolder() || 0) === MessageUserStore.listEndFolder(),
|
||||
|
||||
isSentFolder: () => (FolderUserStore.sentFolder() || 0) === this.messageListEndFolder(),
|
||||
isSentFolder: () => (FolderUserStore.sentFolder() || 0) === MessageUserStore.listEndFolder(),
|
||||
|
||||
isArchiveFolder: () => (FolderUserStore.archiveFolder() || 0) === this.messageListEndFolder(),
|
||||
isArchiveFolder: () => (FolderUserStore.archiveFolder() || 0) === MessageUserStore.listEndFolder(),
|
||||
|
||||
isArchiveDisabled: () => UNUSED_OPTION_VALUE === FolderUserStore.archiveFolder(),
|
||||
|
||||
|
|
@ -174,17 +164,28 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
|
||||
mobileCheckedStateHide: () => ThemeStore.isMobile() ? !MessageUserStore.listChecked().length : true,
|
||||
|
||||
messageListFocused: () => Scope.MessageList === AppUserStore.focusedState()
|
||||
messageListFocused: () => Scope.MessageList === AppUserStore.focusedState(),
|
||||
|
||||
sortText: () => {
|
||||
let mode = FolderUserStore.sortMode(),
|
||||
desc = '' === mode || mode.includes('REVERSE');
|
||||
mode = mode.split(/\s+/);
|
||||
if (mode.includes('FROM')) {
|
||||
return '@' + (desc ? '⬆' : '⬇');
|
||||
}
|
||||
if (mode.includes('SUBJECT')) {
|
||||
return '𝐒' + (desc ? '⬆' : '⬇');
|
||||
}
|
||||
return (mode.includes('SIZE') ? '✉' : '📅') + (desc ? '⬇' : '⬆');
|
||||
}
|
||||
});
|
||||
|
||||
this.hasCheckedOrSelectedLines = MessageUserStore.hasCheckedOrSelected,
|
||||
|
||||
this.quotaTooltip = this.quotaTooltip.bind(this);
|
||||
|
||||
this.selector = new Selector(
|
||||
this.messageList,
|
||||
this.selectorMessageSelected,
|
||||
this.selectorMessageFocused,
|
||||
MessageUserStore.list,
|
||||
MessageUserStore.selectorMessageSelected,
|
||||
MessageUserStore.selectorMessageFocused,
|
||||
'.messageListItem .actionHandle',
|
||||
'.messageListItem .checkboxMessage',
|
||||
'.messageListItem.focused'
|
||||
|
|
@ -209,7 +210,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
addEventListener('mailbox.message.show', e => {
|
||||
const sFolder = e.detail.Folder, sUid = e.detail.Uid;
|
||||
|
||||
const message = this.messageList.find(
|
||||
const message = MessageUserStore.list.find(
|
||||
item => item && sFolder === item.folder && sUid === item.uid
|
||||
);
|
||||
|
||||
|
|
@ -246,6 +247,11 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
});
|
||||
}
|
||||
|
||||
changeSort(self, event) {
|
||||
FolderUserStore.sortMode(event.target.closest('li').dataset.sort);
|
||||
this.reloadCommand();
|
||||
}
|
||||
|
||||
clearCommand() {
|
||||
if (Settings.capa(Capa.DangerousActions)) {
|
||||
showScreenPopup(FolderClearPopupView, [FolderUserStore.currentFolder()]);
|
||||
|
|
@ -375,7 +381,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
return false;
|
||||
});
|
||||
|
||||
if (!SettingsUserStore.usePreviewPane() && !this.message()) {
|
||||
if (!SettingsUserStore.usePreviewPane() && !MessageUserStore.message()) {
|
||||
this.selector.iFocusedNextHelper = up ? -1 : 1;
|
||||
} else {
|
||||
this.selector.iSelectNextHelper = up ? -1 : 1;
|
||||
|
|
@ -391,18 +397,18 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
}
|
||||
|
||||
useAutoSelect() {
|
||||
return !this.messageListDisableAutoSelect()
|
||||
&& !/is:unseen/.test(this.mainMessageListSearch())
|
||||
return !MessageUserStore.listDisableAutoSelect()
|
||||
&& !/is:unseen/.test(MessageUserStore.mainMessageListSearch())
|
||||
&& SettingsUserStore.usePreviewPane();
|
||||
}
|
||||
|
||||
searchEnterAction() {
|
||||
this.mainMessageListSearch(this.sLastSearchValue);
|
||||
MessageUserStore.mainMessageListSearch(this.sLastSearchValue);
|
||||
this.inputMessageListSearchFocus(false);
|
||||
}
|
||||
|
||||
cancelSearch() {
|
||||
this.mainMessageListSearch('');
|
||||
MessageUserStore.mainMessageListSearch('');
|
||||
this.inputMessageListSearchFocus(false);
|
||||
}
|
||||
|
||||
|
|
@ -571,7 +577,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
}
|
||||
|
||||
flagMessages(currentMessage) {
|
||||
const checked = this.messageListCheckedOrSelected();
|
||||
const checked = MessageUserStore.listCheckedOrSelected();
|
||||
if (currentMessage) {
|
||||
const checkedUids = checked.map(message => message.uid);
|
||||
if (checkedUids.includes(currentMessage.uid)) {
|
||||
|
|
@ -591,7 +597,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
}
|
||||
|
||||
flagMessagesFast(bFlag) {
|
||||
const checked = this.messageListCheckedOrSelected();
|
||||
const checked = MessageUserStore.listCheckedOrSelected();
|
||||
if (checked.length) {
|
||||
if (undefined === bFlag) {
|
||||
const flagged = checked.filter(message => message.isFlagged());
|
||||
|
|
@ -611,7 +617,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
}
|
||||
|
||||
seenMessagesFast(seen) {
|
||||
const checked = this.messageListCheckedOrSelected();
|
||||
const checked = MessageUserStore.listCheckedOrSelected();
|
||||
if (checked.length) {
|
||||
if (undefined === seen) {
|
||||
const unseen = checked.filter(message => message.isUnseen());
|
||||
|
|
@ -656,7 +662,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
!this.messageListSearchDesc() &&
|
||||
!this.messageListError() &&
|
||||
!this.messageListEndThreadUid() &&
|
||||
this.messageList.length &&
|
||||
MessageUserStore.list.length &&
|
||||
(this.isSpamFolder() || this.isTrashFolder())
|
||||
);
|
||||
}
|
||||
|
|
@ -700,7 +706,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
|
||||
initShortcuts() {
|
||||
shortcuts.add('enter,open', '', Scope.MessageList, () => {
|
||||
if (this.message() && this.useAutoSelect()) {
|
||||
if (MessageUserStore.message() && this.useAutoSelect()) {
|
||||
dispatchEvent(new CustomEvent('mailbox.message-view.toggle-full-screen'));
|
||||
return false;
|
||||
}
|
||||
|
|
@ -756,9 +762,9 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
}
|
||||
|
||||
shortcuts.add('t', '', [Scope.MessageList], () => {
|
||||
let message = this.selectorMessageSelected();
|
||||
let message = MessageUserStore.selectorMessageSelected();
|
||||
if (!message) {
|
||||
message = this.selectorMessageFocused();
|
||||
message = MessageUserStore.selectorMessageFocused();
|
||||
}
|
||||
|
||||
if (message && 0 < message.threadsLen()) {
|
||||
|
|
@ -831,7 +837,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
return false;
|
||||
});
|
||||
shortcuts.add('tab,arrowright', '', Scope.MessageList, () => {
|
||||
this.message() && AppUserStore.focusedState(Scope.MessageView);
|
||||
MessageUserStore.message() && AppUserStore.focusedState(Scope.MessageView);
|
||||
return false;
|
||||
});
|
||||
|
||||
|
|
@ -841,7 +847,7 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
|
||||
prefetchNextTick() {
|
||||
if (!this.bPrefetch && !ifvisible.now() && this.viewModelVisible) {
|
||||
const message = this.messageList.find(
|
||||
const message = MessageUserStore.list.find(
|
||||
item => item && !hasRequestedMessage(item.folder, item.uid)
|
||||
);
|
||||
if (message) {
|
||||
|
|
@ -866,15 +872,15 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
|||
|
||||
advancedSearchClick() {
|
||||
Settings.capa(Capa.SearchAdv)
|
||||
&& showScreenPopup(AdvancedSearchPopupView, [this.mainMessageListSearch()]);
|
||||
&& showScreenPopup(AdvancedSearchPopupView, [MessageUserStore.mainMessageListSearch()]);
|
||||
}
|
||||
|
||||
quotaTooltip() {
|
||||
return i18n('MESSAGE_LIST/QUOTA_SIZE', {
|
||||
SIZE: FileInfo.friendlySize(this.userUsageSize()),
|
||||
PROC: this.userUsageProc(),
|
||||
LIMIT: FileInfo.friendlySize(this.userQuota())
|
||||
});
|
||||
SIZE: FileInfo.friendlySize(QuotaUserStore.usage()),
|
||||
PROC: QuotaUserStore.percentage(),
|
||||
LIMIT: FileInfo.friendlySize(QuotaUserStore.quota())
|
||||
}).replace(/<[^>]+>/g, '');
|
||||
}
|
||||
|
||||
initUploaderForAppend() {
|
||||
|
|
|
|||
|
|
@ -71,8 +71,6 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
|
|||
moreDropdownTrigger: false
|
||||
});
|
||||
|
||||
this.pswp = null;
|
||||
|
||||
this.moveAction = moveAction;
|
||||
|
||||
this.allowComposer = Settings.capa(Capa.Composer);
|
||||
|
|
@ -84,7 +82,6 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
|
|||
|
||||
this.message = MessageUserStore.message;
|
||||
this.hasCheckedMessages = MessageUserStore.hasCheckedMessages;
|
||||
this.messageListCheckedOrSelectedUidsWithSubMails = MessageUserStore.listCheckedOrSelectedUidsWithSubMails;
|
||||
this.messageLoadingThrottle = MessageUserStore.messageLoading;
|
||||
this.messagesBodiesDom = MessageUserStore.messagesBodiesDom;
|
||||
this.useThreads = SettingsUserStore.useThreads;
|
||||
|
|
@ -136,6 +133,8 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
|
|||
viewReplyTo: '',
|
||||
viewTimeStamp: 0,
|
||||
viewSize: '',
|
||||
viewSpamScore: 0,
|
||||
viewSpamStatus: '',
|
||||
viewLineAsCss: '',
|
||||
viewViewLink: '',
|
||||
viewUnsubscribeLink: '',
|
||||
|
|
@ -220,13 +219,15 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
|
|||
this.viewFromShort(message.fromToLine(true, true));
|
||||
this.viewFromDkimData(message.fromDkimData());
|
||||
this.viewToShort(message.toToLine(true, true));
|
||||
this.viewFrom(message.fromToLine(false));
|
||||
this.viewTo(message.toToLine(false));
|
||||
this.viewCc(message.ccToLine(false));
|
||||
this.viewBcc(message.bccToLine(false));
|
||||
this.viewReplyTo(message.replyToToLine(false));
|
||||
this.viewFrom(message.fromToLine());
|
||||
this.viewTo(message.toToLine());
|
||||
this.viewCc(message.ccToLine());
|
||||
this.viewBcc(message.bccToLine());
|
||||
this.viewReplyTo(message.replyToToLine());
|
||||
this.viewTimeStamp(message.dateTimeStampInUTC());
|
||||
this.viewSize(message.friendlySize());
|
||||
this.viewSpamScore(message.spamScore());
|
||||
this.viewSpamStatus(i18n(message.isSpam() ? 'GLOBAL/SPAM' : 'GLOBAL/NOT_SPAM') + ': ' + message.spamResult());
|
||||
this.viewLineAsCss(message.lineAsCss());
|
||||
this.viewViewLink(message.viewLink());
|
||||
this.viewUnsubscribeLink(message.getFirstUnsubsribeLink());
|
||||
|
|
@ -717,7 +718,7 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
|
|||
* @returns {string}
|
||||
*/
|
||||
printableCheckedMessageCount() {
|
||||
const cnt = this.messageListCheckedOrSelectedUidsWithSubMails().length;
|
||||
const cnt = MessageUserStore.listCheckedOrSelectedUidsWithSubMails().length;
|
||||
return 0 < cnt ? (100 > cnt ? cnt : '99+') : '';
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue