This version uses Rollup instead of WebPack.

Due to that the code is smaller and has changes to prevent Circular Dependencies
This commit is contained in:
djmaze 2021-01-25 22:00:13 +01:00
parent 5e63ade9dd
commit ad8fd8879b
49 changed files with 595 additions and 577 deletions

View file

@ -13,13 +13,22 @@ import { initOnStartOrLangChange } from 'Common/Translator';
import LanguageStore from 'Stores/Language'; import LanguageStore from 'Stores/Language';
import ThemeStore from 'Stores/Theme'; import ThemeStore from 'Stores/Theme';
import SaveTriggerComponent from 'Component/SaveTrigger';
import InputComponent from 'Component/Input';
import SelectComponent from 'Component/Select';
import TextAreaComponent from 'Component/TextArea';
import CheckboxMaterialDesignComponent from 'Component/MaterialDesign/Checkbox';
import CheckboxComponent from 'Component/Checkbox';
const Settings = rl.settings, doc = document; const Settings = rl.settings, doc = document;
export class AbstractApp { export class AbstractApp {
/** /**
* @param {RemoteStorage|AdminRemoteStorage} Remote * @param {RemoteStorage|AdminRemoteStorage} Remote
*/ */
constructor() { constructor(Remote) {
this.Remote = Remote;
const refresh = (()=>dispatchEvent(new CustomEvent('rl.auto-logout-refresh'))).debounce(5000), const refresh = (()=>dispatchEvent(new CustomEvent('rl.auto-logout-refresh'))).debounce(5000),
fn = (ev=>{ fn = (ev=>{
$htmlCL.toggle('rl-ctrl-key-pressed', ev.ctrlKey); $htmlCL.toggle('rl-ctrl-key-pressed', ev.ctrlKey);
@ -81,17 +90,15 @@ export class AbstractApp {
bootstart() { bootstart() {
const mobile = Settings.app('mobile'); const mobile = Settings.app('mobile');
ko.components.register('SaveTrigger', require('Component/SaveTrigger').default); ko.components.register('SaveTrigger', SaveTriggerComponent);
ko.components.register('Input', require('Component/Input').default); ko.components.register('Input', InputComponent);
ko.components.register('Select', require('Component/Select').default); ko.components.register('Select', SelectComponent);
ko.components.register('TextArea', require('Component/TextArea').default); ko.components.register('TextArea', TextAreaComponent);
ko.components.register('CheckboxSimple', CheckboxComponent);
if (Settings.app('materialDesign') && !rl.settings.app('mobile')) { if (Settings.app('materialDesign') && !rl.settings.app('mobile')) {
ko.components.register('Checkbox', require('Component/MaterialDesign/Checkbox').default); ko.components.register('Checkbox', CheckboxMaterialDesignComponent);
ko.components.register('CheckboxSimple', require('Component/Checkbox').default);
} else { } else {
ko.components.register('Checkbox', require('Component/Checkbox').default); ko.components.register('Checkbox', CheckboxComponent);
ko.components.register('CheckboxSimple', require('Component/Checkbox').default);
} }
initOnStartOrLangChange(); initOnStartOrLangChange();

View file

@ -1,3 +1,5 @@
import ko from 'External/User/ko'; // eslint-disable-line no-unused-vars
import { pInt, pString } from 'Common/Utils'; import { pInt, pString } from 'Common/Utils';
import { isPosNumeric, delegateRunOnDestroy, mailToHelper } from 'Common/UtilsUser'; import { isPosNumeric, delegateRunOnDestroy, mailToHelper } from 'Common/UtilsUser';
@ -67,7 +69,10 @@ import { startScreens, showScreenPopup } from 'Knoin/Knoin';
import { AbstractApp } from 'App/Abstract'; import { AbstractApp } from 'App/Abstract';
require('External/User/ko'); import { ComposePopupView } from 'View/Popup/Compose';
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
import { AskPopupView } from 'View/Popup/Ask';
import { TwoFactorConfigurationPopupView } from 'View/Popup/TwoFactorConfiguration';
const doc = document, const doc = document,
Settings = rl.settings; Settings = rl.settings;
@ -329,13 +334,13 @@ class AppUser extends AbstractApp {
} }
if (!oMoveFolder && bUseFolder) { if (!oMoveFolder && bUseFolder) {
showScreenPopup(require('View/Popup/FolderSystem'), [nSetSystemFoldersNotification]); showScreenPopup(FolderSystemPopupView, [nSetSystemFoldersNotification]);
} else if ( } else if (
!bUseFolder || !bUseFolder ||
(FolderType.Trash === iDeleteType && (FolderType.Trash === iDeleteType &&
(sFromFolderFullNameRaw === FolderStore.spamFolder() || sFromFolderFullNameRaw === FolderStore.trashFolder())) (sFromFolderFullNameRaw === FolderStore.spamFolder() || sFromFolderFullNameRaw === FolderStore.trashFolder()))
) { ) {
showScreenPopup(require('View/Popup/Ask'), [ showScreenPopup(AskPopupView, [
i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'),
() => { () => {
this.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove); this.messagesDeleteHelper(sFromFolderFullNameRaw, aUidForRemove);
@ -918,7 +923,7 @@ class AppUser extends AbstractApp {
Settings.get('RequireTwoFactor') Settings.get('RequireTwoFactor')
) { ) {
this.bootend(); this.bootend();
showScreenPopup(require('View/Popup/TwoFactorConfiguration'), [true]); showScreenPopup(TwoFactorConfigurationPopupView, [true]);
} else { } else {
rl.setWindowTitle(i18n('GLOBAL/LOADING')); rl.setWindowTitle(i18n('GLOBAL/LOADING'));
@ -1022,7 +1027,7 @@ class AppUser extends AbstractApp {
} catch (e) {} // eslint-disable-line no-empty } catch (e) {} // eslint-disable-line no-empty
if (Settings.get('MailToEmail')) { if (Settings.get('MailToEmail')) {
mailToHelper(Settings.get('MailToEmail'), require('View/Popup/Compose')); mailToHelper(Settings.get('MailToEmail'), ComposePopupView);
} }
}, 500); }, 500);
} }
@ -1047,6 +1052,11 @@ class AppUser extends AbstractApp {
setInterval(() => dispatchEvent(new CustomEvent('reload-time')), 60000); setInterval(() => dispatchEvent(new CustomEvent('reload-time')), 60000);
} }
showComposePopupView(params = [])
{
showScreenPopup(ComposePopupView, params);
}
} }
export default new AppUser(); export default new AppUser();

View file

@ -1,5 +1,23 @@
import { createCKEditor } from 'External/CKEditor.js'; import { createCKEditor } from 'External/CKEditor.js';
const
htmlre = /[&<>"']/g,
htmlmap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;'
};
/**
* @param {string} text
* @returns {string}
*/
export function encodeHtml(text) {
return (text && text.toString ? text.toString() : ''+text).replace(htmlre, m => htmlmap[m]);
}
class HtmlEditor { class HtmlEditor {
editor; editor;
blurTimer = 0; blurTimer = 0;

View file

@ -1,3 +1,5 @@
import * as Knoin from 'Knoin/Knoin';
const USER_VIEW_MODELS_HOOKS = [], const USER_VIEW_MODELS_HOOKS = [],
ADMIN_VIEW_MODELS_HOOKS = []; ADMIN_VIEW_MODELS_HOOKS = [];
@ -45,9 +47,8 @@ export function addSettingsViewModelForAdmin(SettingsViewModelClass, template, l
* @param {boolean} admin * @param {boolean} admin
*/ */
export function runSettingsViewModelHooks(admin) { export function runSettingsViewModelHooks(admin) {
const Knoin = require('Knoin/Knoin');
(admin ? ADMIN_VIEW_MODELS_HOOKS : USER_VIEW_MODELS_HOOKS).forEach(view => { (admin ? ADMIN_VIEW_MODELS_HOOKS : USER_VIEW_MODELS_HOOKS).forEach(view => {
Knoin.addSettingsViewModel(view[0], view[1], view[2], view[3]); Knoin.settingsAddViewModel(view[0], view[1], view[2], view[3]);
}); });
} }

View file

@ -160,3 +160,17 @@ export function reload(admin, language) {
doc.head.append(script); doc.head.append(script);
}); });
} }
/**
*
* @param {string} language
* @param {boolean=} isEng = false
* @returns {string}
*/
export function convertLangName(language, isEng = false) {
return i18n(
'LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/LANG_' + language.toUpperCase().replace(/[^a-zA-Z0-9]+/g, '_'),
null,
language
);
}

View file

@ -49,20 +49,6 @@ export const convertThemeName = theme => {
.trim(); .trim();
}; };
/**
*
* @param {string} language
* @param {boolean=} isEng = false
* @returns {string}
*/
export function convertLangName(language, isEng = false) {
return require('Common/Translator').i18n(
'LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/LANG_' + language.toUpperCase().replace(/[^a-zA-Z0-9]+/g, '_'),
null,
language
);
}
/** /**
* @param {object} domOption * @param {object} domOption
* @param {object} item * @param {object} item

View file

@ -1,16 +1,11 @@
import { ComposeType, FolderType } from 'Common/EnumsUser'; import { ComposeType, FolderType } from 'Common/EnumsUser';
import { EmailModel } from 'Model/Email';
import { showScreenPopup } from 'Knoin/Knoin';
import { encodeHtml } from 'Common/Html';
const const
tpl = document.createElement('template'), tpl = document.createElement('template'),
isArray = Array.isArray, isArray = Array.isArray;
htmlmap = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#x27;'
},
htmlspecialchars = str => (''+str).replace(/[&<>"']/g, m => htmlmap[m]);
/** /**
* @param {(string|number)} value * @param {(string|number)} value
@ -21,14 +16,6 @@ export function isPosNumeric(value, includeZero = true) {
return null != value && (includeZero ? /^[0-9]*$/ : /^[1-9]+[0-9]*$/).test(value.toString()); return null != value && (includeZero ? /^[0-9]*$/ : /^[1-9]+[0-9]*$/).test(value.toString());
} }
/**
* @param {string} text
* @returns {string}
*/
export function encodeHtml(text) {
return null != text ? htmlspecialchars(text.toString()) : '';
}
/** /**
* @param {string} text * @param {string} text
* @param {number=} len = 100 * @param {number=} len = 100
@ -101,7 +88,7 @@ export function htmlToPlain(html) {
.replace(/[\n]/gm, '<br />') .replace(/[\n]/gm, '<br />')
.replace(/[\r]/gm, '') .replace(/[\r]/gm, '')
: '', : '',
fixAttibuteValue = (...args) => (args && 1 < args.length ? '' + args[1] + htmlspecialchars(args[2]) : ''), fixAttibuteValue = (...args) => (args && 1 < args.length ? '' + args[1] + encodeHtml(args[2]) : ''),
convertLinks = (...args) => (args && 1 < args.length ? args[1].trim() : ''); convertLinks = (...args) => (args && 1 < args.length ? args[1].trim() : '');
tpl.innerHTML = html tpl.innerHTML = html
@ -470,8 +457,7 @@ export function mailToHelper(mailToUrl, PopupComposeViewModel) {
params = {}; params = {};
const email = mailToUrl.replace(/\?.+$/, ''), const email = mailToUrl.replace(/\?.+$/, ''),
query = mailToUrl.replace(/^[^?]*\?/, ''), query = mailToUrl.replace(/^[^?]*\?/, '');
EmailModel = require('Model/Email').default;
query.split('&').forEach(temp => { query.split('&').forEach(temp => {
temp = temp.split('='); temp = temp.split('=');
@ -506,7 +492,7 @@ export function mailToHelper(mailToUrl, PopupComposeViewModel) {
bcc = EmailModel.parseEmailLine(decodeURIComponent(params.bcc)); bcc = EmailModel.parseEmailLine(decodeURIComponent(params.bcc));
} }
require('Knoin/Knoin').showScreenPopup(PopupComposeViewModel, [ showScreenPopup(PopupComposeViewModel, [
ComposeType.Empty, ComposeType.Empty,
null, null,
to, to,

View file

@ -1,6 +1,6 @@
import { SaveSettingsStep } from 'Common/Enums'; import { SaveSettingsStep } from 'Common/Enums';
import { pInt } from 'Common/Utils';
const ko = window.ko; import ko from 'External/ko';
ko.bindingHandlers.saveTrigger = { ko.bindingHandlers.saveTrigger = {
init: (element) => { init: (element) => {
@ -38,11 +38,10 @@ ko.extenders.idleTrigger = (target) => {
}; };
ko.extenders.posInterer = (target, defaultVal) => { ko.extenders.posInterer = (target, defaultVal) => {
const Utils = require('Common/Utils'), const result = ko.computed({
result = ko.computed({
read: target, read: target,
write: newValue => { write: newValue => {
let val = Utils.pInt(newValue.toString(), defaultVal); let val = pInt(newValue.toString(), defaultVal);
if (0 >= val) { if (0 >= val) {
val = defaultVal; val = defaultVal;
} }

View file

@ -1,6 +1,9 @@
const ko = window.ko, import ko from 'External/ko';
import { HtmlEditor } from 'Common/Html';
import { timeToNode } from 'Common/Momentor';
import { EmailModel } from 'Model/Email';
rlContentType = 'snappymail/action', const rlContentType = 'snappymail/action',
// In Chrome we have no access to dataTransfer.getData unless it's the 'drop' event // In Chrome we have no access to dataTransfer.getData unless it's the 'drop' event
// In Chrome Mobile dataTransfer.types.includes(rlContentType) fails, only text/plain is set // In Chrome Mobile dataTransfer.types.includes(rlContentType) fails, only text/plain is set
@ -30,7 +33,6 @@ ko.bindingHandlers.editor = {
let editor = null; let editor = null;
const fValue = fValueAccessor(), const fValue = fValueAccessor(),
HtmlEditor = require('Common/HtmlEditor').default,
fUpdateEditorValue = () => fValue && fValue.__editor && fValue.__editor.setHtmlOrPlain(fValue()), fUpdateEditorValue = () => fValue && fValue.__editor && fValue.__editor.setHtmlOrPlain(fValue()),
fUpdateKoValue = () => fValue && fValue.__editor && fValue(fValue.__editor.getDataWithHtmlMark()), fUpdateKoValue = () => fValue && fValue.__editor && fValue(fValue.__editor.getDataWithHtmlMark()),
fOnReady = () => { fOnReady = () => {
@ -51,7 +53,7 @@ ko.bindingHandlers.editor = {
} }
}; };
let ttn = (element, fValueAccessor) => require('Common/Momentor').timeToNode(element, ko.unwrap(fValueAccessor())); let ttn = (element, fValueAccessor) => timeToNode(element, ko.unwrap(fValueAccessor()));
ko.bindingHandlers.moment = { ko.bindingHandlers.moment = {
init: ttn, init: ttn,
update: ttn update: ttn
@ -59,8 +61,7 @@ ko.bindingHandlers.moment = {
ko.bindingHandlers.emailsTags = { ko.bindingHandlers.emailsTags = {
init: (element, fValueAccessor, fAllBindingsAccessor) => { init: (element, fValueAccessor, fAllBindingsAccessor) => {
const EmailModel = require('Model/Email').default, const fValue = fValueAccessor(),
fValue = fValueAccessor(),
fAllBindings = fAllBindingsAccessor(), fAllBindings = fAllBindingsAccessor(),
inputDelimiters = [',', ';', '\n']; inputDelimiters = [',', ';', '\n'];

23
dev/External/ko.js vendored
View file

@ -1,32 +1,31 @@
import { i18n, i18nToNodes, trigger } from 'Common/Translator';
import { dropdownVisibility } from 'Common/Globals';
const const
doc = document, doc = document,
ko = window.ko,
Translator = () => require('Common/Translator'),
Globals = () => require('Common/Globals'),
isFunction = v => typeof v === 'function', isFunction = v => typeof v === 'function',
koValue = value => !ko.isObservable(value) && isFunction(value) ? value() : ko.unwrap(value); koValue = value => !ko.isObservable(value) && isFunction(value) ? value() : ko.unwrap(value);
ko.bindingHandlers.tooltip = { ko.bindingHandlers.tooltip = {
init: (element, fValueAccessor) => { init: (element, fValueAccessor) => {
const Global = Globals();
const sValue = koValue(fValueAccessor()); const sValue = koValue(fValueAccessor());
if ('off' === element.dataset.tooltipI18n) { if ('off' === element.dataset.tooltipI18n) {
element.title = sValue; element.title = sValue;
} else { } else {
element.title = Translator().i18n(sValue); element.title = i18n(sValue);
Translator().trigger.subscribe(() => trigger.subscribe(() =>
element.title = Translator().i18n(sValue) element.title = i18n(sValue)
); );
Global.dropdownVisibility.subscribe(() => dropdownVisibility.subscribe(() =>
element.title = Translator().i18n(sValue) element.title = i18n(sValue)
); );
} }
}, },
update: (element, fValueAccessor) => { update: (element, fValueAccessor) => {
const sValue = koValue(fValueAccessor()); const sValue = koValue(fValueAccessor());
if (sValue) { if (sValue) {
element.title = 'off' === element.dataset.tooltipI18n ? sValue : Translator().i18n(sValue); element.title = 'off' === element.dataset.tooltipI18n ? sValue : i18n(sValue);
} else { } else {
element.title = ''; element.title = '';
} }
@ -111,13 +110,13 @@ ko.bindingHandlers.modal = {
}; };
ko.bindingHandlers.i18nInit = { ko.bindingHandlers.i18nInit = {
init: element => Translator().i18nToNodes(element) init: element => i18nToNodes(element)
}; };
ko.bindingHandlers.i18nUpdate = { ko.bindingHandlers.i18nUpdate = {
update: (element, fValueAccessor) => { update: (element, fValueAccessor) => {
ko.unwrap(fValueAccessor()); ko.unwrap(fValueAccessor());
Translator().i18nToNodes(element); i18nToNodes(element);
} }
}; };

View file

@ -58,7 +58,7 @@ export function createCommand(fExecute, fCanExecute = true) {
* @param {boolean=} isDefault = false * @param {boolean=} isDefault = false
* @returns {void} * @returns {void}
*/ */
export function addSettingsViewModel(SettingsViewModelClass, template, labelName, route, isDefault = false) { export function settingsAddViewModel(SettingsViewModelClass, template, labelName, route, isDefault = false) {
SettingsViewModelClass.__rlSettingsData = { SettingsViewModelClass.__rlSettingsData = {
Label: labelName, Label: labelName,
Template: template, Template: template,

View file

@ -1,4 +1,4 @@
import { encodeHtml } from 'Common/UtilsUser'; import { encodeHtml } from 'Common/Html';
import { AbstractModel } from 'Knoin/AbstractModel'; import { AbstractModel } from 'Knoin/AbstractModel';

View file

@ -1,227 +0,0 @@
import ko from 'ko';
import { FolderType } from 'Common/EnumsUser';
import { isPosNumeric } from 'Common/UtilsUser';
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
import { AbstractModel } from 'Knoin/AbstractModel';
import { FolderCollectionModel } from 'Model/FolderCollection';
function getSystemFolderName(type, def)
{
switch (type) {
case FolderType.Inbox:
return i18n('FOLDER_LIST/INBOX_NAME');
case FolderType.SentItems:
return i18n('FOLDER_LIST/SENT_NAME');
case FolderType.Draft:
return i18n('FOLDER_LIST/DRAFTS_NAME');
case FolderType.Spam:
return i18n('GLOBAL/SPAM');
case FolderType.Trash:
return i18n('FOLDER_LIST/TRASH_NAME');
case FolderType.Archive:
return i18n('FOLDER_LIST/ARCHIVE_NAME');
// no default
}
return def;
}
export class FolderModel extends AbstractModel {
constructor() {
super();
this.fullName = '';
this.fullNameRaw = '';
this.fullNameHash = '';
this.delimiter = '';
this.namespace = '';
this.deep = 0;
this.interval = 0;
this.selectable = false;
this.exists = true;
this.addObservables({
name: '',
type: FolderType.User,
focused: false,
selected: false,
edited: false,
subscribed: true,
checkable: false,
deleteAccess: false,
nameForEdit: '',
privateMessageCountAll: 0,
privateMessageCountUnread: 0,
collapsedPrivate: true
});
this.subFolders = ko.observableArray(new FolderCollectionModel);
this.actionBlink = ko.observable(false).extend({ falseTimeout: 1000 });
}
/**
* @static
* @param {FetchJsonFolder} json
* @returns {?FolderModel}
*/
static reviveFromJson(json) {
const folder = super.reviveFromJson(json);
if (folder) {
folder.deep = json.FullNameRaw.split(folder.delimiter).length - 1;
folder.messageCountAll = ko.computed({
read: folder.privateMessageCountAll,
write: (iValue) => {
if (isPosNumeric(iValue, true)) {
folder.privateMessageCountAll(iValue);
} else {
folder.privateMessageCountAll.valueHasMutated();
}
}
})
.extend({ notify: 'always' });
folder.messageCountUnread = ko.computed({
read: folder.privateMessageCountUnread,
write: (value) => {
if (isPosNumeric(value, true)) {
folder.privateMessageCountUnread(value);
} else {
folder.privateMessageCountUnread.valueHasMutated();
}
}
})
.extend({ notify: 'always' });
folder.addComputables({
isInbox: () => FolderType.Inbox === folder.type(),
hasSubscribedSubfolders:
() =>
!!folder.subFolders.find(
oFolder => (oFolder.subscribed() || oFolder.hasSubscribedSubfolders()) && !oFolder.isSystemFolder()
),
canBeEdited: () => FolderType.User === folder.type() && folder.exists && folder.selectable,
visible: () => {
const isSubscribed = folder.subscribed(),
isSubFolders = folder.hasSubscribedSubfolders();
return isSubscribed || (isSubFolders && (!folder.exists || !folder.selectable));
},
isSystemFolder: () => FolderType.User !== folder.type(),
hidden: () => {
const isSystem = folder.isSystemFolder(),
isSubFolders = folder.hasSubscribedSubfolders();
return (isSystem && !isSubFolders) || (!folder.selectable && !isSubFolders);
},
printableUnreadCount: () => {
const count = folder.messageCountAll(),
unread = folder.messageCountUnread(),
type = folder.type();
if (0 < count) {
if (FolderType.Draft === type) {
return '' + count;
}
if (
0 < unread &&
FolderType.Trash !== type &&
FolderType.Archive !== type &&
FolderType.SentItems !== type
) {
return '' + unread;
}
}
return '';
},
canBeDeleted: () => !folder.isSystemFolder() && !folder.subFolders.length,
selectableForFolderList: () => !folder.isSystemFolder() && folder.selectable,
canBeSubscribed: () => !folder.isSystemFolder() && folder.selectable,
canBeChecked: () => !folder.isSystemFolder() && folder.selectable,
localName: () => {
let name = folder.name();
if (folder.isSystemFolder()) {
translatorTrigger();
name = getSystemFolderName(folder.type(), name);
}
return name;
},
manageFolderSystemName: () => {
if (folder.isSystemFolder()) {
translatorTrigger();
let suffix = getSystemFolderName(folder.type(), '');
if (folder.name() !== suffix && 'inbox' !== suffix.toLowerCase()) {
return '(' + suffix + ')';
}
}
return '';
},
collapsed: {
read: () => !folder.hidden() && folder.collapsedPrivate(),
write: (value) => {
folder.collapsedPrivate(value);
}
},
hasUnreadMessages: () => 0 < folder.messageCountUnread() && folder.printableUnreadCount(),
hasSubscribedUnreadMessagesSubfolders: () =>
!!folder.subFolders.find(
folder => folder.hasUnreadMessages() || folder.hasSubscribedUnreadMessagesSubfolders()
)
});
folder.addSubscribables({
name: value => folder.nameForEdit(value),
edited: value => value && folder.nameForEdit(folder.name()),
messageCountUnread: unread => {
if (FolderType.Inbox === folder.type()) {
dispatchEvent(new CustomEvent('mailbox.inbox-unread-count', {detail:unread}));
}
}
});
}
return folder;
}
/**
* @returns {string}
*/
collapsedCss() {
return 'e-collapsed-sign ' + (this.hasSubscribedSubfolders()
? (this.collapsed() ? 'icon-right-mini' : 'icon-down-mini')
: 'icon-none'
);
}
/**
* @returns {string}
*/
printableFullName() {
return this.fullName.split(this.delimiter).join(' / ');
}
}

View file

@ -10,11 +10,12 @@ import * as Local from 'Storage/Client';
import AppStore from 'Stores/User/App'; import AppStore from 'Stores/User/App';
import FolderStore from 'Stores/User/Folder'; import FolderStore from 'Stores/User/Folder';
import { FolderModel } from 'Model/Folder'; import ko from 'ko';
import Remote from 'Remote/User/Fetch'; import { isPosNumeric } from 'Common/UtilsUser';
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
'use strict'; import { AbstractModel } from 'Knoin/AbstractModel';
const Settings = rl.settings, const Settings = rl.settings,
@ -141,7 +142,7 @@ export class FolderCollectionModel extends AbstractCollectionModel
FolderStore.archiveFolder(normalizeFolder(Settings.get('ArchiveFolder'))); FolderStore.archiveFolder(normalizeFolder(Settings.get('ArchiveFolder')));
if (update) { if (update) {
Remote.saveSystemFolders(()=>{}, { rl.app.Remote.saveSystemFolders(()=>{}, {
SentFolder: FolderStore.sentFolder(), SentFolder: FolderStore.sentFolder(),
DraftFolder: FolderStore.draftFolder(), DraftFolder: FolderStore.draftFolder(),
SpamFolder: FolderStore.spamFolder(), SpamFolder: FolderStore.spamFolder(),
@ -155,3 +156,222 @@ export class FolderCollectionModel extends AbstractCollectionModel
} }
} }
function getSystemFolderName(type, def)
{
switch (type) {
case FolderType.Inbox:
return i18n('FOLDER_LIST/INBOX_NAME');
case FolderType.SentItems:
return i18n('FOLDER_LIST/SENT_NAME');
case FolderType.Draft:
return i18n('FOLDER_LIST/DRAFTS_NAME');
case FolderType.Spam:
return i18n('GLOBAL/SPAM');
case FolderType.Trash:
return i18n('FOLDER_LIST/TRASH_NAME');
case FolderType.Archive:
return i18n('FOLDER_LIST/ARCHIVE_NAME');
// no default
}
return def;
}
export class FolderModel extends AbstractModel {
constructor() {
super();
this.fullName = '';
this.fullNameRaw = '';
this.fullNameHash = '';
this.delimiter = '';
this.namespace = '';
this.deep = 0;
this.interval = 0;
this.selectable = false;
this.exists = true;
this.addObservables({
name: '',
type: FolderType.User,
focused: false,
selected: false,
edited: false,
subscribed: true,
checkable: false,
deleteAccess: false,
nameForEdit: '',
privateMessageCountAll: 0,
privateMessageCountUnread: 0,
collapsedPrivate: true
});
this.subFolders = ko.observableArray(new FolderCollectionModel);
this.actionBlink = ko.observable(false).extend({ falseTimeout: 1000 });
}
/**
* @static
* @param {FetchJsonFolder} json
* @returns {?FolderModel}
*/
static reviveFromJson(json) {
const folder = super.reviveFromJson(json);
if (folder) {
folder.deep = json.FullNameRaw.split(folder.delimiter).length - 1;
folder.messageCountAll = ko.computed({
read: folder.privateMessageCountAll,
write: (iValue) => {
if (isPosNumeric(iValue, true)) {
folder.privateMessageCountAll(iValue);
} else {
folder.privateMessageCountAll.valueHasMutated();
}
}
})
.extend({ notify: 'always' });
folder.messageCountUnread = ko.computed({
read: folder.privateMessageCountUnread,
write: (value) => {
if (isPosNumeric(value, true)) {
folder.privateMessageCountUnread(value);
} else {
folder.privateMessageCountUnread.valueHasMutated();
}
}
})
.extend({ notify: 'always' });
folder.addComputables({
isInbox: () => FolderType.Inbox === folder.type(),
hasSubscribedSubfolders:
() =>
!!folder.subFolders.find(
oFolder => (oFolder.subscribed() || oFolder.hasSubscribedSubfolders()) && !oFolder.isSystemFolder()
),
canBeEdited: () => FolderType.User === folder.type() && folder.exists && folder.selectable,
visible: () => {
const isSubscribed = folder.subscribed(),
isSubFolders = folder.hasSubscribedSubfolders();
return isSubscribed || (isSubFolders && (!folder.exists || !folder.selectable));
},
isSystemFolder: () => FolderType.User !== folder.type(),
hidden: () => {
const isSystem = folder.isSystemFolder(),
isSubFolders = folder.hasSubscribedSubfolders();
return (isSystem && !isSubFolders) || (!folder.selectable && !isSubFolders);
},
printableUnreadCount: () => {
const count = folder.messageCountAll(),
unread = folder.messageCountUnread(),
type = folder.type();
if (0 < count) {
if (FolderType.Draft === type) {
return '' + count;
}
if (
0 < unread &&
FolderType.Trash !== type &&
FolderType.Archive !== type &&
FolderType.SentItems !== type
) {
return '' + unread;
}
}
return '';
},
canBeDeleted: () => !folder.isSystemFolder() && !folder.subFolders.length,
selectableForFolderList: () => !folder.isSystemFolder() && folder.selectable,
canBeSubscribed: () => !folder.isSystemFolder() && folder.selectable,
canBeChecked: () => !folder.isSystemFolder() && folder.selectable,
localName: () => {
let name = folder.name();
if (folder.isSystemFolder()) {
translatorTrigger();
name = getSystemFolderName(folder.type(), name);
}
return name;
},
manageFolderSystemName: () => {
if (folder.isSystemFolder()) {
translatorTrigger();
let suffix = getSystemFolderName(folder.type(), '');
if (folder.name() !== suffix && 'inbox' !== suffix.toLowerCase()) {
return '(' + suffix + ')';
}
}
return '';
},
collapsed: {
read: () => !folder.hidden() && folder.collapsedPrivate(),
write: (value) => {
folder.collapsedPrivate(value);
}
},
hasUnreadMessages: () => 0 < folder.messageCountUnread() && folder.printableUnreadCount(),
hasSubscribedUnreadMessagesSubfolders: () =>
!!folder.subFolders.find(
folder => folder.hasUnreadMessages() || folder.hasSubscribedUnreadMessagesSubfolders()
)
});
folder.addSubscribables({
name: value => folder.nameForEdit(value),
edited: value => value && folder.nameForEdit(folder.name()),
messageCountUnread: unread => {
if (FolderType.Inbox === folder.type()) {
dispatchEvent(new CustomEvent('mailbox.inbox-unread-count', {detail:unread}));
}
}
});
}
return folder;
}
/**
* @returns {string}
*/
collapsedCss() {
return 'e-collapsed-sign ' + (this.hasSubscribedSubfolders()
? (this.collapsed() ? 'icon-right-mini' : 'icon-down-mini')
: 'icon-none'
);
}
/**
* @returns {string}
*/
printableFullName() {
return this.fullName.split(this.delimiter).join(' / ');
}
}

View file

@ -3,7 +3,7 @@ import ko from 'ko';
import { MessagePriority } from 'Common/EnumsUser'; import { MessagePriority } from 'Common/EnumsUser';
import { i18n } from 'Common/Translator'; import { i18n } from 'Common/Translator';
import { encodeHtml } from 'Common/UtilsUser'; import { encodeHtml } from 'Common/Html';
import { messageViewLink, messageDownloadLink } from 'Common/Links'; import { messageViewLink, messageDownloadLink } from 'Common/Links';
@ -14,6 +14,8 @@ import { AttachmentCollectionModel } from 'Model/AttachmentCollection';
import { EmailCollectionModel } from 'Model/EmailCollection'; import { EmailCollectionModel } from 'Model/EmailCollection';
import { AbstractModel } from 'Knoin/AbstractModel'; import { AbstractModel } from 'Knoin/AbstractModel';
import PreviewHTML from 'Html/PreviewMessage.html';
const isArray = Array.isArray, const isArray = Array.isArray,
SignedVerifyStatus = { SignedVerifyStatus = {
@ -379,9 +381,8 @@ export class MessageModel extends AbstractModel {
ccLine = this.ccToLine(false), ccLine = this.ccToLine(false),
m = 0 < timeStampInUTC ? new Date(timeStampInUTC * 1000) : null, m = 0 < timeStampInUTC ? new Date(timeStampInUTC * 1000) : null,
win = open(''), win = open(''),
doc = win.document, doc = win.document;
html = require('Html/PreviewMessage.html'); doc.write(PreviewHTML
doc.write((html.default)
.replace(/{{subject}}/g, encodeHtml(this.subject())) .replace(/{{subject}}/g, encodeHtml(this.subject()))
.replace('{{date}}', encodeHtml(m ? m.format('LLL') : '')) .replace('{{date}}', encodeHtml(m ? m.format('LLL') : ''))
.replace('{{fromCreds}}', encodeHtml(this.fromToLine(false))) .replace('{{fromCreds}}', encodeHtml(this.fromToLine(false)))

View file

@ -1,4 +1,4 @@
import { addSettingsViewModel } from 'Knoin/Knoin'; import { settingsAddViewModel } from 'Knoin/Knoin';
import { runSettingsViewModelHooks } from 'Common/Plugins'; import { runSettingsViewModelHooks } from 'Common/Plugins';
import { AbstractSettingsScreen } from 'Screen/AbstractSettings'; import { AbstractSettingsScreen } from 'Screen/AbstractSettings';
@ -25,7 +25,7 @@ export class SettingsAdminScreen extends AbstractSettingsScreen {
* @param {Function=} fCallback = null * @param {Function=} fCallback = null
*/ */
setupSettings(fCallback = null) { setupSettings(fCallback = null) {
addSettingsViewModel( settingsAddViewModel(
GeneralAdminSettings, GeneralAdminSettings,
'AdminSettingsGeneral', 'AdminSettingsGeneral',
'TABS_LABELS/LABEL_GENERAL_NAME', 'TABS_LABELS/LABEL_GENERAL_NAME',
@ -43,7 +43,7 @@ export class SettingsAdminScreen extends AbstractSettingsScreen {
[PackagesAdminSettings, 'Packages'], [PackagesAdminSettings, 'Packages'],
[AboutAdminSettings, 'About'], [AboutAdminSettings, 'About'],
].forEach(item => ].forEach(item =>
addSettingsViewModel( settingsAddViewModel(
item[0], item[0],
'AdminSettings'+item[1], 'AdminSettings'+item[1],
'TABS_LABELS/LABEL_'+item[1].toUpperCase()+'_NAME', 'TABS_LABELS/LABEL_'+item[1].toUpperCase()+'_NAME',

View file

@ -20,6 +20,8 @@ import { warmUpScreenPopup } from 'Knoin/Knoin';
import { AbstractScreen } from 'Knoin/AbstractScreen'; import { AbstractScreen } from 'Knoin/AbstractScreen';
import { ComposePopupView } from 'View/Popup/Compose';
const Settings = rl.settings; const Settings = rl.settings;
export class MailBoxUserScreen extends AbstractScreen { export class MailBoxUserScreen extends AbstractScreen {
@ -101,7 +103,7 @@ export class MailBoxUserScreen extends AbstractScreen {
*/ */
onStart() { onStart() {
setTimeout(() => SettingsStore.layout.valueHasMutated(), 50); setTimeout(() => SettingsStore.layout.valueHasMutated(), 50);
setTimeout(() => warmUpScreenPopup(require('View/Popup/Compose')), 500); setTimeout(() => warmUpScreenPopup(ComposePopupView), 500);
addEventListener('mailbox.inbox-unread-count', e => { addEventListener('mailbox.inbox-unread-count', e => {
FolderStore.foldersInboxUnreadCount(e.detail); FolderStore.foldersInboxUnreadCount(e.detail);

View file

@ -6,7 +6,7 @@ import { initOnStartOrLangChange, i18n } from 'Common/Translator';
import AppStore from 'Stores/User/App'; import AppStore from 'Stores/User/App';
import AccountStore from 'Stores/User/Account'; import AccountStore from 'Stores/User/Account';
import { addSettingsViewModel } from 'Knoin/Knoin'; import { settingsAddViewModel } from 'Knoin/Knoin';
import { AbstractSettingsScreen } from 'Screen/AbstractSettings'; import { AbstractSettingsScreen } from 'Screen/AbstractSettings';
@ -48,14 +48,14 @@ export class SettingsUserScreen extends AbstractSettingsScreen {
return false; return false;
} }
addSettingsViewModel(GeneralUserSettings, 'SettingsGeneral', 'SETTINGS_LABELS/LABEL_GENERAL_NAME', 'general', true); settingsAddViewModel(GeneralUserSettings, 'SettingsGeneral', 'SETTINGS_LABELS/LABEL_GENERAL_NAME', 'general', true);
if (AppStore.contactsIsAllowed()) { if (AppStore.contactsIsAllowed()) {
addSettingsViewModel(ContactsUserSettings, 'SettingsContacts', 'SETTINGS_LABELS/LABEL_CONTACTS_NAME', 'contacts'); settingsAddViewModel(ContactsUserSettings, 'SettingsContacts', 'SETTINGS_LABELS/LABEL_CONTACTS_NAME', 'contacts');
} }
if (Settings.capa(Capa.AdditionalAccounts) || Settings.capa(Capa.Identities)) { if (Settings.capa(Capa.AdditionalAccounts) || Settings.capa(Capa.Identities)) {
addSettingsViewModel( settingsAddViewModel(
AccountsUserSettings, AccountsUserSettings,
'SettingsAccounts', 'SettingsAccounts',
Settings.capa(Capa.AdditionalAccounts) Settings.capa(Capa.AdditionalAccounts)
@ -66,15 +66,15 @@ export class SettingsUserScreen extends AbstractSettingsScreen {
} }
if (Settings.capa(Capa.Sieve)) { if (Settings.capa(Capa.Sieve)) {
addSettingsViewModel(FiltersUserSettings, 'SettingsFilters', 'SETTINGS_LABELS/LABEL_FILTERS_NAME', 'filters'); settingsAddViewModel(FiltersUserSettings, 'SettingsFilters', 'SETTINGS_LABELS/LABEL_FILTERS_NAME', 'filters');
} }
if (Settings.capa(Capa.AutoLogout) || Settings.capa(Capa.TwoFactor)) { if (Settings.capa(Capa.AutoLogout) || Settings.capa(Capa.TwoFactor)) {
addSettingsViewModel(SecurityUserSettings, 'SettingsSecurity', 'SETTINGS_LABELS/LABEL_SECURITY_NAME', 'security'); settingsAddViewModel(SecurityUserSettings, 'SettingsSecurity', 'SETTINGS_LABELS/LABEL_SECURITY_NAME', 'security');
} }
if (Settings.capa(Capa.Templates)) { if (Settings.capa(Capa.Templates)) {
addSettingsViewModel( settingsAddViewModel(
TemplatesUserSettings, TemplatesUserSettings,
'SettingsTemplates', 'SettingsTemplates',
'SETTINGS_LABELS/LABEL_TEMPLATES_NAME', 'SETTINGS_LABELS/LABEL_TEMPLATES_NAME',
@ -83,15 +83,15 @@ export class SettingsUserScreen extends AbstractSettingsScreen {
} }
if (Settings.capa(Capa.Folders)) { if (Settings.capa(Capa.Folders)) {
addSettingsViewModel(FoldersUserSettings, 'SettingsFolders', 'SETTINGS_LABELS/LABEL_FOLDERS_NAME', 'folders'); settingsAddViewModel(FoldersUserSettings, 'SettingsFolders', 'SETTINGS_LABELS/LABEL_FOLDERS_NAME', 'folders');
} }
if (Settings.capa(Capa.Themes)) { if (Settings.capa(Capa.Themes)) {
addSettingsViewModel(ThemesUserSettings, 'SettingsThemes', 'SETTINGS_LABELS/LABEL_THEMES_NAME', 'themes'); settingsAddViewModel(ThemesUserSettings, 'SettingsThemes', 'SETTINGS_LABELS/LABEL_THEMES_NAME', 'themes');
} }
if (Settings.capa(Capa.OpenPGP)) { if (Settings.capa(Capa.OpenPGP)) {
addSettingsViewModel(OpenPgpUserSettings, 'SettingsOpenPGP', 'OpenPGP', 'openpgp'); settingsAddViewModel(OpenPgpUserSettings, 'SettingsOpenPGP', 'OpenPGP', 'openpgp');
} }
runSettingsViewModelHooks(false); runSettingsViewModelHooks(false);

View file

@ -6,6 +6,9 @@ import { showScreenPopup } from 'Knoin/Knoin';
import DomainStore from 'Stores/Admin/Domain'; import DomainStore from 'Stores/Admin/Domain';
import Remote from 'Remote/Admin/Fetch'; import Remote from 'Remote/Admin/Fetch';
import { DomainPopupView } from 'View/Popup/Domain';
import { DomainAliasPopupView } from 'View/Popup/DomainAlias';
export class DomainsAdminSettings { export class DomainsAdminSettings {
constructor() { constructor() {
this.domains = DomainStore.domains; this.domains = DomainStore.domains;
@ -19,11 +22,11 @@ export class DomainsAdminSettings {
} }
createDomain() { createDomain() {
showScreenPopup(require('View/Popup/Domain')); showScreenPopup(DomainPopupView);
} }
createDomainAlias() { createDomainAlias() {
showScreenPopup(require('View/Popup/DomainAlias')); showScreenPopup(DomainAliasPopupView);
} }
deleteDomain(domain) { deleteDomain(domain) {
@ -47,7 +50,7 @@ export class DomainsAdminSettings {
onDomainLoadRequest(sResult, oData) { onDomainLoadRequest(sResult, oData) {
if (StorageResultType.Success === sResult && oData && oData.Result) { if (StorageResultType.Success === sResult && oData && oData.Result) {
showScreenPopup(require('View/Popup/Domain'), [oData.Result]); showScreenPopup(DomainPopupView, [oData.Result]);
} }
} }

View file

@ -4,12 +4,11 @@ import {
pInt, pInt,
settingsSaveHelperSimpleFunction, settingsSaveHelperSimpleFunction,
changeTheme, changeTheme,
convertThemeName, convertThemeName
convertLangName
} from 'Common/Utils'; } from 'Common/Utils';
import { SaveSettingsStep } from 'Common/Enums'; import { SaveSettingsStep } from 'Common/Enums';
import { reload as translatorReload } from 'Common/Translator'; import { reload as translatorReload, convertLangName } from 'Common/Translator';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
@ -19,6 +18,7 @@ import ThemeStore from 'Stores/Theme';
import LanguageStore from 'Stores/Language'; import LanguageStore from 'Stores/Language';
import AppAdminStore from 'Stores/Admin/App'; import AppAdminStore from 'Stores/Admin/App';
import CapaAdminStore from 'Stores/Admin/Capa'; import CapaAdminStore from 'Stores/Admin/Capa';
import LanguagesPopupView from 'View/Popup/Languages';
const settingsGet = rl.settings.get; const settingsGet = rl.settings.get;
@ -167,11 +167,11 @@ export class GeneralAdminSettings {
} }
selectLanguage() { selectLanguage() {
showScreenPopup(require('View/Popup/Languages'), [this.language, this.languages(), LanguageStore.userLanguage()]); showScreenPopup(LanguagesPopupView, [this.language, this.languages(), LanguageStore.userLanguage()]);
} }
selectLanguageAdmin() { selectLanguageAdmin() {
showScreenPopup(require('View/Popup/Languages'), [ showScreenPopup(LanguagesPopupView, [
this.languageAdmin, this.languageAdmin,
this.languagesAdmin(), this.languagesAdmin(),
LanguageStore.userLanguageAdmin() LanguageStore.userLanguageAdmin()

View file

@ -9,6 +9,8 @@ import PluginStore from 'Stores/Admin/Plugin';
import Remote from 'Remote/Admin/Fetch'; import Remote from 'Remote/Admin/Fetch';
import { PluginPopupView } from 'View/Popup/Plugin';
export class PluginsAdminSettings { export class PluginsAdminSettings {
constructor() { constructor() {
this.enabledPlugins = ko.observable(!!rl.settings.get('EnabledPlugins')); this.enabledPlugins = ko.observable(!!rl.settings.get('EnabledPlugins'));
@ -54,7 +56,7 @@ export class PluginsAdminSettings {
onPluginLoadRequest(result, data) { onPluginLoadRequest(result, data) {
if (StorageResultType.Success === result && data && data.Result) { if (StorageResultType.Success === result && data && data.Result) {
showScreenPopup(require('View/Popup/Plugin'), [data.Result]); showScreenPopup(PluginPopupView, [data.Result]);
} }
} }

View file

@ -8,6 +8,9 @@ import Remote from 'Remote/User/Fetch';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { AccountPopupView } from 'View/Popup/Account';
import { IdentityPopupView } from 'View/Popup/Identity';
export class AccountsUserSettings { export class AccountsUserSettings {
constructor() { constructor() {
this.allowAdditionalAccount = rl.settings.capa(Capa.AdditionalAccounts); this.allowAdditionalAccount = rl.settings.capa(Capa.AdditionalAccounts);
@ -21,21 +24,21 @@ export class AccountsUserSettings {
} }
addNewAccount() { addNewAccount() {
showScreenPopup(require('View/Popup/Account')); showScreenPopup(AccountPopupView);
} }
editAccount(account) { editAccount(account) {
if (account && account.canBeEdit()) { if (account && account.canBeEdit()) {
showScreenPopup(require('View/Popup/Account'), [account]); showScreenPopup(AccountPopupView, [account]);
} }
} }
addNewIdentity() { addNewIdentity() {
showScreenPopup(require('View/Popup/Identity')); showScreenPopup(IdentityPopupView);
} }
editIdentity(identity) { editIdentity(identity) {
showScreenPopup(require('View/Popup/Identity'), [identity]); showScreenPopup(IdentityPopupView, [identity]);
} }
/** /**

View file

@ -11,6 +11,8 @@ import { SieveScriptModel } from 'Model/SieveScript';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { SieveScriptPopupView } from 'View/Popup/SieveScript';
export class FiltersUserSettings { export class FiltersUserSettings {
constructor() { constructor() {
this.scripts = SieveStore.scripts; this.scripts = SieveStore.scripts;
@ -60,11 +62,11 @@ export class FiltersUserSettings {
} }
addScript() { addScript() {
showScreenPopup(require('View/Popup/SieveScript'), [new SieveScriptModel()]); showScreenPopup(SieveScriptPopupView, [new SieveScriptModel()]);
} }
editScript(script) { editScript(script) {
showScreenPopup(require('View/Popup/SieveScript'), [script]); showScreenPopup(SieveScriptPopupView, [script]);
} }
deleteScript(script) { deleteScript(script) {

View file

@ -14,6 +14,9 @@ import Remote from 'Remote/User/Fetch';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { FolderCreatePopupView } from 'View/Popup/FolderCreate';
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
export class FoldersUserSettings { export class FoldersUserSettings {
constructor() { constructor() {
this.displaySpecSetting = FolderStore.displaySpecSetting; this.displaySpecSetting = FolderStore.displaySpecSetting;
@ -79,11 +82,11 @@ export class FoldersUserSettings {
} }
createFolder() { createFolder() {
showScreenPopup(require('View/Popup/FolderCreate')); showScreenPopup(FolderCreatePopupView);
} }
systemFolder() { systemFolder() {
showScreenPopup(require('View/Popup/FolderSystem')); showScreenPopup(FolderSystemPopupView);
} }
deleteFolder(folderToRemove) { deleteFolder(folderToRemove) {

View file

@ -5,9 +5,9 @@ import { MESSAGES_PER_PAGE_VALUES } from 'Common/Consts';
import { SaveSettingsStep } from 'Common/Enums'; import { SaveSettingsStep } from 'Common/Enums';
import { EditorDefaultType, Layout } from 'Common/EnumsUser'; import { EditorDefaultType, Layout } from 'Common/EnumsUser';
import { settingsSaveHelperSimpleFunction, convertLangName } from 'Common/Utils'; import { settingsSaveHelperSimpleFunction } from 'Common/Utils';
import { i18n, trigger as translatorTrigger, reload as translatorReload } from 'Common/Translator'; import { i18n, trigger as translatorTrigger, reload as translatorReload, convertLangName } from 'Common/Translator';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
@ -20,6 +20,9 @@ import MessageStore from 'Stores/User/Message';
import Remote from 'Remote/User/Fetch'; import Remote from 'Remote/User/Fetch';
import { IdentityPopupView } from 'View/Popup/Identity';
import { LanguagesPopupView } from 'View/Popup/Languages';
export class GeneralUserSettings { export class GeneralUserSettings {
constructor() { constructor() {
this.language = LanguageStore.language; this.language = LanguageStore.language;
@ -87,7 +90,7 @@ export class GeneralUserSettings {
editMainIdentity() { editMainIdentity() {
const identity = this.identityMain(); const identity = this.identityMain();
if (identity) { if (identity) {
showScreenPopup(require('View/Popup/Identity'), [identity]); showScreenPopup(IdentityPopupView, [identity]);
} }
} }
@ -161,6 +164,6 @@ export class GeneralUserSettings {
} }
selectLanguage() { selectLanguage() {
showScreenPopup(require('View/Popup/Languages'), [this.language, this.languages(), LanguageStore.userLanguage()]); showScreenPopup(LanguagesPopupView, [this.language, this.languages(), LanguageStore.userLanguage()]);
} }
} }

View file

@ -9,6 +9,10 @@ import Remote from 'Remote/User/Fetch';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { AddOpenPgpKeyPopupView } from 'View/Popup/AddOpenPgpKey';
import { NewOpenPgpKeyPopupView } from 'View/Popup/NewOpenPgpKey';
import { ViewOpenPgpKeyPopupView } from 'View/Popup/ViewOpenPgpKey';
export class OpenPgpUserSettings { export class OpenPgpUserSettings {
constructor() { constructor() {
this.openpgpkeys = PgpStore.openpgpkeys; this.openpgpkeys = PgpStore.openpgpkeys;
@ -21,16 +25,16 @@ export class OpenPgpUserSettings {
} }
addOpenPgpKey() { addOpenPgpKey() {
showScreenPopup(require('View/Popup/AddOpenPgpKey')); showScreenPopup(AddOpenPgpKeyPopupView);
} }
generateOpenPgpKey() { generateOpenPgpKey() {
showScreenPopup(require('View/Popup/NewOpenPgpKey')); showScreenPopup(NewOpenPgpKeyPopupView);
} }
viewOpenPgpKey(openPgpKey) { viewOpenPgpKey(openPgpKey) {
if (openPgpKey) { if (openPgpKey) {
showScreenPopup(require('View/Popup/ViewOpenPgpKey'), [openPgpKey]); showScreenPopup(ViewOpenPgpKeyPopupView, [openPgpKey]);
} }
} }

View file

@ -10,6 +10,8 @@ import SettinsStore from 'Stores/User/Settings';
import Remote from 'Remote/User/Fetch'; import Remote from 'Remote/User/Fetch';
import { TwoFactorConfigurationPopupView } from 'View/Popup/TwoFactorConfiguration';
export class SecurityUserSettings { export class SecurityUserSettings {
constructor() { constructor() {
this.capaAutoLogout = rl.settings.capa(Capa.AutoLogout); this.capaAutoLogout = rl.settings.capa(Capa.AutoLogout);
@ -34,7 +36,7 @@ export class SecurityUserSettings {
} }
configureTwoFactor() { configureTwoFactor() {
showScreenPopup(require('View/Popup/TwoFactorConfiguration')); showScreenPopup(TwoFactorConfigurationPopupView);
} }
onBuild() { onBuild() {

View file

@ -7,6 +7,8 @@ import Remote from 'Remote/User/Fetch';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { TemplatePopupView } from 'View/Popup/Template';
export class TemplatesUserSettings { export class TemplatesUserSettings {
constructor() { constructor() {
this.templates = TemplateStore.templates; this.templates = TemplateStore.templates;
@ -20,12 +22,12 @@ export class TemplatesUserSettings {
} }
addNewTemplate() { addNewTemplate() {
showScreenPopup(require('View/Popup/Template')); showScreenPopup(TemplatePopupView);
} }
editTemplate(oTemplateItem) { editTemplate(oTemplateItem) {
if (oTemplateItem) { if (oTemplateItem) {
showScreenPopup(require('View/Popup/Template'), [oTemplateItem]); showScreenPopup(TemplatePopupView, [oTemplateItem]);
} }
} }

View file

@ -7,6 +7,8 @@ import AccountStore from 'Stores/User/Account';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { MessageOpenPgpPopupView } from 'View/Popup/MessageOpenPgp';
function controlsHelper(dom, verControl, success, title, text) function controlsHelper(dom, verControl, success, title, text)
{ {
dom.classList.toggle('error', !success); dom.classList.toggle('error', !success);
@ -264,7 +266,7 @@ class PgpUserStore {
if (message && message.getEncryptionKeyIds) { if (message && message.getEncryptionKeyIds) {
const privateKeys = this.findPrivateKeysByEncryptionKeyIds(message.getEncryptionKeyIds(), recipients, true); const privateKeys = this.findPrivateKeysByEncryptionKeyIds(message.getEncryptionKeyIds(), recipients, true);
if (privateKeys && privateKeys.length) { if (privateKeys && privateKeys.length) {
showScreenPopup(require('View/Popup/MessageOpenPgp'), [ showScreenPopup(MessageOpenPgpPopupView, [
(decryptedKey) => { (decryptedKey) => {
if (decryptedKey) { if (decryptedKey) {
message.decrypt(decryptedKey).then( message.decrypt(decryptedKey).then(

View file

@ -15,7 +15,8 @@ import {
} from 'Common/EnumsUser'; } from 'Common/EnumsUser';
import { inFocus, pInt } from 'Common/Utils'; import { inFocus, pInt } from 'Common/Utils';
import { encodeHtml, delegateRunOnDestroy } from 'Common/UtilsUser'; import { delegateRunOnDestroy } from 'Common/UtilsUser';
import { encodeHtml } from 'Common/Html';
import { UNUSED_OPTION_VALUE } from 'Common/Consts'; import { UNUSED_OPTION_VALUE } from 'Common/Consts';
import { upload } from 'Common/Links'; import { upload } from 'Common/Links';
@ -23,7 +24,7 @@ import { i18n, getNotification, getUploadErrorDescByCode } from 'Common/Translat
import { format as momentorFormat } from 'Common/Momentor'; import { format as momentorFormat } from 'Common/Momentor';
import { MessageFlagsCache, setFolderHash } from 'Common/Cache'; import { MessageFlagsCache, setFolderHash } from 'Common/Cache';
import { HtmlEditor } from 'Common/HtmlEditor'; import { HtmlEditor } from 'Common/Html';
import AppStore from 'Stores/User/App'; import AppStore from 'Stores/User/App';
import SettingsStore from 'Stores/User/Settings'; import SettingsStore from 'Stores/User/Settings';
@ -40,6 +41,11 @@ import { ComposeAttachmentModel } from 'Model/ComposeAttachment';
import { command, isPopupVisible, showScreenPopup, hideScreenPopup } from 'Knoin/Knoin'; import { command, isPopupVisible, showScreenPopup, hideScreenPopup } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { FolderSystemPopupView } from 'View/Popup/FolderSystem';
import { AskPopupView } from 'View/Popup/Ask';
import { ContactsPopupView } from 'View/Popup/Contacts';
import { ComposeOpenPgpPopupView } from 'View/Popup/ComposeOpenPgp';
const Settings = rl.settings, const Settings = rl.settings,
/** /**
* @param {string} prefix * @param {string} prefix
@ -403,7 +409,7 @@ class ComposePopupView extends AbstractViewPopup {
} }
if (!sSentFolder) { if (!sSentFolder) {
showScreenPopup(require('View/Popup/FolderSystem'), [SetSystemFoldersNotification.Sent]); showScreenPopup(FolderSystemPopupView, [SetSystemFoldersNotification.Sent]);
} else { } else {
this.sendError(false); this.sendError(false);
this.sending(true); this.sending(true);
@ -443,7 +449,7 @@ class ComposePopupView extends AbstractViewPopup {
} }
if (FolderStore.draftFolderNotEnabled()) { if (FolderStore.draftFolderNotEnabled()) {
showScreenPopup(require('View/Popup/FolderSystem'), [SetSystemFoldersNotification.Draft]); showScreenPopup(FolderSystemPopupView, [SetSystemFoldersNotification.Draft]);
} else { } else {
this.savedError(false); this.savedError(false);
this.saving(true); this.saving(true);
@ -463,9 +469,8 @@ class ComposePopupView extends AbstractViewPopup {
@command((self) => self.isDraftFolderMessage()) @command((self) => self.isDraftFolderMessage())
deleteCommand() { deleteCommand() {
const PopupsAskViewModel = require('View/Popup/Ask'); if (!isPopupVisible(AskPopupView) && this.modalVisibility()) {
if (!isPopupVisible(PopupsAskViewModel) && this.modalVisibility()) { showScreenPopup(AskPopupView, [
showScreenPopup(PopupsAskViewModel, [
i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'), i18n('POPUPS_ASK/DESC_WANT_DELETE_MESSAGES'),
() => { () => {
if (this.modalVisibility()) { if (this.modalVisibility()) {
@ -499,7 +504,7 @@ class ComposePopupView extends AbstractViewPopup {
if (this.allowContacts) { if (this.allowContacts) {
this.skipCommand(); this.skipCommand();
setTimeout(() => { setTimeout(() => {
showScreenPopup(require('View/Popup/Contacts'), [true, this.sLastFocusedField]); showScreenPopup(ContactsPopupView, [true, this.sLastFocusedField]);
}, 200); }, 200);
} }
} }
@ -535,7 +540,7 @@ class ComposePopupView extends AbstractViewPopup {
openOpenPgpPopup() { openOpenPgpPopup() {
if (PgpStore.capaOpenPGP() && this.oEditor && !this.oEditor.isHtml()) { if (PgpStore.capaOpenPGP() && this.oEditor && !this.oEditor.isHtml()) {
showScreenPopup(require('View/Popup/ComposeOpenPgp'), [ showScreenPopup(ComposeOpenPgpPopupView, [
(result) => { (result) => {
this.editor((editor) => { this.editor((editor) => {
editor.setPlain(result); editor.setPlain(result);
@ -780,7 +785,7 @@ class ComposePopupView extends AbstractViewPopup {
if (AppStore.composeInEdit()) { if (AppStore.composeInEdit()) {
type = type || ComposeType.Empty; type = type || ComposeType.Empty;
if (ComposeType.Empty !== type) { if (ComposeType.Empty !== type) {
showScreenPopup(require('View/Popup/Ask'), [ showScreenPopup(AskPopupView, [
i18n('COMPOSE/DISCARD_UNSAVED_DATA'), i18n('COMPOSE/DISCARD_UNSAVED_DATA'),
() => { () => {
this.initOnShow(type, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText); this.initOnShow(type, oMessageOrArray, aToEmails, aCcEmails, aBccEmails, sCustomSubject, sCustomPlainText);
@ -1137,12 +1142,11 @@ class ComposePopupView extends AbstractViewPopup {
} }
tryToClosePopup() { tryToClosePopup() {
const PopupsAskViewModel = require('View/Popup/Ask'); if (!isPopupVisible(AskPopupView) && this.modalVisibility()) {
if (!isPopupVisible(PopupsAskViewModel) && this.modalVisibility()) {
if (this.bSkipNextHide || (this.isEmptyForm() && !this.draftUid())) { if (this.bSkipNextHide || (this.isEmptyForm() && !this.draftUid())) {
this.closeCommand && this.closeCommand(); this.closeCommand && this.closeCommand();
} else { } else {
showScreenPopup(PopupsAskViewModel, [ showScreenPopup(AskPopupView, [
i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'),
() => { () => {
if (this.modalVisibility()) { if (this.modalVisibility()) {

View file

@ -26,9 +26,10 @@ import { EmailModel } from 'Model/Email';
import { ContactModel } from 'Model/Contact'; import { ContactModel } from 'Model/Contact';
import { ContactPropertyModel, ContactPropertyType } from 'Model/ContactProperty'; import { ContactPropertyModel, ContactPropertyType } from 'Model/ContactProperty';
import { command, showScreenPopup, hideScreenPopup } from 'Knoin/Knoin'; import { command, hideScreenPopup } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';
const CONTACTS_PER_PAGE = 50, const CONTACTS_PER_PAGE = 50,
propertyIsMail = prop => prop.isType(ContactPropertyType.Email), propertyIsMail = prop => prop.isType(ContactPropertyType.Email),
propertyIsName = prop => prop.isType(ContactPropertyType.FirstName) || prop.isType(ContactPropertyType.LastName); propertyIsName = prop => prop.isType(ContactPropertyType.FirstName) || prop.isType(ContactPropertyType.LastName);
@ -225,7 +226,7 @@ class ContactsPopupView extends AbstractViewPopup {
this.sLastComposeFocusedField = ''; this.sLastComposeFocusedField = '';
setTimeout(() => { setTimeout(() => {
showScreenPopup(require('View/Popup/Compose'), [ComposeType.Empty, null, toEmails, ccEmails, bccEmails]); rl.app.showComposePopupView([ComposeType.Empty, null, toEmails, ccEmails, bccEmails]);
}, 200); }, 200);
} }
@ -567,7 +568,7 @@ class ContactsPopupView extends AbstractViewPopup {
this.bBackToCompose = false; this.bBackToCompose = false;
if (rl.settings.capa(Capa.Composer)) { if (rl.settings.capa(Capa.Composer)) {
showScreenPopup(require('View/Popup/Compose')); rl.app.showComposePopupView();
} }
} }
} }

View file

@ -12,7 +12,7 @@ import Remote from 'Remote/User/Fetch';
import { command } from 'Knoin/Knoin'; import { command } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';
class FolderCreateView extends AbstractViewPopup { class FolderCreatePopupView extends AbstractViewPopup {
constructor() { constructor() {
super('FolderCreate'); super('FolderCreate');
@ -77,4 +77,4 @@ class FolderCreateView extends AbstractViewPopup {
} }
} }
export { FolderCreateView, FolderCreateView as default }; export { FolderCreatePopupView, FolderCreatePopupView as default };

View file

@ -1,6 +1,6 @@
import ko from 'ko'; import ko from 'ko';
import { convertLangName } from 'Common/Utils'; import { convertLangName } from 'Common/Translator';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';

View file

@ -7,6 +7,7 @@ import Remote from 'Remote/Admin/Fetch';
import { command, isPopupVisible, showScreenPopup } from 'Knoin/Knoin'; import { command, isPopupVisible, showScreenPopup } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { AskPopupView } from 'View/Popup/Ask';
class PluginPopupView extends AbstractViewPopup { class PluginPopupView extends AbstractViewPopup {
constructor() { constructor() {
@ -88,9 +89,8 @@ class PluginPopupView extends AbstractViewPopup {
} }
tryToClosePopup() { tryToClosePopup() {
const PopupsAskViewModel = require('View/Popup/Ask'); if (!isPopupVisible(AskPopupView)) {
if (!isPopupVisible(PopupsAskViewModel)) { showScreenPopup(AskPopupView, [
showScreenPopup(PopupsAskViewModel, [
i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'), i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'),
() => this.modalVisibility() && this.cancelCommand && this.cancelCommand() () => this.modalVisibility() && this.cancelCommand && this.cancelCommand()
]); ]);

View file

@ -12,6 +12,8 @@ import SieveStore from 'Stores/User/Sieve';
import { showScreenPopup/*, command*/ } from 'Knoin/Knoin'; import { showScreenPopup/*, command*/ } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { FilterPopupView } from 'View/Popup/Filter';
class SieveScriptPopupView extends AbstractViewPopup { class SieveScriptPopupView extends AbstractViewPopup {
constructor() { constructor() {
super('SieveScript'); super('SieveScript');
@ -83,7 +85,7 @@ class SieveScriptPopupView extends AbstractViewPopup {
/* this = SieveScriptModel */ /* this = SieveScriptModel */
const filter = new FilterModel(); const filter = new FilterModel();
filter.generateID(); filter.generateID();
showScreenPopup(require('View/Popup/Filter'), [ showScreenPopup(FilterPopupView, [
filter, filter,
() => { () => {
this.filters.push(filter); this.filters.push(filter);
@ -94,7 +96,7 @@ class SieveScriptPopupView extends AbstractViewPopup {
editFilter(filter) { editFilter(filter) {
const clonedFilter = filter.cloneSelf(); const clonedFilter = filter.cloneSelf();
showScreenPopup(require('View/Popup/Filter'), [ showScreenPopup(FilterPopupView, [
clonedFilter, clonedFilter,
() => { () => {
const script = this.script(), const script = this.script(),

View file

@ -1,6 +1,6 @@
import { StorageResultType, Notification } from 'Common/Enums'; import { StorageResultType, Notification } from 'Common/Enums';
import { getNotification } from 'Common/Translator'; import { getNotification } from 'Common/Translator';
import { HtmlEditor } from 'Common/HtmlEditor'; import { HtmlEditor } from 'Common/Html';
import Remote from 'Remote/User/Fetch'; import Remote from 'Remote/User/Fetch';

View file

@ -7,6 +7,8 @@ import Remote from 'Remote/User/Fetch';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { TwoFactorTestPopupView } from 'View/Popup/TwoFactorTest';
class TwoFactorConfigurationPopupView extends AbstractViewPopup { class TwoFactorConfigurationPopupView extends AbstractViewPopup {
constructor() { constructor() {
super('TwoFactorConfiguration'); super('TwoFactorConfiguration');
@ -104,7 +106,7 @@ class TwoFactorConfigurationPopupView extends AbstractViewPopup {
} }
testTwoFactor() { testTwoFactor() {
showScreenPopup(require('View/Popup/TwoFactorTest'), [this.twoFactorTested]); showScreenPopup(TwoFactorTestPopupView, [this.twoFactorTested]);
} }
clearTwoFactor() { clearTwoFactor() {

View file

@ -8,6 +8,9 @@ import { settings } from 'Common/Links';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { AbstractViewRight } from 'Knoin/AbstractViews'; import { AbstractViewRight } from 'Knoin/AbstractViews';
import { KeyboardShortcutsHelpPopupView } from 'View/Popup/KeyboardShortcutsHelp';
import { AccountPopupView } from 'View/Popup/Account';
const Settings = rl.settings; const Settings = rl.settings;
export class AbstractSystemDropDownUserView extends AbstractViewRight { export class AbstractSystemDropDownUserView extends AbstractViewRight {
@ -63,13 +66,13 @@ export class AbstractSystemDropDownUserView extends AbstractViewRight {
settingsHelp() { settingsHelp() {
if (Settings.capa(Capa.Help)) { if (Settings.capa(Capa.Help)) {
showScreenPopup(require('View/Popup/KeyboardShortcutsHelp')); showScreenPopup(KeyboardShortcutsHelpPopupView);
} }
} }
addAccountClick() { addAccountClick() {
if (this.capaAdditionalAccounts()) { if (this.capaAdditionalAccounts()) {
showScreenPopup(require('View/Popup/Account')); showScreenPopup(AccountPopupView);
} }
} }
@ -89,7 +92,7 @@ export class AbstractSystemDropDownUserView extends AbstractViewRight {
// shortcuts help // shortcuts help
shortcuts.add('?,f1,help', '', [KeyState.MessageList, KeyState.MessageView, KeyState.Settings], () => { shortcuts.add('?,f1,help', '', [KeyState.MessageList, KeyState.MessageView, KeyState.Settings], () => {
if (this.viewModelVisible) { if (this.viewModelVisible) {
showScreenPopup(require('View/Popup/KeyboardShortcutsHelp')); showScreenPopup(KeyboardShortcutsHelpPopupView);
return false; return false;
} }
return true; return true;

View file

@ -7,9 +7,7 @@ import {
import { ClientSideKeyName } from 'Common/EnumsUser'; import { ClientSideKeyName } from 'Common/EnumsUser';
import { convertLangName } from 'Common/Utils'; import { getNotification, getNotificationFromResponse, reload as translatorReload, convertLangName } from 'Common/Translator';
import { getNotification, getNotificationFromResponse, reload as translatorReload } from 'Common/Translator';
import AppStore from 'Stores/User/App'; import AppStore from 'Stores/User/App';
import LanguageStore from 'Stores/Language'; import LanguageStore from 'Stores/Language';
@ -23,6 +21,8 @@ import { AbstractViewCenter } from 'Knoin/AbstractViews';
import { rootAdmin } from 'Common/Links'; import { rootAdmin } from 'Common/Links';
import { LanguagesPopupView } from 'View/Popup/Languages';
const Settings = rl.settings, const Settings = rl.settings,
LoginSignMeType = { LoginSignMeType = {
@ -269,7 +269,7 @@ class LoginUserView extends AbstractViewCenter {
} }
selectLanguage() { selectLanguage() {
showScreenPopup(require('View/Popup/Languages'), [this.language, this.languages(), LanguageStore.userLanguage()]); showScreenPopup(LanguagesPopupView, [this.language, this.languages(), LanguageStore.userLanguage()]);
} }
} }

View file

@ -14,6 +14,10 @@ import MessageStore from 'Stores/User/Message';
import { showScreenPopup } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { AbstractViewLeft } from 'Knoin/AbstractViews'; import { AbstractViewLeft } from 'Knoin/AbstractViews';
import { ComposePopupView } from 'View/Popup/Compose';
import { FolderCreatePopupView } from 'View/Popup/FolderCreate';
import { ContactsPopupView } from 'View/Popup/Contacts';
const Settings = rl.settings; const Settings = rl.settings;
class FolderListMailBoxUserView extends AbstractViewLeft { class FolderListMailBoxUserView extends AbstractViewLeft {
@ -200,12 +204,12 @@ class FolderListMailBoxUserView extends AbstractViewLeft {
composeClick() { composeClick() {
if (Settings.capa(Capa.Composer)) { if (Settings.capa(Capa.Composer)) {
showScreenPopup(require('View/Popup/Compose')); showScreenPopup(ComposePopupView);
} }
} }
createFolder() { createFolder() {
showScreenPopup(require('View/Popup/FolderCreate')); showScreenPopup(FolderCreatePopupView);
} }
configureFolders() { configureFolders() {
@ -214,7 +218,7 @@ class FolderListMailBoxUserView extends AbstractViewLeft {
contactsClick() { contactsClick() {
if (this.allowContacts) { if (this.allowContacts) {
showScreenPopup(require('View/Popup/Contacts')); showScreenPopup(ContactsPopupView);
} }
} }
} }

View file

@ -44,6 +44,10 @@ import Remote from 'Remote/User/Fetch';
import { command, showScreenPopup, popupVisibility } from 'Knoin/Knoin'; import { command, showScreenPopup, popupVisibility } from 'Knoin/Knoin';
import { AbstractViewRight } from 'Knoin/AbstractViews'; import { AbstractViewRight } from 'Knoin/AbstractViews';
import { FolderClearPopupView } from 'View/Popup/FolderClear';
import { ComposePopupView } from 'View/Popup/Compose';
import { AdvancedSearchPopupView } from 'View/Popup/AdvancedSearch';
const const
Settings = rl.settings, Settings = rl.settings,
canBeMovedHelper = (self) => self.canBeMoved(), canBeMovedHelper = (self) => self.canBeMoved(),
@ -244,7 +248,7 @@ class MessageListMailBoxUserView extends AbstractViewRight {
@command() @command()
clearCommand() { clearCommand() {
if (Settings.capa(Capa.DangerousActions)) { if (Settings.capa(Capa.DangerousActions)) {
showScreenPopup(require('View/Popup/FolderClear'), [FolderStore.currentFolder()]); showScreenPopup(FolderClearPopupView, [FolderStore.currentFolder()]);
} }
} }
@ -258,7 +262,7 @@ class MessageListMailBoxUserView extends AbstractViewRight {
@command(canBeMovedHelper) @command(canBeMovedHelper)
multyForwardCommand() { multyForwardCommand() {
if (Settings.capa(Capa.Composer)) { if (Settings.capa(Capa.Composer)) {
showScreenPopup(require('View/Popup/Compose'), [ showScreenPopup(ComposePopupView, [
ComposeType.ForwardAsAttachment, ComposeType.ForwardAsAttachment,
MessageStore.messageListCheckedOrSelected() MessageStore.messageListCheckedOrSelected()
]); ]);
@ -350,7 +354,7 @@ class MessageListMailBoxUserView extends AbstractViewRight {
composeClick() { composeClick() {
if (Settings.capa(Capa.Composer)) { if (Settings.capa(Capa.Composer)) {
showScreenPopup(require('View/Popup/Compose')); showScreenPopup(ComposePopupView);
} }
} }
@ -761,7 +765,7 @@ class MessageListMailBoxUserView extends AbstractViewRight {
if (Settings.capa(Capa.Composer)) { if (Settings.capa(Capa.Composer)) {
// write/compose (open compose popup) // write/compose (open compose popup)
shortcuts.add('w,c,new', '', [KeyState.MessageList, KeyState.MessageView], () => { shortcuts.add('w,c,new', '', [KeyState.MessageList, KeyState.MessageView], () => {
showScreenPopup(require('View/Popup/Compose')); showScreenPopup(ComposePopupView);
return false; return false;
}); });
} }
@ -887,7 +891,7 @@ class MessageListMailBoxUserView extends AbstractViewRight {
advancedSearchClick() { advancedSearchClick() {
Settings.capa(Capa.SearchAdv) Settings.capa(Capa.SearchAdv)
&& showScreenPopup(require('View/Popup/AdvancedSearch'), [this.mainMessageListSearch()]); && showScreenPopup(AdvancedSearchPopupView, [this.mainMessageListSearch()]);
} }
quotaTooltip() { quotaTooltip() {

View file

@ -41,6 +41,8 @@ import Remote from 'Remote/User/Fetch';
import { command, showScreenPopup, createCommand } from 'Knoin/Knoin'; import { command, showScreenPopup, createCommand } from 'Knoin/Knoin';
import { AbstractViewRight } from 'Knoin/AbstractViews'; import { AbstractViewRight } from 'Knoin/AbstractViews';
import { ComposePopupView } from 'View/Popup/Compose';
const Settings = rl.settings; const Settings = rl.settings;
function isTransparent(color) { function isTransparent(color) {
@ -342,7 +344,7 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
* @returns {void} * @returns {void}
*/ */
replyOrforward(sType) { replyOrforward(sType) {
Settings.capa(Capa.Composer) && showScreenPopup(require('View/Popup/Compose'), [sType, MessageStore.message()]); Settings.capa(Capa.Composer) && showScreenPopup(ComposePopupView, [sType, MessageStore.message()]);
} }
checkHeaderHeight() { checkHeaderHeight() {
@ -426,7 +428,7 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
3 !== event.which && 3 !== event.which &&
mailToHelper( mailToHelper(
el.href, el.href,
Settings.capa(Capa.Composer) ? require('View/Popup/Compose') : null Settings.capa(Capa.Composer) ? ComposePopupView : null
) )
); );
} }
@ -684,13 +686,13 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
composeClick() { composeClick() {
if (Settings.capa(Capa.Composer)) { if (Settings.capa(Capa.Composer)) {
showScreenPopup(require('View/Popup/Compose')); showScreenPopup(ComposePopupView);
} }
} }
editMessage() { editMessage() {
if (Settings.capa(Capa.Composer) && MessageStore.message()) { if (Settings.capa(Capa.Composer) && MessageStore.message()) {
showScreenPopup(require('View/Popup/Compose'), [ComposeType.Draft, MessageStore.message()]); showScreenPopup(ComposePopupView, [ComposeType.Draft, MessageStore.message()]);
} }
} }

View file

@ -50,7 +50,6 @@
"@babel/runtime-corejs3": "7.8.7", "@babel/runtime-corejs3": "7.8.7",
"babel-eslint": "10.1.0", "babel-eslint": "10.1.0",
"babel-loader": "8.0.6", "babel-loader": "8.0.6",
"copy-webpack-plugin": "5.1.1",
"css-loader": "3.4.2", "css-loader": "3.4.2",
"eslint": "6.8.0", "eslint": "6.8.0",
"eslint-config-prettier": "6.10.0", "eslint-config-prettier": "6.10.0",
@ -74,18 +73,18 @@
"gulp-size": "3.0.0", "gulp-size": "3.0.0",
"gulp-stripbom": "1.0.5", "gulp-stripbom": "1.0.5",
"gulp-terser": "^1.4.0", "gulp-terser": "^1.4.0",
"gulp-through": "0.4.0",
"gulp-util": "3.0.8", "gulp-util": "3.0.8",
"gulp-zip": "5.0.1", "gulp-zip": "5.0.1",
"node-fs": "0.1.7", "node-fs": "0.1.7",
"openpgp": "2.6.2", "openpgp": "2.6.2",
"prettier": "1.19.1", "rimraf": "3.0.2"
"raw-loader": "4.0.0",
"rimraf": "3.0.2",
"style-loader": "1.1.3"
}, },
"dependencies": { "dependencies": {
"webpack": "4.42.0", "rollup": "^2.38.0",
"webpack-cli": "3.3.11" "rollup-plugin-babel": "^4.4.0",
"rollup-plugin-external-globals": "^0.6.1",
"rollup-plugin-html": "^0.2.1",
"rollup-plugin-includepaths": "^0.2.4",
"rollup-plugin-terser": "^7.0.2"
} }
} }

View file

@ -7,6 +7,11 @@ if (!$gulp) {
exit('gulp not installed, run as root: npm install --global gulp-cli'); exit('gulp not installed, run as root: npm install --global gulp-cli');
} }
$rollup = trim(`which rollup`);
if (!$rollup) {
exit('rollup not installed, run as root: npm install --global rollup');
}
$options = getopt('', ['docker']); $options = getopt('', ['docker']);
$options['docker'] = isset($options['docker']); $options['docker'] = isset($options['docker']);
@ -25,6 +30,11 @@ if ($return_var) {
exit("gulp failed with error code {$return_var}\n"); exit("gulp failed with error code {$return_var}\n");
} }
passthru("{$rollup} -c", $return_var);
if ($return_var) {
exit("rollup failed with error code {$return_var}\n");
}
$cmddir = escapeshellcmd(__DIR__) . '/snappymail/v/0.0.0/static'; $cmddir = escapeshellcmd(__DIR__) . '/snappymail/v/0.0.0/static';
if ($gzip = trim(`which gzip`)) { if ($gzip = trim(`which gzip`)) {

95
rollup.config.js Normal file
View file

@ -0,0 +1,95 @@
/*
npm install rollup rollup-plugin-includepaths rollup-plugin-babel rollup-plugin-external-globals rollup-plugin-html rollup-plugin-terser
rollup -c
*/
import babel from 'rollup-plugin-babel';
import includePaths from 'rollup-plugin-includepaths';
import externalGlobals from "rollup-plugin-external-globals";
import html from 'rollup-plugin-html';
import { terser } from "rollup-plugin-terser";
let includePathOptions = {
include: {},
paths: ['dev'],
external: [],
extensions: ['.js', '.html']
};
let babelConfig = {
exclude: 'node_modules/**',
babelrc: false,
presets: [
[
'@babel/preset-env',
{
targets: {"chrome": "60"},
loose: true,
modules: false
}
]
],
plugins: [
[
'@babel/plugin-proposal-decorators',
{
legacy: true
}
],
'@babel/plugin-proposal-class-properties'
]
};
let terserConfig = {
output: {
comments: false
},
keep_classnames: true, // Required for AbstractModel and AbstractCollectionModel
compress:{
ecma: 6,
drop_console: true
/*
,hoist_props: false
,keep_fargs: false
,toplevel: true
,unsafe_arrows: true // Issue with knockoutjs
,unsafe_methods: true
,unsafe_proto: true
*/
}
// ,mangle: {reserved:['SendMessage']}
};
export default [{
external: ['ko'],
input: 'dev/admin.js',
// dest: 'snappymail/v/0.0.0/static/js/admin.rollup.js',
output: [
{file: 'snappymail/v/0.0.0/static/js/admin.js', format: 'iife'}, // format: 'es'
{file: 'snappymail/v/0.0.0/static/js/min/admin.min.js', format: 'iife', plugins: [terser(terserConfig)], }
],
plugins: [
babel(babelConfig),
includePaths(includePathOptions),
externalGlobals({
ko: 'ko'
})
],
}, {
external: ['ko'],
input: 'dev/app.js',
output: [
{file: 'snappymail/v/0.0.0/static/js/app.js', format: 'iife'},
{file: 'snappymail/v/0.0.0/static/js/min/app.min.js', format: 'iife', plugins: [terser(terserConfig)], }
],
plugins: [
babel(babelConfig),
includePaths(includePathOptions),
externalGlobals({
ko: 'ko'
}),
html({
include: '**/*.html'
})
],
}];

View file

@ -16,7 +16,7 @@ const concat = require('gulp-concat-util'),
const { config } = require('./config'); const { config } = require('./config');
const { del, getHead } = require('./common'); const { del, getHead } = require('./common');
const { webpack } = require('./webpack'); //const { rollupJS } = require('./rollup');
const jsClean = () => del(config.paths.staticJS + '/**/*.{js,map}'); const jsClean = () => del(config.paths.staticJS + '/**/*.{js,map}');
@ -24,14 +24,28 @@ const jsClean = () => del(config.paths.staticJS + '/**/*.{js,map}');
const jsBoot = () => { const jsBoot = () => {
return gulp return gulp
.src('dev/boot.js') .src('dev/boot.js')
.pipe(gulp.dest('snappymail/v/' + config.devVersion + '/static/js')); .pipe(gulp.dest(config.paths.staticJS));
}; };
// ServiceWorker // ServiceWorker
const jsServiceWorker = () => { const jsServiceWorker = () => {
return gulp return gulp
.src('dev/serviceworker.js') .src('dev/serviceworker.js')
.pipe(gulp.dest('snappymail/v/' + config.devVersion + '/static/js')); .pipe(gulp.dest(config.paths.staticJS));
};
// OpenPGP
const jsOpenPGP = () => {
return gulp
.src('node_modules/openpgp/dist/openpgp.min.js')
.pipe(gulp.dest(config.paths.staticMinJS));
};
// OpenPGP Worker
const jsOpenPGPWorker = () => {
return gulp
.src('node_modules/openpgp/dist/openpgp.worker.min.js')
.pipe(gulp.dest(config.paths.staticMinJS));
}; };
// libs // libs
@ -114,8 +128,8 @@ const jsLint = () =>
.pipe(eslint.failAfterError()); .pipe(eslint.failAfterError());
const jsState1 = gulp.series(jsLint); const jsState1 = gulp.series(jsLint);
const jsState3 = gulp.parallel(jsBoot, jsServiceWorker, jsLibs, jsApp, jsAdmin); const jsState3 = gulp.parallel(jsBoot, jsServiceWorker, jsOpenPGP, jsOpenPGPWorker, jsLibs/*, jsApp, jsAdmin*/);
const jsState2 = gulp.series(jsClean, webpack, jsState3, jsMin); const jsState2 = gulp.series(jsClean/*, rollupJS('app.js'), rollupJS('admin.js')*/, jsState3, jsMin);
exports.jsLint = jsLint; exports.jsLint = jsLint;
exports.js = gulp.parallel(jsState1, jsState2); exports.js = gulp.parallel(jsState1, jsState2);

View file

@ -1,30 +0,0 @@
/* RainLoop Webmail (c) RainLoop Team | Licensed under AGPL 3 */
const webpack = require('webpack');
const gutil = require('gulp-util');
const { config } = require('./config');
const webpackCfgBuilder = require('../webpack.config.builder.js');
const webpackError = (err) => {
if (err) {
gutil.log('[webpack]', '---');
gutil.log('[webpack]', err.error ? err.error.toString() : '');
gutil.log('[webpack]', err.message || '');
gutil.log('[webpack]', '---');
}
};
const webpackCallback = (done) => (err, stats) => {
if (err) {
throw new gutil.PluginError('webpack', err);
} else if (stats && stats.compilation && stats.compilation.errors && stats.compilation.errors[0]) {
throw new gutil.PluginError('webpack', stats.compilation.errors[0]);
}
done();
};
exports.webpack = (done) => {
webpack(webpackCfgBuilder(config.paths.staticJS, 'production'), webpackCallback(done));
};

View file

@ -1,134 +0,0 @@
const path = require('path');
const webpack = require('webpack');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const devPath = path.resolve(__dirname, 'dev');
const devPathJoin = path.join(__dirname, 'dev');
const externalPathJoin = path.join(__dirname, 'dev', 'External');
const loose = true;
//npm install closure-webpack-plugin google-closure-compiler
//const ClosurePlugin = require('closure-webpack-plugin');
const babelLoaderOptions = function() {
return {
ignore: [/\/core-js/],
cacheDirectory: true,
overrides: [
{
test: './node_modules/',
sourceType: 'unambiguous'
}
],
presets: [
[
'@babel/preset-env',
{
targets: {"chrome": "60"},
// useBuiltIns: 'usage',
// corejs: { version: 3, proposals: true },
loose: loose,
modules: false
}
]
],
plugins: [
[
'@babel/plugin-proposal-decorators',
{
legacy: true
}
],
'@babel/plugin-proposal-class-properties'
]
};
};
process.noDeprecation = true;
module.exports = function(publicPath, mode) {
return {
// mode: 'production',
mode: mode || 'development',
devtool: 'inline-source-map',
entry: {
'js/app': path.join(devPathJoin, 'app.js'),
'js/admin': path.join(devPathJoin, 'admin.js')
},
output: {
pathinfo: true,
path: path.join(__dirname, 'snappymail', 'v', '0.0.0', 'static'),
filename: '[name].js',
publicPath: publicPath || 'snappymail/v/0.0.0/static/'
},
performance: {
hints: false
},
optimization: {
concatenateModules: false,
minimize: false
/*
,minimizer: [
new ClosurePlugin({mode: 'STANDARD'}, {
language_in:'ECMASCRIPT6',
language_out:'ECMASCRIPT6',
compilation_level: 'ADVANCED_OPTIMIZATIONS'
// compiler flags here
//
// for debugging help, try these:
//
// formatting: 'PRETTY_PRINT'
// debug: true,
// renaming: false
})
]
*/
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
new webpack.DefinePlugin({}),
new CopyWebpackPlugin([
{ from: 'node_modules/openpgp/dist/openpgp.min.js', to: 'js/min/openpgp.min.js' },
{ from: 'node_modules/openpgp/dist/openpgp.worker.min.js', to: 'js/min/openpgp.worker.min.js' }
])
],
resolve: {
modules: [devPath, 'node_modules'],
extensions: ['.js'],
alias: {
'ko$': path.join(externalPathJoin, 'ko.js')
}
},
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
include: [devPath],
options: babelLoaderOptions()
},
{
test: /\.html$/,
loader: 'raw-loader',
include: [devPath]
},
{
test: /\.css/,
loaders: ['style-loader', 'css-loader'],
include: [devPath]
},
{
test: /\.json$/,
loader: 'json-loader',
include: [devPath]
}
]
},
externals: {
}
};
};

View file

@ -1 +0,0 @@
module.exports = require('./webpack.config.builder')();