mirror of
https://github.com/the-djmaze/snappymail.git
synced 2025-01-01 04:22:15 +08:00
Improved knockout observables management to prevent memory leaks
This commit is contained in:
parent
b165a1de4f
commit
3eb6ab1ef7
46 changed files with 1020 additions and 1013 deletions
|
@ -1,5 +1,4 @@
|
|||
import { ComposeType, FolderType } from 'Common/Enums';
|
||||
import { pString } from 'Common/Utils';
|
||||
|
||||
const
|
||||
tpl = document.createElement('template'),
|
||||
|
@ -303,13 +302,13 @@ export function folderListOptionsBuilder(
|
|||
|
||||
bSep = true;
|
||||
aList.forEach(oItem => {
|
||||
// if (oItem.subScribed() || !oItem.existen || bBuildUnvisible)
|
||||
// if (oItem.subscribed() || !oItem.exists || bBuildUnvisible)
|
||||
if (
|
||||
(oItem.subScribed() || !oItem.existen || bBuildUnvisible) &&
|
||||
(oItem.selectable || oItem.hasSubScribedSubfolders())
|
||||
(oItem.subscribed() || !oItem.exists || bBuildUnvisible) &&
|
||||
(oItem.selectable || oItem.hasSubscribedSubfolders())
|
||||
) {
|
||||
if (fVisibleCallback ? fVisibleCallback(oItem) : true) {
|
||||
if (FolderType.User === oItem.type() || !bSystem || oItem.hasSubScribedSubfolders()) {
|
||||
if (FolderType.User === oItem.type() || !bSystem || oItem.hasSubscribedSubfolders()) {
|
||||
aResult.push({
|
||||
id: oItem.fullNameRaw,
|
||||
name:
|
||||
|
@ -327,7 +326,7 @@ export function folderListOptionsBuilder(
|
|||
}
|
||||
}
|
||||
|
||||
if (oItem.subScribed() && oItem.subFolders().length) {
|
||||
if (oItem.subscribed() && oItem.subFolders().length) {
|
||||
aResult = aResult.concat(
|
||||
folderListOptionsBuilder(
|
||||
[],
|
||||
|
@ -349,17 +348,14 @@ export function folderListOptionsBuilder(
|
|||
}
|
||||
|
||||
/**
|
||||
* Call the Model/CollectionModel onDestroy() to clear knockout functions/objects
|
||||
* @param {Object|Array} objectOrObjects
|
||||
* @returns {void}
|
||||
*/
|
||||
export function delegateRunOnDestroy(objectOrObjects) {
|
||||
if (objectOrObjects) {
|
||||
if (isArray(objectOrObjects)) {
|
||||
objectOrObjects.forEach(item => delegateRunOnDestroy(item));
|
||||
} else {
|
||||
objectOrObjects.onDestroy && objectOrObjects.onDestroy();
|
||||
}
|
||||
}
|
||||
objectOrObjects && (isArray(objectOrObjects) ? objectOrObjects : [objectOrObjects]).forEach(
|
||||
obj => obj.onDestroy && obj.onDestroy()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -448,14 +444,6 @@ export function computedPaginatorHelper(koCurrentPage, koPageCount) {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} color
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isTransparent(color) {
|
||||
return 'rgba(0, 0, 0, 0)' === color || 'transparent' === color;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} mailToUrl
|
||||
* @param {Function} PopupComposeViewModel
|
||||
|
@ -524,8 +512,8 @@ export function mailToHelper(mailToUrl, PopupComposeViewModel) {
|
|||
to,
|
||||
cc,
|
||||
bcc,
|
||||
null == params.subject ? null : pString(decodeURIComponent(params.subject)),
|
||||
null == params.body ? null : plainToHtml(pString(decodeURIComponent(params.body)))
|
||||
null == params.subject ? null : decodeURIComponent(params.subject),
|
||||
null == params.body ? null : plainToHtml(decodeURIComponent(params.body))
|
||||
]);
|
||||
|
||||
return true;
|
||||
|
|
15
dev/External/ko.js
vendored
15
dev/External/ko.js
vendored
|
@ -262,4 +262,19 @@ ko.observable.fn.deleteAccessHelper = function() {
|
|||
return this;
|
||||
};
|
||||
|
||||
ko.addObservablesTo = (target, observables) => {
|
||||
Object.entries(observables).forEach(([key, value]) => target[key] = ko.observable(value) );
|
||||
/*
|
||||
Object.entries(observables).forEach(([key, value]) =>
|
||||
target[key] = Array.isArray(value) ? ko.observableArray(value) : ko.observable(value)
|
||||
);
|
||||
*/
|
||||
};
|
||||
|
||||
ko.addComputablesTo = (target, computables) =>
|
||||
Object.entries(computables).forEach(([key, fn]) => target[key] = ko.computed(fn));
|
||||
|
||||
ko.addSubscribablesTo = (target, subscribables) =>
|
||||
Object.entries(subscribables).forEach(([key, fn]) => target[key].subscribe(fn));
|
||||
|
||||
export default ko;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
|
||||
function disposeOne(disposable) {
|
||||
function dispose(disposable) {
|
||||
if (disposable && 'function' === typeof disposable.dispose) {
|
||||
disposable.dispose();
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ function typeCast(curValue, newValue) {
|
|||
}
|
||||
|
||||
export class AbstractModel {
|
||||
disposables = [];
|
||||
subscribables = [];
|
||||
|
||||
constructor() {
|
||||
/*
|
||||
|
@ -32,27 +32,30 @@ export class AbstractModel {
|
|||
*/
|
||||
}
|
||||
|
||||
addObservables(obj) {
|
||||
Object.entries(obj).forEach(([key, value]) => this[key] = ko.observable(value) );
|
||||
/*
|
||||
Object.entries(obj).forEach(([key, value]) =>
|
||||
this[key] = Array.isArray(value) ? ko.observableArray(value) : ko.observable(value)
|
||||
);
|
||||
*/
|
||||
addObservables(observables) {
|
||||
ko.addObservablesTo(this, observables);
|
||||
}
|
||||
|
||||
addComputables(obj) {
|
||||
Object.entries(obj).forEach(([key, fn]) => this[key] = ko.computed(fn) );
|
||||
addComputables(computables) {
|
||||
ko.addComputablesTo(this, computables);
|
||||
}
|
||||
|
||||
addSubscribables(obj) {
|
||||
Object.entries(obj).forEach(([key, fn]) => this.disposables.push( this[key].subscribe(fn) ) );
|
||||
addSubscribables(subscribables) {
|
||||
Object.entries(subscribables).forEach(([key, fn]) => this.subscribables.push( this[key].subscribe(fn) ) );
|
||||
}
|
||||
|
||||
/** Called by delegateRunOnDestroy */
|
||||
onDestroy() {
|
||||
this.disposables.forEach(disposeOne);
|
||||
/** clear ko.subscribe */
|
||||
this.subscribables.forEach(dispose);
|
||||
/** clear object entries */
|
||||
Object.entries(this).forEach(([key, value]) => {
|
||||
disposeOne(value);
|
||||
/** clear CollectionModel */
|
||||
let arr = ko.isObservableArray(value) ? value() : value;
|
||||
arr && arr.onDestroy && value.onDestroy();
|
||||
/** destroy ko.observable/ko.computed? */
|
||||
dispose(value);
|
||||
/** clear object value */
|
||||
this[key] = null;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -56,4 +56,16 @@ export class AbstractViewNext {
|
|||
return this.viewModelDom.querySelector(selectors);
|
||||
}
|
||||
|
||||
addObservables(observables) {
|
||||
ko.addObservablesTo(this, observables);
|
||||
}
|
||||
|
||||
addComputables(computables) {
|
||||
ko.addComputablesTo(this, computables);
|
||||
}
|
||||
|
||||
addSubscribables(subscribables) {
|
||||
ko.addSubscribablesTo(this, subscribables);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -10,6 +10,10 @@ export class AbstractCollectionModel extends Array
|
|||
super();
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
this.forEach(item => item.onDestroy && item.onDestroy());
|
||||
}
|
||||
|
||||
/**
|
||||
* @static
|
||||
* @param {FetchJson} json
|
||||
|
|
|
@ -20,7 +20,7 @@ class FolderModel extends AbstractModel {
|
|||
this.interval = 0;
|
||||
|
||||
this.selectable = false;
|
||||
this.existen = true;
|
||||
this.exists = true;
|
||||
|
||||
this.addObservables({
|
||||
name: '',
|
||||
|
@ -29,7 +29,7 @@ class FolderModel extends AbstractModel {
|
|||
focused: false,
|
||||
selected: false,
|
||||
edited: false,
|
||||
subScribed: true,
|
||||
subscribed: true,
|
||||
checkable: false,
|
||||
deleteAccess: false,
|
||||
|
||||
|
@ -54,10 +54,6 @@ class FolderModel extends AbstractModel {
|
|||
const folder = super.reviveFromJson(json);
|
||||
if (folder) {
|
||||
folder.deep = json.FullNameRaw.split(folder.delimiter).length - 1;
|
||||
folder.selectable = !!json.IsSelectable;
|
||||
folder.existen = !!json.IsExists;
|
||||
|
||||
folder.subScribed(!!json.IsSubscribed);
|
||||
|
||||
folder.messageCountAll = ko.computed({
|
||||
read: folder.privateMessageCountAll,
|
||||
|
@ -87,26 +83,26 @@ class FolderModel extends AbstractModel {
|
|||
|
||||
isInbox: () => FolderType.Inbox === folder.type(),
|
||||
|
||||
hasSubScribedSubfolders:
|
||||
hasSubscribedSubfolders:
|
||||
() =>
|
||||
!!folder.subFolders().find(
|
||||
oFolder => (oFolder.subScribed() || oFolder.hasSubScribedSubfolders()) && !oFolder.isSystemFolder()
|
||||
oFolder => (oFolder.subscribed() || oFolder.hasSubscribedSubfolders()) && !oFolder.isSystemFolder()
|
||||
),
|
||||
|
||||
canBeEdited: () => FolderType.User === folder.type() && folder.existen && folder.selectable,
|
||||
canBeEdited: () => FolderType.User === folder.type() && folder.exists && folder.selectable,
|
||||
|
||||
visible: () => {
|
||||
const isSubScribed = folder.subScribed(),
|
||||
isSubFolders = folder.hasSubScribedSubfolders();
|
||||
const isSubscribed = folder.subscribed(),
|
||||
isSubFolders = folder.hasSubscribedSubfolders();
|
||||
|
||||
return isSubScribed || (isSubFolders && (!folder.existen || !folder.selectable));
|
||||
return isSubscribed || (isSubFolders && (!folder.exists || !folder.selectable));
|
||||
},
|
||||
|
||||
isSystemFolder: () => FolderType.User !== folder.type(),
|
||||
|
||||
hidden: () => {
|
||||
const isSystem = folder.isSystemFolder(),
|
||||
isSubFolders = folder.hasSubScribedSubfolders();
|
||||
isSubFolders = folder.hasSubscribedSubfolders();
|
||||
|
||||
return (isSystem && !isSubFolders) || (!folder.selectable && !isSubFolders);
|
||||
},
|
||||
|
@ -137,7 +133,7 @@ class FolderModel extends AbstractModel {
|
|||
|
||||
selectableForFolderList: () => !folder.isSystemFolder() && folder.selectable,
|
||||
|
||||
canBeSubScribed: () => !folder.isSystemFolder() && folder.selectable,
|
||||
canBeSubscribed: () => !folder.isSystemFolder() && folder.selectable,
|
||||
|
||||
canBeChecked: () => !folder.isSystemFolder() && folder.selectable,
|
||||
|
||||
|
@ -221,9 +217,9 @@ class FolderModel extends AbstractModel {
|
|||
|
||||
hasUnreadMessages: () => 0 < folder.messageCountUnread() && folder.printableUnreadCount(),
|
||||
|
||||
hasSubScribedUnreadMessagesSubfolders: () =>
|
||||
hasSubscribedUnreadMessagesSubfolders: () =>
|
||||
!!folder.subFolders().find(
|
||||
folder => folder.hasUnreadMessages() || folder.hasSubScribedUnreadMessagesSubfolders()
|
||||
folder => folder.hasUnreadMessages() || folder.hasSubscribedUnreadMessagesSubfolders()
|
||||
)
|
||||
});
|
||||
|
||||
|
@ -246,7 +242,7 @@ class FolderModel extends AbstractModel {
|
|||
* @returns {string}
|
||||
*/
|
||||
collapsedCss() {
|
||||
return 'e-collapsed-sign ' + (this.hasSubScribedSubfolders()
|
||||
return 'e-collapsed-sign ' + (this.hasSubscribedSubfolders()
|
||||
? (this.collapsed() ? 'icon-right-mini' : 'icon-down-mini')
|
||||
: 'icon-none'
|
||||
);
|
||||
|
|
|
@ -120,13 +120,13 @@ class FoldersUserSettings {
|
|||
subscribeFolder(folder) {
|
||||
Local.set(ClientSideKeyName.FoldersLashHash, '');
|
||||
Remote.folderSetSubscribe(()=>{}, folder.fullNameRaw, true);
|
||||
folder.subScribed(true);
|
||||
folder.subscribed(true);
|
||||
}
|
||||
|
||||
unSubscribeFolder(folder) {
|
||||
Local.set(ClientSideKeyName.FoldersLashHash, '');
|
||||
Remote.folderSetSubscribe(()=>{}, folder.fullNameRaw, false);
|
||||
folder.subScribed(false);
|
||||
folder.subscribed(false);
|
||||
}
|
||||
|
||||
checkableTrueFolder(folder) {
|
||||
|
|
|
@ -26,9 +26,6 @@ class ThemesUserSettings {
|
|||
|
||||
this.themeTrigger = ko.observable(SaveSettingsStep.Idle).extend({ throttle: 100 });
|
||||
|
||||
this.iTimer = 0;
|
||||
this.oThemeAjaxRequest = null;
|
||||
|
||||
this.theme.subscribe((value) => {
|
||||
this.themesObjects().forEach(theme => {
|
||||
theme.selected(value === theme.name);
|
||||
|
|
|
@ -160,9 +160,9 @@ class FolderUserStore {
|
|||
folder &&
|
||||
inboxFolderName !== folder.fullNameRaw &&
|
||||
folder.selectable &&
|
||||
folder.existen &&
|
||||
folder.exists &&
|
||||
timeout > folder.interval &&
|
||||
(folder.isSystemFolder() || (folder.subScribed() && folder.checkable()))
|
||||
(folder.isSystemFolder() || (folder.subscribed() && folder.checkable()))
|
||||
) {
|
||||
timeouts.push([folder.interval, folder.fullNameRaw]);
|
||||
}
|
||||
|
|
|
@ -23,29 +23,33 @@ class LoginAdminView extends AbstractViewNext {
|
|||
|
||||
this.hideSubmitButton = appSettingsGet('hideSubmitButton');
|
||||
|
||||
this.login = ko.observable('');
|
||||
this.password = ko.observable('');
|
||||
this.addObservables({
|
||||
login: '',
|
||||
password: '',
|
||||
|
||||
this.loginError = ko.observable(false);
|
||||
this.passwordError = ko.observable(false);
|
||||
loginError: false,
|
||||
passwordError: false,
|
||||
|
||||
formHidden: false,
|
||||
|
||||
submitRequest: false,
|
||||
submitError: ''
|
||||
});
|
||||
|
||||
this.loginErrorAnimation = ko.observable(false).extend({ 'falseTimeout': 500 });
|
||||
this.passwordErrorAnimation = ko.observable(false).extend({ 'falseTimeout': 500 });
|
||||
|
||||
this.formHidden = ko.observable(false);
|
||||
|
||||
this.formError = ko.computed(() => this.loginErrorAnimation() || this.passwordErrorAnimation());
|
||||
|
||||
this.login.subscribe(() => this.loginError(false));
|
||||
this.addSubscribables({
|
||||
login: () => this.loginError(false),
|
||||
|
||||
this.password.subscribe(() => this.passwordError(false));
|
||||
password: () => this.passwordError(false),
|
||||
|
||||
this.loginError.subscribe(v => this.loginErrorAnimation(!!v));
|
||||
loginError: v => this.loginErrorAnimation(!!v),
|
||||
|
||||
this.passwordError.subscribe(v => this.passwordErrorAnimation(!!v));
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
this.submitError = ko.observable('');
|
||||
passwordError: v => this.passwordErrorAnimation(!!v)
|
||||
});
|
||||
}
|
||||
|
||||
@command((self) => !self.submitRequest())
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { StorageResultType, Notification } from 'Common/Enums';
|
||||
import { getNotification } from 'Common/Translator';
|
||||
|
||||
|
@ -16,27 +14,25 @@ class AccountPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.isNew = ko.observable(true);
|
||||
this.addObservables({
|
||||
isNew: true,
|
||||
|
||||
this.email = ko.observable('');
|
||||
this.password = ko.observable('');
|
||||
email: '',
|
||||
password: '',
|
||||
|
||||
this.emailError = ko.observable(false);
|
||||
this.passwordError = ko.observable(false);
|
||||
emailError: false,
|
||||
passwordError: false,
|
||||
|
||||
this.email.subscribe(() => {
|
||||
this.emailError(false);
|
||||
submitRequest: false,
|
||||
submitError: '',
|
||||
submitErrorAdditional: '',
|
||||
|
||||
emailFocus: false
|
||||
});
|
||||
|
||||
this.password.subscribe(() => {
|
||||
this.passwordError(false);
|
||||
});
|
||||
this.email.subscribe(() => this.emailError(false));
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
this.submitError = ko.observable('');
|
||||
this.submitErrorAdditional = ko.observable('');
|
||||
|
||||
this.emailFocus = ko.observable(false);
|
||||
this.password.subscribe(() => this.passwordError(false));
|
||||
}
|
||||
|
||||
@command((self) => !self.submitRequest())
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import PgpStore from 'Stores/User/Pgp';
|
||||
|
||||
import { popup, command } from 'Knoin/Knoin';
|
||||
|
@ -13,13 +11,15 @@ class AddOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.key = ko.observable('');
|
||||
this.key.error = ko.observable(false);
|
||||
this.key.errorMessage = ko.observable('');
|
||||
this.addObservables({
|
||||
key: '',
|
||||
keyError: false,
|
||||
keyErrorMessage: ''
|
||||
});
|
||||
|
||||
this.key.subscribe(() => {
|
||||
this.key.error(false);
|
||||
this.key.errorMessage('');
|
||||
this.keyError(false);
|
||||
this.keyErrorMessage('');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -35,10 +35,10 @@ class AddOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
keyTrimmed = keyTrimmed.replace(/[\r]+/g, '').replace(/[\n]{2,}/g, '\n\n');
|
||||
}
|
||||
|
||||
this.key.error(!keyTrimmed);
|
||||
this.key.errorMessage('');
|
||||
this.keyError(!keyTrimmed);
|
||||
this.keyErrorMessage('');
|
||||
|
||||
if (!openpgpKeyring || this.key.error()) {
|
||||
if (!openpgpKeyring || this.keyError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -58,8 +58,8 @@ class AddOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
}
|
||||
|
||||
if (err) {
|
||||
this.key.error(true);
|
||||
this.key.errorMessage(err && err[0] ? '' + err[0] : '');
|
||||
this.keyError(true);
|
||||
this.keyErrorMessage(err && err[0] ? '' + err[0] : '');
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ class AddOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
|
||||
rl.app.reloadOpenPgpKeys();
|
||||
|
||||
if (this.key.error()) {
|
||||
if (this.keyError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -85,8 +85,8 @@ class AddOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
|
||||
clearPopup() {
|
||||
this.key('');
|
||||
this.key.error(false);
|
||||
this.key.errorMessage('');
|
||||
this.keyError(false);
|
||||
this.keyErrorMessage('');
|
||||
}
|
||||
|
||||
onShow() {
|
||||
|
|
|
@ -15,17 +15,19 @@ class AdvancedSearchPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.fromFocus = ko.observable(false);
|
||||
this.addObservables({
|
||||
fromFocus: false,
|
||||
|
||||
this.from = ko.observable('');
|
||||
this.to = ko.observable('');
|
||||
this.subject = ko.observable('');
|
||||
this.text = ko.observable('');
|
||||
this.selectedDateValue = ko.observable(-1);
|
||||
from: '',
|
||||
to: '',
|
||||
subject: '',
|
||||
text: '',
|
||||
selectedDateValue: -1,
|
||||
|
||||
this.hasAttachment = ko.observable(false);
|
||||
this.starred = ko.observable(false);
|
||||
this.unseen = ko.observable(false);
|
||||
hasAttachment: false,
|
||||
starred: false,
|
||||
unseen: false
|
||||
});
|
||||
|
||||
this.selectedDates = ko.computed(() => {
|
||||
translatorTrigger();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { KeyState } from 'Common/Enums';
|
||||
import { i18n } from 'Common/Translator';
|
||||
|
||||
|
@ -14,9 +12,11 @@ class AskPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.askDesc = ko.observable('');
|
||||
this.yesButton = ko.observable('');
|
||||
this.noButton = ko.observable('');
|
||||
this.addObservables({
|
||||
askDesc: '',
|
||||
yesButton: '',
|
||||
noButton: ''
|
||||
});
|
||||
|
||||
this.fYesAction = null;
|
||||
this.fNoAction = null;
|
||||
|
|
|
@ -132,150 +132,86 @@ class ComposePopupView extends AbstractViewNext {
|
|||
|
||||
this.capaOpenPGP = PgpStore.capaOpenPGP;
|
||||
|
||||
this.identitiesDropdownTrigger = ko.observable(false);
|
||||
this.identities = IdentityStore.identities;
|
||||
|
||||
this.to = ko.observable('');
|
||||
this.to.focused = ko.observable(false);
|
||||
this.cc = ko.observable('');
|
||||
this.cc.focused = ko.observable(false);
|
||||
this.bcc = ko.observable('');
|
||||
this.bcc.focused = ko.observable(false);
|
||||
this.replyTo = ko.observable('');
|
||||
this.replyTo.focused = ko.observable(false);
|
||||
this.addObservables({
|
||||
identitiesDropdownTrigger: false,
|
||||
|
||||
to: '',
|
||||
toFocused: false,
|
||||
cc: '',
|
||||
ccFocused: false,
|
||||
bcc: '',
|
||||
bccFocused: false,
|
||||
replyTo: '',
|
||||
replyToFocused: false,
|
||||
|
||||
subject: '',
|
||||
subjectFocused: false,
|
||||
|
||||
isHtml: false,
|
||||
|
||||
requestDsn: false,
|
||||
requestReadReceipt: false,
|
||||
markAsImportant: false,
|
||||
|
||||
sendError: false,
|
||||
sendSuccessButSaveError: false,
|
||||
savedError: false,
|
||||
|
||||
sendErrorDesc: '',
|
||||
savedErrorDesc: '',
|
||||
|
||||
savedTime: 0,
|
||||
|
||||
emptyToError: false,
|
||||
|
||||
attachmentsInProcessError: false,
|
||||
attachmentsInErrorError: false,
|
||||
|
||||
showCc: false,
|
||||
showBcc: false,
|
||||
showReplyTo: false,
|
||||
|
||||
draftFolder: '',
|
||||
draftUid: '',
|
||||
sending: false,
|
||||
saving: false,
|
||||
|
||||
attachmentsPlace: false,
|
||||
|
||||
composeUploaderButton: null,
|
||||
composeUploaderDropPlace: null,
|
||||
dragAndDropEnabled: false,
|
||||
attacheMultipleAllowed: false,
|
||||
addAttachmentEnabled: false,
|
||||
|
||||
composeEditorArea: null,
|
||||
|
||||
currentIdentity: this.identities()[0] ? this.identities()[0] : null
|
||||
});
|
||||
|
||||
// this.to.subscribe((v) => console.log(v));
|
||||
|
||||
ko.computed(() => {
|
||||
switch (true) {
|
||||
case this.to.focused():
|
||||
case this.toFocused():
|
||||
this.sLastFocusedField = 'to';
|
||||
break;
|
||||
case this.cc.focused():
|
||||
case this.ccFocused():
|
||||
this.sLastFocusedField = 'cc';
|
||||
break;
|
||||
case this.bcc.focused():
|
||||
case this.bccFocused():
|
||||
this.sLastFocusedField = 'bcc';
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
}).extend({ notify: 'always' });
|
||||
|
||||
this.subject = ko.observable('');
|
||||
this.subject.focused = ko.observable(false);
|
||||
|
||||
this.isHtml = ko.observable(false);
|
||||
|
||||
this.requestDsn = ko.observable(false);
|
||||
this.requestReadReceipt = ko.observable(false);
|
||||
this.markAsImportant = ko.observable(false);
|
||||
|
||||
this.sendError = ko.observable(false);
|
||||
this.sendSuccessButSaveError = ko.observable(false);
|
||||
this.savedError = ko.observable(false);
|
||||
|
||||
this.sendButtonSuccess = ko.computed(() => !this.sendError() && !this.sendSuccessButSaveError());
|
||||
|
||||
this.sendErrorDesc = ko.observable('');
|
||||
this.savedErrorDesc = ko.observable('');
|
||||
|
||||
this.sendError.subscribe(value => !value && this.sendErrorDesc(''));
|
||||
|
||||
this.savedError.subscribe(value => !value && this.savedErrorDesc(''));
|
||||
|
||||
this.sendSuccessButSaveError.subscribe(value => !value && this.savedErrorDesc(''));
|
||||
|
||||
this.savedTime = ko.observable(0);
|
||||
this.savedTimeText = ko.computed(() =>
|
||||
this.savedTime()
|
||||
? i18n('COMPOSE/SAVED_TIME', { 'TIME': this.savedTime().format('LT') })
|
||||
: ''
|
||||
);
|
||||
|
||||
this.emptyToError = ko.observable(false);
|
||||
this.emptyToErrorTooltip = ko.computed(() => (this.emptyToError() ? i18n('COMPOSE/EMPTY_TO_ERROR_DESC') : ''));
|
||||
|
||||
this.attachmentsInProcessError = ko.observable(false);
|
||||
this.attachmentsInErrorError = ko.observable(false);
|
||||
|
||||
this.attachmentsErrorTooltip = ko.computed(() => {
|
||||
let result = '';
|
||||
switch (true) {
|
||||
case this.attachmentsInProcessError():
|
||||
result = i18n('COMPOSE/ATTACHMENTS_UPLOAD_ERROR_DESC');
|
||||
break;
|
||||
case this.attachmentsInErrorError():
|
||||
result = i18n('COMPOSE/ATTACHMENTS_ERROR_DESC');
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
this.showCc = ko.observable(false);
|
||||
this.showBcc = ko.observable(false);
|
||||
this.showReplyTo = ko.observable(false);
|
||||
|
||||
this.cc.subscribe((value) => {
|
||||
if (false === this.showCc() && value.length) {
|
||||
this.showCc(true);
|
||||
}
|
||||
});
|
||||
|
||||
this.bcc.subscribe((value) => {
|
||||
if (false === this.showBcc() && value.length) {
|
||||
this.showBcc(true);
|
||||
}
|
||||
});
|
||||
|
||||
this.replyTo.subscribe((value) => {
|
||||
if (false === this.showReplyTo() && value.length) {
|
||||
this.showReplyTo(true);
|
||||
}
|
||||
});
|
||||
|
||||
this.draftFolder = ko.observable('');
|
||||
this.draftUid = ko.observable('');
|
||||
this.sending = ko.observable(false);
|
||||
this.saving = ko.observable(false);
|
||||
this.attachments = ko.observableArray([]);
|
||||
|
||||
this.attachmentsInProcess = ko.computed(() => this.attachments().filter(item => item && !item.complete()));
|
||||
this.attachmentsInReady = ko.computed(() => this.attachments().filter(item => item && item.complete()));
|
||||
this.attachmentsInError = ko.computed(() => this.attachments().filter(item => item && item.error()));
|
||||
|
||||
this.attachmentsCount = ko.computed(() => this.attachments().length);
|
||||
this.attachmentsInErrorCount = ko.computed(() => this.attachmentsInError().length);
|
||||
this.attachmentsInProcessCount = ko.computed(() => this.attachmentsInProcess().length);
|
||||
this.isDraftFolderMessage = ko.computed(() => this.draftFolder() && this.draftUid());
|
||||
|
||||
this.attachmentsPlace = ko.observable(false);
|
||||
|
||||
this.attachmentsInErrorCount.subscribe((value) => {
|
||||
if (0 === value) {
|
||||
this.attachmentsInErrorError(false);
|
||||
}
|
||||
});
|
||||
|
||||
this.composeUploaderButton = ko.observable(null);
|
||||
this.composeUploaderDropPlace = ko.observable(null);
|
||||
this.dragAndDropEnabled = ko.observable(false);
|
||||
this.dragAndDropOver = ko.observable(false).extend({ throttle: 1 });
|
||||
this.dragAndDropVisible = ko.observable(false).extend({ throttle: 1 });
|
||||
this.attacheMultipleAllowed = ko.observable(false);
|
||||
this.addAttachmentEnabled = ko.observable(false);
|
||||
|
||||
this.composeEditorArea = ko.observable(null);
|
||||
|
||||
this.identities = IdentityStore.identities;
|
||||
this.identitiesOptions = ko.computed(() =>
|
||||
IdentityStore.identities().map(item => ({
|
||||
'item': item,
|
||||
'optValue': item.id(),
|
||||
'optText': item.formattedName()
|
||||
}))
|
||||
);
|
||||
|
||||
this.currentIdentity = ko.observable(this.identities()[0] ? this.identities()[0] : null);
|
||||
|
||||
this.currentIdentity.extend({
|
||||
toggleSubscribe: [
|
||||
|
@ -291,24 +227,105 @@ class ComposePopupView extends AbstractViewNext {
|
|||
]
|
||||
});
|
||||
|
||||
this.currentIdentityView = ko.computed(() => {
|
||||
const item = this.currentIdentity();
|
||||
return item ? item.formattedName() : 'unknown';
|
||||
this.bDisabeCloseOnEsc = true;
|
||||
this.sDefaultKeyScope = KeyState.Compose;
|
||||
|
||||
this.tryToClosePopup = this.tryToClosePopup.debounce(200);
|
||||
|
||||
this.iTimer = 0;
|
||||
|
||||
this.addComputables({
|
||||
sendButtonSuccess: () => !this.sendError() && !this.sendSuccessButSaveError(),
|
||||
|
||||
savedTimeText: () =>
|
||||
this.savedTime() ? i18n('COMPOSE/SAVED_TIME', { 'TIME': this.savedTime().format('LT') }) : '',
|
||||
|
||||
emptyToErrorTooltip: () => (this.emptyToError() ? i18n('COMPOSE/EMPTY_TO_ERROR_DESC') : ''),
|
||||
|
||||
attachmentsErrorTooltip: () => {
|
||||
let result = '';
|
||||
switch (true) {
|
||||
case this.attachmentsInProcessError():
|
||||
result = i18n('COMPOSE/ATTACHMENTS_UPLOAD_ERROR_DESC');
|
||||
break;
|
||||
case this.attachmentsInErrorError():
|
||||
result = i18n('COMPOSE/ATTACHMENTS_ERROR_DESC');
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
attachmentsInProcess: () => this.attachments().filter(item => item && !item.complete()),
|
||||
attachmentsInReady: () => this.attachments().filter(item => item && item.complete()),
|
||||
attachmentsInError: () => this.attachments().filter(item => item && item.error()),
|
||||
|
||||
attachmentsCount: () => this.attachments().length,
|
||||
attachmentsInErrorCount: () => this.attachmentsInError().length,
|
||||
attachmentsInProcessCount: () => this.attachmentsInProcess().length,
|
||||
isDraftFolderMessage: () => this.draftFolder() && this.draftUid(),
|
||||
|
||||
identitiesOptions: () =>
|
||||
IdentityStore.identities().map(item => ({
|
||||
'item': item,
|
||||
'optValue': item.id(),
|
||||
'optText': item.formattedName()
|
||||
})),
|
||||
|
||||
currentIdentityView: () => {
|
||||
const item = this.currentIdentity();
|
||||
return item ? item.formattedName() : 'unknown';
|
||||
},
|
||||
|
||||
canBeSentOrSaved: () => !this.sending() && !this.saving()
|
||||
|
||||
});
|
||||
|
||||
this.to.subscribe((value) => {
|
||||
if (this.emptyToError() && value.length) {
|
||||
this.emptyToError(false);
|
||||
this.addSubscribables({
|
||||
sendError: value => !value && this.sendErrorDesc(''),
|
||||
|
||||
savedError: value => !value && this.savedErrorDesc(''),
|
||||
|
||||
sendSuccessButSaveError: value => !value && this.savedErrorDesc(''),
|
||||
|
||||
cc: value => {
|
||||
if (false === this.showCc() && value.length) {
|
||||
this.showCc(true);
|
||||
}
|
||||
},
|
||||
|
||||
bcc: value => {
|
||||
if (false === this.showBcc() && value.length) {
|
||||
this.showBcc(true);
|
||||
}
|
||||
},
|
||||
|
||||
replyTo: value => {
|
||||
if (false === this.showReplyTo() && value.length) {
|
||||
this.showReplyTo(true);
|
||||
}
|
||||
},
|
||||
|
||||
attachmentsInErrorCount: value => {
|
||||
if (0 === value) {
|
||||
this.attachmentsInErrorError(false);
|
||||
}
|
||||
},
|
||||
|
||||
to: value => {
|
||||
if (this.emptyToError() && value.length) {
|
||||
this.emptyToError(false);
|
||||
}
|
||||
},
|
||||
|
||||
attachmentsInProcess: value => {
|
||||
if (this.attachmentsInProcessError() && Array.isNotEmpty(value)) {
|
||||
this.attachmentsInProcessError(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.attachmentsInProcess.subscribe(value => {
|
||||
if (this.attachmentsInProcessError() && Array.isNotEmpty(value)) {
|
||||
this.attachmentsInProcessError(false);
|
||||
}
|
||||
});
|
||||
|
||||
this.canBeSentOrSaved = ko.computed(() => !this.sending() && !this.saving());
|
||||
this.resizeObserver = new ResizeObserver(this.resizerTrigger.throttle(50).bind(this));
|
||||
|
||||
setInterval(() => {
|
||||
if (
|
||||
|
@ -323,15 +340,6 @@ class ComposePopupView extends AbstractViewNext {
|
|||
this.saveCommand();
|
||||
}
|
||||
}, 120000);
|
||||
|
||||
this.bDisabeCloseOnEsc = true;
|
||||
this.sDefaultKeyScope = KeyState.Compose;
|
||||
|
||||
this.tryToClosePopup = this.tryToClosePopup.debounce(200);
|
||||
|
||||
this.iTimer = 0;
|
||||
|
||||
this.resizeObserver = new ResizeObserver(this.resizerTrigger.throttle(50).bind(this));
|
||||
}
|
||||
|
||||
getMessageRequestParams(sSaveFolder)
|
||||
|
@ -677,7 +685,7 @@ class ComposePopupView extends AbstractViewNext {
|
|||
|
||||
this.bSkipNextHide = false;
|
||||
|
||||
this.to.focused(false);
|
||||
this.toFocused(false);
|
||||
|
||||
rl.route.on();
|
||||
|
||||
|
@ -1120,9 +1128,9 @@ class ComposePopupView extends AbstractViewNext {
|
|||
// rl.settings.app('mobile') ||
|
||||
setTimeout(() => {
|
||||
if (!this.to()) {
|
||||
this.to.focused(true);
|
||||
this.toFocused(true);
|
||||
} else if (this.oEditor) {
|
||||
if (!this.to.focused()) {
|
||||
if (!this.toFocused()) {
|
||||
this.oEditor.focus();
|
||||
}
|
||||
}
|
||||
|
@ -1222,10 +1230,7 @@ class ComposePopupView extends AbstractViewNext {
|
|||
if (attachment) {
|
||||
this.attachments.remove(attachment);
|
||||
delegateRunOnDestroy(attachment);
|
||||
|
||||
if (oJua) {
|
||||
oJua.cancel(id);
|
||||
}
|
||||
oJua && oJua.cancel(id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -25,57 +25,59 @@ class ComposeOpenPgpPopupView extends AbstractViewNext {
|
|||
this.publicKeysOptionsCaption = i18n('PGP_NOTIFICATIONS/ADD_A_PUBLICK_KEY');
|
||||
this.privateKeysOptionsCaption = i18n('PGP_NOTIFICATIONS/SELECT_A_PRIVATE_KEY');
|
||||
|
||||
this.notification = ko.observable('');
|
||||
this.addObservables({
|
||||
notification: '',
|
||||
|
||||
this.sign = ko.observable(false);
|
||||
this.encrypt = ko.observable(false);
|
||||
sign: false,
|
||||
encrypt: false,
|
||||
|
||||
this.password = ko.observable('');
|
||||
password: '',
|
||||
|
||||
this.text = ko.observable('');
|
||||
this.selectedPrivateKey = ko.observable(null);
|
||||
this.selectedPublicKey = ko.observable(null);
|
||||
text: '',
|
||||
selectedPrivateKey: null,
|
||||
selectedPublicKey: null,
|
||||
|
||||
this.signKey = ko.observable(null);
|
||||
signKey: null,
|
||||
|
||||
submitRequest: false
|
||||
});
|
||||
this.encryptKeys = ko.observableArray([]);
|
||||
|
||||
this.encryptKeysView = ko.computed(
|
||||
() => this.encryptKeys().map(oKey => (oKey ? oKey.key : null)).filter(v => v)
|
||||
);
|
||||
this.addComputables({
|
||||
encryptKeysView: () => this.encryptKeys().map(oKey => (oKey ? oKey.key : null)).filter(v => v),
|
||||
|
||||
this.privateKeysOptions = ko.computed(() => {
|
||||
const opts = PgpStore.openpgpkeysPrivate().map((oKey, iIndex) => {
|
||||
if (this.signKey() && this.signKey().key.id === oKey.id) {
|
||||
return null;
|
||||
}
|
||||
return oKey.users.map(user => ({
|
||||
'id': oKey.guid,
|
||||
'name': '(' + oKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() + ') ' + user,
|
||||
'key': oKey,
|
||||
'class': iIndex % 2 ? 'odd' : 'even'
|
||||
}));
|
||||
});
|
||||
privateKeysOptions: () => {
|
||||
const opts = PgpStore.openpgpkeysPrivate().map((oKey, iIndex) => {
|
||||
if (this.signKey() && this.signKey().key.id === oKey.id) {
|
||||
return null;
|
||||
}
|
||||
return oKey.users.map(user => ({
|
||||
'id': oKey.guid,
|
||||
'name': '(' + oKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() + ') ' + user,
|
||||
'key': oKey,
|
||||
'class': iIndex % 2 ? 'odd' : 'even'
|
||||
}));
|
||||
});
|
||||
|
||||
return opts.flat().filter(v => v);
|
||||
return opts.flat().filter(v => v);
|
||||
},
|
||||
|
||||
publicKeysOptions: () => {
|
||||
const opts = PgpStore.openpgpkeysPublic().map((oKey, index) => {
|
||||
if (this.encryptKeysView().includes(oKey)) {
|
||||
return null;
|
||||
}
|
||||
return oKey.users.map(user => ({
|
||||
'id': oKey.guid,
|
||||
'name': '(' + oKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() + ') ' + user,
|
||||
'key': oKey,
|
||||
'class': index % 2 ? 'odd' : 'even'
|
||||
}));
|
||||
});
|
||||
return opts.flat().filter(v => v);
|
||||
}
|
||||
});
|
||||
|
||||
this.publicKeysOptions = ko.computed(() => {
|
||||
const opts = PgpStore.openpgpkeysPublic().map((oKey, index) => {
|
||||
if (this.encryptKeysView().includes(oKey)) {
|
||||
return null;
|
||||
}
|
||||
return oKey.users.map(user => ({
|
||||
'id': oKey.guid,
|
||||
'name': '(' + oKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() + ') ' + user,
|
||||
'key': oKey,
|
||||
'class': index % 2 ? 'odd' : 'even'
|
||||
}));
|
||||
});
|
||||
return opts.flat().filter(v => v);
|
||||
});
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
|
||||
this.resultCallback = null;
|
||||
|
||||
this.selectedPrivateKey.subscribe((value) => {
|
||||
|
|
|
@ -46,81 +46,36 @@ class ContactsPopupView extends AbstractViewNext {
|
|||
this.allowContactsSync = ContactStore.allowContactsSync;
|
||||
this.enableContactsSync = ContactStore.enableContactsSync;
|
||||
|
||||
this.search = ko.observable('');
|
||||
this.contactsCount = ko.observable(0);
|
||||
this.contacts = ContactStore.contacts;
|
||||
this.addObservables({
|
||||
search: '',
|
||||
contactsCount: 0,
|
||||
|
||||
this.currentContact = ko.observable(null);
|
||||
currentContact: null,
|
||||
|
||||
this.importUploaderButton = ko.observable(null);
|
||||
importUploaderButton: null,
|
||||
|
||||
this.contactsPage = ko.observable(1);
|
||||
this.contactsPageCount = ko.computed(() =>
|
||||
Math.max(1, Math.ceil(this.contactsCount() / CONTACTS_PER_PAGE))
|
||||
);
|
||||
contactsPage: 1,
|
||||
|
||||
this.contactsPaginator = ko.computed(computedPaginatorHelper(this.contactsPage, this.contactsPageCount));
|
||||
emptySelection: true,
|
||||
viewClearSearch: false,
|
||||
|
||||
this.emptySelection = ko.observable(true);
|
||||
this.viewClearSearch = ko.observable(false);
|
||||
viewID: '',
|
||||
viewReadOnly: false,
|
||||
|
||||
this.viewID = ko.observable('');
|
||||
this.viewReadOnly = ko.observable(false);
|
||||
this.viewProperties = ko.observableArray([]);
|
||||
viewSaveTrigger: SaveSettingsStep.Idle,
|
||||
|
||||
this.viewSaveTrigger = ko.observable(SaveSettingsStep.Idle);
|
||||
viewSaving: false,
|
||||
|
||||
this.viewPropertiesNames = ko.computed(() =>
|
||||
this.viewProperties().filter(
|
||||
property => [ContactPropertyType.FirstName, ContactPropertyType.LastName].includes(property.type())
|
||||
)
|
||||
);
|
||||
this.viewPropertiesOther = ko.computed(() =>
|
||||
this.viewProperties().filter(property => [ContactPropertyType.Nick].includes(property.type()))
|
||||
);
|
||||
|
||||
this.viewPropertiesEmails = ko.computed(() =>
|
||||
this.viewProperties().filter(property => ContactPropertyType.Email === property.type())
|
||||
);
|
||||
|
||||
this.viewPropertiesWeb = ko.computed(() =>
|
||||
this.viewProperties().filter(property => ContactPropertyType.Web === property.type())
|
||||
);
|
||||
|
||||
this.viewHasNonEmptyRequiredProperties = ko.computed(() => {
|
||||
const names = this.viewPropertiesNames(),
|
||||
emails = this.viewPropertiesEmails(),
|
||||
fFilter = property => !!trim(property.value());
|
||||
|
||||
return !!(names.find(fFilter) || emails.find(fFilter));
|
||||
watchDirty: false,
|
||||
watchHash: false
|
||||
});
|
||||
|
||||
this.viewPropertiesPhones = ko.computed(() =>
|
||||
this.viewProperties().filter(property => ContactPropertyType.Phone === property.type())
|
||||
);
|
||||
this.contacts = ContactStore.contacts;
|
||||
|
||||
this.viewPropertiesEmailsNonEmpty = ko.computed(() =>
|
||||
this.viewPropertiesNames().filter(property => !!trim(property.value()))
|
||||
);
|
||||
this.viewProperties = ko.observableArray([]);
|
||||
|
||||
const propertyFocused = property => !trim(property.value()) && !property.focused();
|
||||
|
||||
this.viewPropertiesEmailsEmptyAndOnFocused = ko.computed(() =>
|
||||
this.viewPropertiesEmails().filter(propertyFocused)
|
||||
);
|
||||
|
||||
this.viewPropertiesPhonesEmptyAndOnFocused = ko.computed(() =>
|
||||
this.viewPropertiesPhones().filter(propertyFocused)
|
||||
);
|
||||
|
||||
this.viewPropertiesWebEmptyAndOnFocused = ko.computed(() =>
|
||||
this.viewPropertiesWeb().filter(propertyFocused)
|
||||
);
|
||||
|
||||
this.viewPropertiesOtherEmptyAndOnFocused = ko.computed(() =>
|
||||
this.viewPropertiesOther().filter(propertyFocused)
|
||||
);
|
||||
|
||||
/*
|
||||
// Somehow this is broken now when calling addNewProperty
|
||||
const fFastClearEmptyListHelper = list => {
|
||||
|
@ -129,33 +84,18 @@ class ContactsPopupView extends AbstractViewNext {
|
|||
delegateRunOnDestroy(list);
|
||||
}
|
||||
};
|
||||
this.viewPropertiesEmailsEmptyAndOnFocused.subscribe(fFastClearEmptyListHelper);
|
||||
this.viewPropertiesPhonesEmptyAndOnFocused.subscribe(fFastClearEmptyListHelper);
|
||||
this.viewPropertiesWebEmptyAndOnFocused.subscribe(fFastClearEmptyListHelper);
|
||||
this.viewPropertiesOtherEmptyAndOnFocused.subscribe(fFastClearEmptyListHelper);
|
||||
this.addSubscribables({
|
||||
viewPropertiesEmailsEmptyAndOnFocused: fFastClearEmptyListHelper,
|
||||
viewPropertiesPhonesEmptyAndOnFocused: fFastClearEmptyListHelper,
|
||||
viewPropertiesWebEmptyAndOnFocused: fFastClearEmptyListHelper,
|
||||
viewPropertiesOtherEmptyAndOnFocused: fFastClearEmptyListHelper
|
||||
});
|
||||
*/
|
||||
|
||||
this.viewSaving = ko.observable(false);
|
||||
|
||||
this.useCheckboxesInList = SettingsStore.useCheckboxesInList;
|
||||
|
||||
this.search.subscribe(() => this.reloadContactList());
|
||||
|
||||
this.contactsChecked = ko.computed(() => this.contacts().filter(item => item.checked()));
|
||||
|
||||
this.contactsCheckedOrSelected = ko.computed(() => {
|
||||
const checked = this.contactsChecked(),
|
||||
selected = this.currentContact();
|
||||
|
||||
return selected
|
||||
? checked.concat([selected]).unique()
|
||||
: checked;
|
||||
});
|
||||
|
||||
this.contactsCheckedOrSelectedUids = ko.computed(() =>
|
||||
this.contactsCheckedOrSelected().map(contact => contact.id)
|
||||
);
|
||||
|
||||
this.selector = new Selector(
|
||||
this.contacts,
|
||||
this.currentContact,
|
||||
|
@ -177,11 +117,6 @@ class ContactsPopupView extends AbstractViewNext {
|
|||
|
||||
this.bDropPageAfterDelete = false;
|
||||
|
||||
this.watchDirty = ko.observable(false);
|
||||
this.watchHash = ko.observable(false);
|
||||
|
||||
this.viewHash = ko.computed(() => '' + this.viewProperties().map(oItem => oItem.value()).join(''));
|
||||
|
||||
// this.saveCommandDebounce = _.debounce(this.saveCommand.bind(this), 1000);
|
||||
|
||||
this.viewHash.subscribe(() => {
|
||||
|
@ -191,6 +126,61 @@ class ContactsPopupView extends AbstractViewNext {
|
|||
});
|
||||
|
||||
this.sDefaultKeyScope = KeyState.ContactList;
|
||||
|
||||
this.addComputables({
|
||||
contactsPageCount: () => Math.max(1, Math.ceil(this.contactsCount() / CONTACTS_PER_PAGE)),
|
||||
|
||||
contactsPaginator: computedPaginatorHelper(this.contactsPage, this.contactsPageCount),
|
||||
|
||||
viewPropertiesNames: () =>
|
||||
this.viewProperties().filter(
|
||||
property => [ContactPropertyType.FirstName, ContactPropertyType.LastName].includes(property.type())
|
||||
),
|
||||
|
||||
viewPropertiesOther: () =>
|
||||
this.viewProperties().filter(property => [ContactPropertyType.Nick].includes(property.type())),
|
||||
|
||||
viewPropertiesEmails: () =>
|
||||
this.viewProperties().filter(property => ContactPropertyType.Email === property.type()),
|
||||
|
||||
viewPropertiesWeb: () => this.viewProperties().filter(property => ContactPropertyType.Web === property.type()),
|
||||
|
||||
viewHasNonEmptyRequiredProperties: () => {
|
||||
const names = this.viewPropertiesNames(),
|
||||
emails = this.viewPropertiesEmails(),
|
||||
fFilter = property => !!trim(property.value());
|
||||
|
||||
return !!(names.find(fFilter) || emails.find(fFilter));
|
||||
},
|
||||
|
||||
viewPropertiesPhones: () =>
|
||||
this.viewProperties().filter(property => ContactPropertyType.Phone === property.type()),
|
||||
|
||||
viewPropertiesEmailsNonEmpty: () => this.viewPropertiesNames().filter(property => !!trim(property.value())),
|
||||
|
||||
viewPropertiesEmailsEmptyAndOnFocused: () => this.viewPropertiesEmails().filter(propertyFocused),
|
||||
|
||||
viewPropertiesPhonesEmptyAndOnFocused: () => this.viewPropertiesPhones().filter(propertyFocused),
|
||||
|
||||
viewPropertiesWebEmptyAndOnFocused: () => this.viewPropertiesWeb().filter(propertyFocused),
|
||||
|
||||
viewPropertiesOtherEmptyAndOnFocused: () => this.viewPropertiesOther().filter(propertyFocused),
|
||||
|
||||
contactsChecked: () => this.contacts().filter(item => item.checked()),
|
||||
|
||||
contactsCheckedOrSelected: () => {
|
||||
const checked = this.contactsChecked(),
|
||||
selected = this.currentContact();
|
||||
|
||||
return selected
|
||||
? checked.concat([selected]).unique()
|
||||
: checked;
|
||||
},
|
||||
|
||||
contactsCheckedOrSelectedUids: () => this.contactsCheckedOrSelected().map(contact => contact.id),
|
||||
|
||||
viewHash: () => '' + this.viewProperties().map(oItem => oItem.value()).join('')
|
||||
});
|
||||
}
|
||||
|
||||
@command()
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { StorageResultType, ServerSecure, Notification } from 'Common/Enums';
|
||||
import { pInt, pString } from 'Common/Utils';
|
||||
import { i18n } from 'Common/Translator';
|
||||
|
@ -19,154 +17,155 @@ class DomainPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.edit = ko.observable(false);
|
||||
this.saving = ko.observable(false);
|
||||
this.savingError = ko.observable('');
|
||||
this.page = ko.observable('main');
|
||||
this.sieveSettings = ko.observable(false);
|
||||
this.addObservables({
|
||||
edit: false,
|
||||
saving: false,
|
||||
savingError: '',
|
||||
page: 'main',
|
||||
sieveSettings: false,
|
||||
|
||||
this.testing = ko.observable(false);
|
||||
this.testingDone = ko.observable(false);
|
||||
this.testingImapError = ko.observable(false);
|
||||
this.testingSieveError = ko.observable(false);
|
||||
this.testingSmtpError = ko.observable(false);
|
||||
this.testingImapErrorDesc = ko.observable('');
|
||||
this.testingSieveErrorDesc = ko.observable('');
|
||||
this.testingSmtpErrorDesc = ko.observable('');
|
||||
testing: false,
|
||||
testingDone: false,
|
||||
testingImapError: false,
|
||||
testingSieveError: false,
|
||||
testingSmtpError: false,
|
||||
testingImapErrorDesc: '',
|
||||
testingSieveErrorDesc: '',
|
||||
testingSmtpErrorDesc: '',
|
||||
|
||||
this.testingImapError.subscribe(value => value || this.testingImapErrorDesc(''));
|
||||
imapServerFocus: false,
|
||||
sieveServerFocus: false,
|
||||
smtpServerFocus: false,
|
||||
|
||||
this.testingSieveError.subscribe(value => value || this.testingSieveErrorDesc(''));
|
||||
name: '',
|
||||
|
||||
this.testingSmtpError.subscribe(value => value || this.testingSmtpErrorDesc(''));
|
||||
imapServer: '',
|
||||
imapPort: '143',
|
||||
imapSecure: ServerSecure.None,
|
||||
imapShortLogin: false,
|
||||
useSieve: false,
|
||||
sieveAllowRaw: false,
|
||||
sieveServer: '',
|
||||
sievePort: '4190',
|
||||
sieveSecure: ServerSecure.None,
|
||||
smtpServer: '',
|
||||
smtpPort: '25',
|
||||
smtpSecure: ServerSecure.None,
|
||||
smtpShortLogin: false,
|
||||
smtpAuth: true,
|
||||
smtpPhpMail: false,
|
||||
whiteList: '',
|
||||
aliasName: '',
|
||||
|
||||
this.imapServerFocus = ko.observable(false);
|
||||
this.sieveServerFocus = ko.observable(false);
|
||||
this.smtpServerFocus = ko.observable(false);
|
||||
enableSmartPorts: false
|
||||
});
|
||||
|
||||
this.name = ko.observable('');
|
||||
this.addSubscribables({
|
||||
testingImapError: value => value || this.testingImapErrorDesc(''),
|
||||
testingSieveError: value => value || this.testingSieveErrorDesc(''),
|
||||
testingSmtpError: value => value || this.testingSmtpErrorDesc(''),
|
||||
|
||||
this.imapServer = ko.observable('');
|
||||
this.imapPort = ko.observable('143');
|
||||
this.imapSecure = ko.observable(ServerSecure.None);
|
||||
this.imapShortLogin = ko.observable(false);
|
||||
this.useSieve = ko.observable(false);
|
||||
this.sieveAllowRaw = ko.observable(false);
|
||||
this.sieveServer = ko.observable('');
|
||||
this.sievePort = ko.observable('4190');
|
||||
this.sieveSecure = ko.observable(ServerSecure.None);
|
||||
this.smtpServer = ko.observable('');
|
||||
this.smtpPort = ko.observable('25');
|
||||
this.smtpSecure = ko.observable(ServerSecure.None);
|
||||
this.smtpShortLogin = ko.observable(false);
|
||||
this.smtpAuth = ko.observable(true);
|
||||
this.smtpPhpMail = ko.observable(false);
|
||||
this.whiteList = ko.observable('');
|
||||
this.aliasName = ko.observable('');
|
||||
page: () => this.sieveSettings(false),
|
||||
|
||||
this.enableSmartPorts = ko.observable(false);
|
||||
// smart form improvements
|
||||
imapServerFocus: value =>
|
||||
value && this.name() && !this.imapServer() && this.imapServer(this.name().replace(/[.]?[*][.]?/g, '')),
|
||||
|
||||
this.allowSieve = ko.computed(() => CapaAdminStore.filters() && CapaAdminStore.sieve());
|
||||
sieveServerFocus: value =>
|
||||
value && this.imapServer() && !this.sieveServer() && this.sieveServer(this.imapServer()),
|
||||
|
||||
this.headerText = ko.computed(() => {
|
||||
const name = this.name(),
|
||||
aliasName = this.aliasName();
|
||||
smtpServerFocus: value => value && this.imapServer() && !this.smtpServer()
|
||||
&& this.smtpServer(this.imapServer().replace(/imap/gi, 'smtp')),
|
||||
|
||||
let result = '';
|
||||
|
||||
if (this.edit()) {
|
||||
result = i18n('POPUPS_DOMAIN/TITLE_EDIT_DOMAIN', { 'NAME': name });
|
||||
if (aliasName) {
|
||||
result += ' ← ' + aliasName;
|
||||
imapSecure: value => {
|
||||
if (this.enableSmartPorts()) {
|
||||
const port = pInt(this.imapPort());
|
||||
switch (pString(value)) {
|
||||
case '0':
|
||||
case '2':
|
||||
if (993 === port) {
|
||||
this.imapPort('143');
|
||||
}
|
||||
break;
|
||||
case '1':
|
||||
if (143 === port) {
|
||||
this.imapPort('993');
|
||||
}
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
}
|
||||
} else {
|
||||
result = name
|
||||
? i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME', { 'NAME': name })
|
||||
: i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN');
|
||||
}
|
||||
},
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
this.domainDesc = ko.computed(() => {
|
||||
const name = this.name();
|
||||
return !this.edit() && name ? i18n('POPUPS_DOMAIN/NEW_DOMAIN_DESC', { 'NAME': '*@' + name }) : '';
|
||||
});
|
||||
|
||||
this.domainIsComputed = ko.computed(() => {
|
||||
const usePhpMail = this.smtpPhpMail(),
|
||||
allowSieve = this.allowSieve(),
|
||||
useSieve = this.useSieve();
|
||||
|
||||
return (
|
||||
this.name() &&
|
||||
this.imapServer() &&
|
||||
this.imapPort() &&
|
||||
(allowSieve && useSieve ? this.sieveServer() && this.sievePort() : true) &&
|
||||
((this.smtpServer() && this.smtpPort()) || usePhpMail)
|
||||
);
|
||||
});
|
||||
|
||||
this.canBeTested = ko.computed(() => !this.testing() && this.domainIsComputed());
|
||||
this.canBeSaved = ko.computed(() => !this.saving() && this.domainIsComputed());
|
||||
|
||||
this.page.subscribe(() => this.sieveSettings(false));
|
||||
|
||||
// smart form improvements
|
||||
this.imapServerFocus.subscribe(value =>
|
||||
value && this.name() && !this.imapServer() && this.imapServer(this.name().replace(/[.]?[*][.]?/g, ''))
|
||||
);
|
||||
|
||||
this.sieveServerFocus.subscribe(value =>
|
||||
value && this.imapServer() && !this.sieveServer() && this.sieveServer(this.imapServer())
|
||||
);
|
||||
|
||||
this.smtpServerFocus.subscribe(value =>
|
||||
value && this.imapServer() && !this.smtpServer() && this.smtpServer(this.imapServer().replace(/imap/gi, 'smtp'))
|
||||
);
|
||||
|
||||
this.imapSecure.subscribe(value => {
|
||||
if (this.enableSmartPorts()) {
|
||||
const port = pInt(this.imapPort());
|
||||
switch (pString(value)) {
|
||||
case '0':
|
||||
case '2':
|
||||
if (993 === port) {
|
||||
this.imapPort('143');
|
||||
}
|
||||
break;
|
||||
case '1':
|
||||
if (143 === port) {
|
||||
this.imapPort('993');
|
||||
}
|
||||
break;
|
||||
// no default
|
||||
smtpSecure: value => {
|
||||
if (this.enableSmartPorts()) {
|
||||
const port = pInt(this.smtpPort());
|
||||
switch (pString(value)) {
|
||||
case '0':
|
||||
if (465 === port || 587 === port) {
|
||||
this.smtpPort('25');
|
||||
}
|
||||
break;
|
||||
case '1':
|
||||
if (25 === port || 587 === port) {
|
||||
this.smtpPort('465');
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
if (25 === port || 465 === port) {
|
||||
this.smtpPort('587');
|
||||
}
|
||||
break;
|
||||
// no default
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.smtpSecure.subscribe(value => {
|
||||
if (this.enableSmartPorts()) {
|
||||
const port = pInt(this.smtpPort());
|
||||
switch (pString(value)) {
|
||||
case '0':
|
||||
if (465 === port || 587 === port) {
|
||||
this.smtpPort('25');
|
||||
}
|
||||
break;
|
||||
case '1':
|
||||
if (25 === port || 587 === port) {
|
||||
this.smtpPort('465');
|
||||
}
|
||||
break;
|
||||
case '2':
|
||||
if (25 === port || 465 === port) {
|
||||
this.smtpPort('587');
|
||||
}
|
||||
break;
|
||||
// no default
|
||||
this.addComputables({
|
||||
allowSieve: () => CapaAdminStore.filters() && CapaAdminStore.sieve(),
|
||||
|
||||
headerText: () => {
|
||||
const name = this.name(),
|
||||
aliasName = this.aliasName();
|
||||
|
||||
let result = '';
|
||||
|
||||
if (this.edit()) {
|
||||
result = i18n('POPUPS_DOMAIN/TITLE_EDIT_DOMAIN', { 'NAME': name });
|
||||
if (aliasName) {
|
||||
result += ' ← ' + aliasName;
|
||||
}
|
||||
} else {
|
||||
result = name
|
||||
? i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME', { 'NAME': name })
|
||||
: i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN');
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
domainDesc: () => {
|
||||
const name = this.name();
|
||||
return !this.edit() && name ? i18n('POPUPS_DOMAIN/NEW_DOMAIN_DESC', { 'NAME': '*@' + name }) : '';
|
||||
},
|
||||
|
||||
domainIsComputed: () => {
|
||||
const usePhpMail = this.smtpPhpMail(),
|
||||
allowSieve = this.allowSieve(),
|
||||
useSieve = this.useSieve();
|
||||
|
||||
return (
|
||||
this.name() &&
|
||||
this.imapServer() &&
|
||||
this.imapPort() &&
|
||||
(allowSieve && useSieve ? this.sieveServer() && this.sievePort() : true) &&
|
||||
((this.smtpServer() && this.smtpPort()) || usePhpMail)
|
||||
);
|
||||
},
|
||||
|
||||
canBeTested: () => !this.testing() && this.domainIsComputed(),
|
||||
canBeSaved: () => !this.saving() && this.domainIsComputed()
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -18,18 +18,18 @@ class DomainAliasPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.saving = ko.observable(false);
|
||||
this.savingError = ko.observable('');
|
||||
this.addObservables({
|
||||
saving: false,
|
||||
savingError: '',
|
||||
|
||||
this.name = ko.observable('');
|
||||
name: '',
|
||||
|
||||
this.alias = ko.observable('');
|
||||
alias: ''
|
||||
});
|
||||
|
||||
this.domains = DomainStore.domainsWithoutAliases;
|
||||
|
||||
this.domainsOptions = ko.computed(() =>
|
||||
this.domains().map(item => ({ optValue: item.name, optText: item.name }))
|
||||
);
|
||||
this.domainsOptions = ko.computed(() => this.domains().map(item => ({ optValue: item.name, optText: item.name })));
|
||||
|
||||
this.canBeSaved = ko.computed(() => !this.saving() && this.name() && this.alias());
|
||||
|
||||
|
|
|
@ -18,24 +18,21 @@ class FilterPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.isNew = ko.observable(true);
|
||||
this.addObservables({
|
||||
isNew: true,
|
||||
filter: null,
|
||||
allowMarkAsRead: false,
|
||||
selectedFolderValue: ''
|
||||
});
|
||||
|
||||
this.modules = FilterStore.modules;
|
||||
|
||||
this.fTrueCallback = null;
|
||||
this.filter = ko.observable(null);
|
||||
|
||||
this.allowMarkAsRead = ko.observable(false);
|
||||
|
||||
this.defaultOptionsAfterRender = defaultOptionsAfterRender;
|
||||
this.folderSelectList = FolderStore.folderMenuForFilters;
|
||||
this.selectedFolderValue = ko.observable('');
|
||||
|
||||
this.selectedFolderValue.subscribe(() => {
|
||||
if (this.filter()) {
|
||||
this.filter().actionValueError(false);
|
||||
}
|
||||
});
|
||||
this.selectedFolderValue.subscribe(() => this.filter() && this.filter().actionValueError(false));
|
||||
|
||||
this.actionTypeOptions = ko.observableArray([]);
|
||||
this.fieldOptions = ko.observableArray([]);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { StorageResultType, Notification } from 'Common/Enums';
|
||||
import { i18n, getNotification } from 'Common/Translator';
|
||||
import { setFolderHash } from 'Common/Cache';
|
||||
|
@ -19,23 +17,25 @@ class FolderClearPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.selectedFolder = ko.observable(null);
|
||||
this.clearingProcess = ko.observable(false);
|
||||
this.clearingError = ko.observable('');
|
||||
|
||||
this.folderFullNameForClear = ko.computed(() => {
|
||||
const folder = this.selectedFolder();
|
||||
return folder ? folder.printableFullName() : '';
|
||||
this.addObservables({
|
||||
selectedFolder: null,
|
||||
clearingProcess: false,
|
||||
clearingError: ''
|
||||
});
|
||||
|
||||
this.folderNameForClear = ko.computed(() => {
|
||||
const folder = this.selectedFolder();
|
||||
return folder ? folder.localName() : '';
|
||||
});
|
||||
this.addComputables({
|
||||
folderFullNameForClear: () => {
|
||||
const folder = this.selectedFolder();
|
||||
return folder ? folder.printableFullName() : '';
|
||||
},
|
||||
|
||||
this.dangerDescHtml = ko.computed(() =>
|
||||
i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { 'FOLDER': this.folderNameForClear() })
|
||||
);
|
||||
folderNameForClear: () => {
|
||||
const folder = this.selectedFolder();
|
||||
return folder ? folder.localName() : '';
|
||||
},
|
||||
|
||||
dangerDescHtml: () => i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { 'FOLDER': this.folderNameForClear() })
|
||||
});
|
||||
}
|
||||
|
||||
@command((self) => {
|
||||
|
|
|
@ -20,10 +20,12 @@ class FolderCreateView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.folderName = ko.observable('');
|
||||
this.folderName.focused = ko.observable(false);
|
||||
this.addObservables({
|
||||
folderName: '',
|
||||
folderNameFocused: false,
|
||||
|
||||
this.selectedParentValue = ko.observable(UNUSED_OPTION_VALUE);
|
||||
selectedParentValue: UNUSED_OPTION_VALUE
|
||||
});
|
||||
|
||||
this.parentFolderSelectList = ko.computed(() => {
|
||||
const top = [],
|
||||
|
@ -66,7 +68,7 @@ class FolderCreateView extends AbstractViewNext {
|
|||
clearPopup() {
|
||||
this.folderName('');
|
||||
this.selectedParentValue('');
|
||||
this.folderName.focused(false);
|
||||
this.folderNameFocused(false);
|
||||
}
|
||||
|
||||
onShow() {
|
||||
|
@ -75,7 +77,7 @@ class FolderCreateView extends AbstractViewNext {
|
|||
|
||||
onShowWithDelay() {
|
||||
// rl.settings.app('mobile') ||
|
||||
this.folderName.focused(true);
|
||||
this.folderNameFocused(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,11 +79,13 @@ class FolderSystemPopupView extends AbstractViewNext {
|
|||
fSaveSystemFolders();
|
||||
};
|
||||
|
||||
FolderStore.sentFolder.subscribe(fCallback);
|
||||
FolderStore.draftFolder.subscribe(fCallback);
|
||||
FolderStore.spamFolder.subscribe(fCallback);
|
||||
FolderStore.trashFolder.subscribe(fCallback);
|
||||
FolderStore.archiveFolder.subscribe(fCallback);
|
||||
ko.addSubscribablesTo(FolderStore, {
|
||||
sentFolder: fCallback,
|
||||
draftFolder: fCallback,
|
||||
spamFolder: fCallback,
|
||||
trashFolder: fCallback,
|
||||
archiveFolder: fCallback
|
||||
});
|
||||
|
||||
this.defaultOptionsAfterRender = defaultOptionsAfterRender;
|
||||
}
|
||||
|
|
|
@ -26,25 +26,27 @@ class IdentityPopupView extends AbstractViewNext {
|
|||
super();
|
||||
|
||||
this.id = '';
|
||||
this.edit = ko.observable(false);
|
||||
this.owner = ko.observable(false);
|
||||
this.addObservables({
|
||||
edit: false,
|
||||
owner: false,
|
||||
emailFocused: false,
|
||||
name: '',
|
||||
replyToFocused: false,
|
||||
bccFocused: false,
|
||||
|
||||
signature: '',
|
||||
signatureInsertBefore: false,
|
||||
|
||||
showBcc: false,
|
||||
showReplyTo: false,
|
||||
|
||||
submitRequest: false,
|
||||
submitError: ''
|
||||
});
|
||||
|
||||
this.email = ko.observable('').validateEmail();
|
||||
this.email.focused = ko.observable(false);
|
||||
this.name = ko.observable('');
|
||||
this.replyTo = ko.observable('').validateEmail();
|
||||
this.replyTo.focused = ko.observable(false);
|
||||
this.bcc = ko.observable('').validateEmail();
|
||||
this.bcc.focused = ko.observable(false);
|
||||
|
||||
this.signature = ko.observable('');
|
||||
this.signatureInsertBefore = ko.observable(false);
|
||||
|
||||
this.showBcc = ko.observable(false);
|
||||
this.showReplyTo = ko.observable(false);
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
this.submitError = ko.observable('');
|
||||
|
||||
this.bcc.subscribe((value) => {
|
||||
if (false === this.showBcc() && value.length) {
|
||||
|
@ -71,19 +73,19 @@ class IdentityPopupView extends AbstractViewNext {
|
|||
|
||||
if (this.email.hasError()) {
|
||||
if (!this.owner()) {
|
||||
this.email.focused(true);
|
||||
this.emailFocused(true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.replyTo.hasError()) {
|
||||
this.replyTo.focused(true);
|
||||
this.replyToFocused(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.bcc.hasError()) {
|
||||
this.bcc.focused(true);
|
||||
this.bccFocused(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -163,7 +165,7 @@ class IdentityPopupView extends AbstractViewNext {
|
|||
|
||||
onShowWithDelay() {
|
||||
if (!this.owner()/* && !rl.settings.app('mobile')*/) {
|
||||
this.email.focused(true);
|
||||
this.emailFocused(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,7 @@ class LanguagesPopupView extends AbstractViewNext {
|
|||
}));
|
||||
});
|
||||
|
||||
this.langs.subscribe(() => {
|
||||
this.setLanguageSelection();
|
||||
});
|
||||
this.langs.subscribe(() => this.setLanguageSelection());
|
||||
}
|
||||
|
||||
languageTooltipName(language) {
|
||||
|
|
|
@ -14,17 +14,16 @@ class MessageOpenPgpPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.notification = ko.observable('');
|
||||
|
||||
this.selectedKey = ko.observable(null);
|
||||
this.addObservables({
|
||||
notification: '',
|
||||
selectedKey: null,
|
||||
password: '',
|
||||
submitRequest: false
|
||||
});
|
||||
this.privateKeys = ko.observableArray([]);
|
||||
|
||||
this.password = ko.observable('');
|
||||
|
||||
this.resultCallback = null;
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
|
||||
this.sDefaultKeyScope = KeyState.PopupMessageOpenPGP;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { pInt } from 'Common/Utils';
|
||||
|
||||
import PgpStore from 'Stores/User/Pgp';
|
||||
|
@ -15,20 +13,20 @@ class NewOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.email = ko.observable('');
|
||||
this.email.focus = ko.observable('');
|
||||
this.email.error = ko.observable(false);
|
||||
this.addObservables({
|
||||
email: '',
|
||||
emailFocus: '',
|
||||
emailError: false,
|
||||
|
||||
this.name = ko.observable('');
|
||||
this.password = ko.observable('');
|
||||
this.keyBitLength = ko.observable(2048);
|
||||
name: '',
|
||||
password: '',
|
||||
keyBitLength: 2048,
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
this.submitError = ko.observable('');
|
||||
|
||||
this.email.subscribe(() => {
|
||||
this.email.error(false);
|
||||
submitRequest: false,
|
||||
submitError: ''
|
||||
});
|
||||
|
||||
this.email.subscribe(() => this.emailError(false));
|
||||
}
|
||||
|
||||
@command()
|
||||
|
@ -36,8 +34,8 @@ class NewOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
const userId = {},
|
||||
openpgpKeyring = PgpStore.openpgpKeyring;
|
||||
|
||||
this.email.error(!this.email().trim());
|
||||
if (!openpgpKeyring || this.email.error()) {
|
||||
this.emailError(!this.email().trim());
|
||||
if (!openpgpKeyring || this.emailError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -95,7 +93,7 @@ class NewOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
this.password('');
|
||||
|
||||
this.email('');
|
||||
this.email.error(false);
|
||||
this.emailError(false);
|
||||
this.keyBitLength(2048);
|
||||
|
||||
this.submitError('');
|
||||
|
@ -106,7 +104,7 @@ class NewOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
}
|
||||
|
||||
onShowWithDelay() {
|
||||
this.email.focus(true);
|
||||
this.emailFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,10 +18,11 @@ class PluginPopupView extends AbstractViewNext {
|
|||
|
||||
this.onPluginSettingsUpdateResponse = this.onPluginSettingsUpdateResponse.bind(this);
|
||||
|
||||
this.saveError = ko.observable('');
|
||||
|
||||
this.name = ko.observable('');
|
||||
this.readme = ko.observable('');
|
||||
this.addObservables({
|
||||
saveError: '',
|
||||
name: '',
|
||||
readme: ''
|
||||
});
|
||||
|
||||
this.configures = ko.observableArray([]);
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { StorageResultType, Notification } from 'Common/Enums';
|
||||
import { getNotification } from 'Common/Translator';
|
||||
import { HtmlEditor } from 'Common/HtmlEditor';
|
||||
|
@ -19,38 +17,37 @@ class TemplatePopupView extends AbstractViewNext {
|
|||
super();
|
||||
|
||||
this.editor = null;
|
||||
this.signatureDom = ko.observable(null);
|
||||
|
||||
this.id = ko.observable('');
|
||||
this.addObservables({
|
||||
signatureDom: null,
|
||||
|
||||
this.name = ko.observable('');
|
||||
this.name.error = ko.observable(false);
|
||||
this.name.focus = ko.observable(false);
|
||||
id: '',
|
||||
|
||||
this.body = ko.observable('');
|
||||
this.body.loading = ko.observable(false);
|
||||
this.body.error = ko.observable(false);
|
||||
name: '',
|
||||
nameError: false,
|
||||
nameFocus: false,
|
||||
|
||||
this.name.subscribe(() => {
|
||||
this.name.error(false);
|
||||
body: '',
|
||||
bodyLoading: false,
|
||||
bodyError: false,
|
||||
|
||||
submitRequest: false,
|
||||
submitError: ''
|
||||
});
|
||||
|
||||
this.body.subscribe(() => {
|
||||
this.body.error(false);
|
||||
});
|
||||
this.name.subscribe(() => this.nameError(false));
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
this.submitError = ko.observable('');
|
||||
this.body.subscribe(() => this.bodyError(false));
|
||||
}
|
||||
|
||||
@command((self) => !self.submitRequest())
|
||||
addTemplateCommand() {
|
||||
this.populateBodyFromEditor();
|
||||
|
||||
this.name.error(!this.name().trim());
|
||||
this.body.error(!this.body().trim() || ':HTML:' === this.body().trim());
|
||||
this.nameError(!this.name().trim());
|
||||
this.bodyError(!this.body().trim() || ':HTML:' === this.body().trim());
|
||||
|
||||
if (this.name.error() || this.body.error()) {
|
||||
if (this.nameError() || this.bodyError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -82,11 +79,11 @@ class TemplatePopupView extends AbstractViewNext {
|
|||
this.id('');
|
||||
|
||||
this.name('');
|
||||
this.name.error(false);
|
||||
this.nameError(false);
|
||||
|
||||
this.body('');
|
||||
this.body.loading(false);
|
||||
this.body.error(false);
|
||||
this.bodyLoading(false);
|
||||
this.bodyError(false);
|
||||
|
||||
this.submitRequest(false);
|
||||
this.submitError('');
|
||||
|
@ -125,11 +122,11 @@ class TemplatePopupView extends AbstractViewNext {
|
|||
if (template.populated) {
|
||||
this.editorSetBody(this.body());
|
||||
} else {
|
||||
this.body.loading(true);
|
||||
this.body.error(false);
|
||||
this.bodyLoading(true);
|
||||
this.bodyError(false);
|
||||
|
||||
Remote.templateGetById((result, data) => {
|
||||
this.body.loading(false);
|
||||
this.bodyLoading(false);
|
||||
|
||||
if (
|
||||
StorageResultType.Success === result &&
|
||||
|
@ -141,10 +138,10 @@ class TemplatePopupView extends AbstractViewNext {
|
|||
template.populated = true;
|
||||
|
||||
this.body(template.body);
|
||||
this.body.error(false);
|
||||
this.bodyError(false);
|
||||
} else {
|
||||
this.body('');
|
||||
this.body.error(true);
|
||||
this.bodyError(true);
|
||||
}
|
||||
|
||||
this.editorSetBody(this.body());
|
||||
|
@ -156,7 +153,7 @@ class TemplatePopupView extends AbstractViewNext {
|
|||
}
|
||||
|
||||
onShowWithDelay() {
|
||||
this.name.focus(true);
|
||||
this.nameFocus(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { Capa, StorageResultType } from 'Common/Enums';
|
||||
import { pString } from 'Common/Utils';
|
||||
import { i18n, trigger as translatorTrigger } from 'Common/Translator';
|
||||
|
@ -17,68 +15,72 @@ class TwoFactorConfigurationPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.lock = ko.observable(false);
|
||||
this.addObservables({
|
||||
lock: false,
|
||||
|
||||
processing: false,
|
||||
clearing: false,
|
||||
secreting: false,
|
||||
|
||||
viewUser: '',
|
||||
twoFactorStatus: false,
|
||||
|
||||
twoFactorTested: false,
|
||||
|
||||
viewSecret: '',
|
||||
viewBackupCodes: '',
|
||||
viewUrlTitle: '',
|
||||
viewUrl: '',
|
||||
|
||||
viewEnable_: false
|
||||
});
|
||||
|
||||
this.capaTwoFactor = rl.settings.capa(Capa.TwoFactor);
|
||||
|
||||
this.processing = ko.observable(false);
|
||||
this.clearing = ko.observable(false);
|
||||
this.secreting = ko.observable(false);
|
||||
|
||||
this.viewUser = ko.observable('');
|
||||
this.twoFactorStatus = ko.observable(false);
|
||||
|
||||
this.twoFactorTested = ko.observable(false);
|
||||
|
||||
this.viewSecret = ko.observable('');
|
||||
this.viewBackupCodes = ko.observable('');
|
||||
this.viewUrlTitle = ko.observable('');
|
||||
this.viewUrl = ko.observable('');
|
||||
|
||||
this.viewEnable_ = ko.observable(false);
|
||||
|
||||
this.viewEnable = ko.computed({
|
||||
read: this.viewEnable_,
|
||||
write: (value) => {
|
||||
value = !!value;
|
||||
if (value && this.twoFactorTested()) {
|
||||
this.viewEnable_(value);
|
||||
Remote.enableTwoFactor((result, data) => {
|
||||
if (StorageResultType.Success !== result || !data || !data.Result) {
|
||||
this.viewEnable_(false);
|
||||
}
|
||||
}, true);
|
||||
} else {
|
||||
if (!value) {
|
||||
this.addComputables({
|
||||
viewEnable: {
|
||||
read: this.viewEnable_,
|
||||
write: (value) => {
|
||||
value = !!value;
|
||||
if (value && this.twoFactorTested()) {
|
||||
this.viewEnable_(value);
|
||||
}
|
||||
|
||||
Remote.enableTwoFactor((result, data) => {
|
||||
if (StorageResultType.Success !== result || !data || !data.Result) {
|
||||
this.viewEnable_(false);
|
||||
Remote.enableTwoFactor((result, data) => {
|
||||
if (StorageResultType.Success !== result || !data || !data.Result) {
|
||||
this.viewEnable_(false);
|
||||
}
|
||||
}, true);
|
||||
} else {
|
||||
if (!value) {
|
||||
this.viewEnable_(value);
|
||||
}
|
||||
}, false);
|
||||
|
||||
Remote.enableTwoFactor((result, data) => {
|
||||
if (StorageResultType.Success !== result || !data || !data.Result) {
|
||||
this.viewEnable_(false);
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
this.viewTwoFactorEnableTooltip = ko.computed(() => {
|
||||
translatorTrigger();
|
||||
return this.twoFactorTested() || this.viewEnable_()
|
||||
? ''
|
||||
: i18n('POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_TEST_BEFORE_DESC');
|
||||
});
|
||||
viewTwoFactorEnableTooltip: () => {
|
||||
translatorTrigger();
|
||||
return this.twoFactorTested() || this.viewEnable_()
|
||||
? ''
|
||||
: i18n('POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_TEST_BEFORE_DESC');
|
||||
},
|
||||
|
||||
this.viewTwoFactorStatus = ko.computed(() => {
|
||||
translatorTrigger();
|
||||
return i18n(
|
||||
this.twoFactorStatus()
|
||||
? 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_CONFIGURED_DESC'
|
||||
: 'POPUPS_TWO_FACTOR_CFG/TWO_FACTOR_SECRET_NOT_CONFIGURED_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'
|
||||
);
|
||||
},
|
||||
|
||||
this.twoFactorAllowedEnable = ko.computed(() => this.viewEnable() || this.twoFactorTested());
|
||||
twoFactorAllowedEnable: () => this.viewEnable() || this.twoFactorTested()
|
||||
});
|
||||
|
||||
this.onResult = this.onResult.bind(this);
|
||||
this.onShowSecretResult = this.onShowSecretResult.bind(this);
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { StorageResultType } from 'Common/Enums';
|
||||
|
||||
import Remote from 'Remote/User/Fetch';
|
||||
|
@ -15,13 +13,15 @@ class TwoFactorTestPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.code = ko.observable('');
|
||||
this.code.focused = ko.observable(false);
|
||||
this.code.status = ko.observable(null);
|
||||
this.addObservables({
|
||||
code: '',
|
||||
codeFocused: false,
|
||||
codeStatus: null,
|
||||
|
||||
testing: false
|
||||
});
|
||||
|
||||
this.koTestedTrigger = null;
|
||||
|
||||
this.testing = ko.observable(false);
|
||||
}
|
||||
|
||||
@command((self) => self.code() && !self.testing())
|
||||
|
@ -29,9 +29,9 @@ class TwoFactorTestPopupView extends AbstractViewNext {
|
|||
this.testing(true);
|
||||
Remote.testTwoFactor((result, data) => {
|
||||
this.testing(false);
|
||||
this.code.status(StorageResultType.Success === result && data && !!data.Result);
|
||||
this.codeStatus(StorageResultType.Success === result && data && !!data.Result);
|
||||
|
||||
if (this.koTestedTrigger && this.code.status()) {
|
||||
if (this.koTestedTrigger && this.codeStatus()) {
|
||||
this.koTestedTrigger(true);
|
||||
}
|
||||
}, this.code());
|
||||
|
@ -39,8 +39,8 @@ class TwoFactorTestPopupView extends AbstractViewNext {
|
|||
|
||||
clearPopup() {
|
||||
this.code('');
|
||||
this.code.focused(false);
|
||||
this.code.status(null);
|
||||
this.codeFocused(false);
|
||||
this.codeStatus(null);
|
||||
this.testing(false);
|
||||
|
||||
this.koTestedTrigger = null;
|
||||
|
@ -54,7 +54,7 @@ class TwoFactorTestPopupView extends AbstractViewNext {
|
|||
|
||||
onShowWithDelay() {
|
||||
// rl.settings.app('mobile') ||
|
||||
this.code.focused(true);
|
||||
this.codeFocused(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import ko from 'ko';
|
||||
|
||||
import { KeyState } from 'Common/Enums';
|
||||
|
||||
import { popup } from 'Knoin/Knoin';
|
||||
|
@ -13,8 +11,10 @@ class ViewOpenPgpKeyPopupView extends AbstractViewNext {
|
|||
constructor() {
|
||||
super();
|
||||
|
||||
this.key = ko.observable('');
|
||||
this.keyDom = ko.observable(null);
|
||||
this.addObservables({
|
||||
key: '',
|
||||
keyDom: null
|
||||
});
|
||||
|
||||
this.sDefaultKeyScope = KeyState.PopupViewOpenPGP;
|
||||
}
|
||||
|
|
|
@ -37,17 +37,31 @@ class LoginUserView extends AbstractViewNext {
|
|||
|
||||
this.hideSubmitButton = Settings.app('hideSubmitButton');
|
||||
|
||||
this.welcome = ko.observable(!!Settings.get('UseLoginWelcomePage'));
|
||||
this.addObservables({
|
||||
welcome: !!Settings.get('UseLoginWelcomePage'),
|
||||
email: '',
|
||||
password: '',
|
||||
signMe: false,
|
||||
additionalCode: '',
|
||||
|
||||
this.email = ko.observable('');
|
||||
this.password = ko.observable('');
|
||||
this.signMe = ko.observable(false);
|
||||
emailError: false,
|
||||
passwordError: false,
|
||||
|
||||
this.additionalCode = ko.observable('');
|
||||
this.additionalCode.error = ko.observable(false);
|
||||
this.additionalCode.errorAnimation = ko.observable(false).extend({ falseTimeout: 500 });
|
||||
this.additionalCode.visibility = ko.observable(false);
|
||||
this.additionalCodeSignMe = ko.observable(false);
|
||||
formHidden: false,
|
||||
|
||||
submitRequest: false,
|
||||
submitError: '',
|
||||
submitErrorAddidional: '',
|
||||
|
||||
langRequest: false,
|
||||
|
||||
additionalCodeError: false,
|
||||
additionalCodeSignMe: false,
|
||||
additionalCodeVisibility: false,
|
||||
signMeType: LoginSignMeType.Unused
|
||||
});
|
||||
|
||||
this.additionalCodeErrorAnimation = ko.observable(false).extend({ falseTimeout: 500 });
|
||||
|
||||
this.logoImg = (Settings.get('LoginLogo')||'').trim();
|
||||
this.loginDescription = (Settings.get('LoginDescription')||'').trim();
|
||||
|
@ -58,61 +72,50 @@ class LoginUserView extends AbstractViewNext {
|
|||
this.forgotPasswordLinkUrl = Settings.app('forgotPasswordLinkUrl');
|
||||
this.registrationLinkUrl = Settings.app('registrationLinkUrl');
|
||||
|
||||
this.emailError = ko.observable(false);
|
||||
this.passwordError = ko.observable(false);
|
||||
|
||||
this.emailErrorAnimation = ko.observable(false).extend({ falseTimeout: 500 });
|
||||
this.passwordErrorAnimation = ko.observable(false).extend({ falseTimeout: 500 });
|
||||
|
||||
this.formHidden = ko.observable(false);
|
||||
this.addComputables({
|
||||
formError:
|
||||
() =>
|
||||
this.emailErrorAnimation() ||
|
||||
this.passwordErrorAnimation() ||
|
||||
(this.additionalCodeVisibility() && this.additionalCodeErrorAnimation()),
|
||||
|
||||
this.formError = ko.computed(
|
||||
() =>
|
||||
this.emailErrorAnimation() ||
|
||||
this.passwordErrorAnimation() ||
|
||||
(this.additionalCode.visibility() && this.additionalCode.errorAnimation())
|
||||
);
|
||||
languageFullName: () => convertLangName(this.language()),
|
||||
|
||||
this.email.subscribe(() => {
|
||||
this.emailError(false);
|
||||
this.additionalCode('');
|
||||
this.additionalCode.visibility(false);
|
||||
signMeVisibility: () => LoginSignMeType.Unused !== this.signMeType()
|
||||
});
|
||||
|
||||
this.password.subscribe(() => this.passwordError(false));
|
||||
this.addSubscribables({
|
||||
email: () => {
|
||||
this.emailError(false);
|
||||
this.additionalCode('');
|
||||
this.additionalCodeVisibility(false);
|
||||
},
|
||||
|
||||
this.additionalCode.subscribe(() => this.additionalCode.error(false));
|
||||
password: () => this.passwordError(false),
|
||||
|
||||
this.additionalCode.visibility.subscribe(() => this.additionalCode.error(false));
|
||||
additionalCode: () => this.additionalCodeError(false),
|
||||
additionalCodeError: bV => this.additionalCodeErrorAnimation(!!bV),
|
||||
additionalCodeVisibility: () => this.additionalCodeError(false),
|
||||
|
||||
this.emailError.subscribe(bV => this.emailErrorAnimation(!!bV));
|
||||
emailError: bV => this.emailErrorAnimation(!!bV),
|
||||
|
||||
this.passwordError.subscribe(bV => this.passwordErrorAnimation(!!bV));
|
||||
passwordError: bV => this.passwordErrorAnimation(!!bV),
|
||||
|
||||
this.additionalCode.error.subscribe(bV => this.additionalCode.errorAnimation(!!bV));
|
||||
submitError: value => value || this.submitErrorAddidional(''),
|
||||
|
||||
this.submitRequest = ko.observable(false);
|
||||
this.submitError = ko.observable('');
|
||||
this.submitErrorAddidional = ko.observable('');
|
||||
|
||||
this.submitError.subscribe(value => value || this.submitErrorAddidional(''));
|
||||
signMeType: iValue => this.signMe(LoginSignMeType.DefaultOn === iValue)
|
||||
});
|
||||
|
||||
this.allowLanguagesOnLogin = !!Settings.get('AllowLanguagesOnLogin');
|
||||
|
||||
this.langRequest = ko.observable(false);
|
||||
this.language = LanguageStore.language;
|
||||
this.languages = LanguageStore.languages;
|
||||
|
||||
this.bSendLanguage = false;
|
||||
|
||||
this.languageFullName = ko.computed(() => convertLangName(this.language()));
|
||||
|
||||
this.signMeType = ko.observable(LoginSignMeType.Unused);
|
||||
|
||||
this.signMeType.subscribe(iValue => this.signMe(LoginSignMeType.DefaultOn === iValue));
|
||||
|
||||
this.signMeVisibility = ko.computed(() => LoginSignMeType.Unused !== this.signMeType());
|
||||
|
||||
if (Settings.get('AdditionalLoginError') && !this.submitError()) {
|
||||
this.submitError(Settings.get('AdditionalLoginError'));
|
||||
}
|
||||
|
@ -128,10 +131,10 @@ class LoginUserView extends AbstractViewNext {
|
|||
this.passwordError(false);
|
||||
|
||||
let error;
|
||||
if (this.additionalCode.visibility()) {
|
||||
this.additionalCode.error(false);
|
||||
if (this.additionalCodeVisibility()) {
|
||||
this.additionalCodeError(false);
|
||||
if (!this.additionalCode().trim()) {
|
||||
this.additionalCode.error(true);
|
||||
this.additionalCodeError(true);
|
||||
error = '.inputAdditionalCode';
|
||||
}
|
||||
}
|
||||
|
@ -157,7 +160,7 @@ class LoginUserView extends AbstractViewNext {
|
|||
if (oData.Result) {
|
||||
if (oData.TwoFactorAuth) {
|
||||
this.additionalCode('');
|
||||
this.additionalCode.visibility(true);
|
||||
this.additionalCodeVisibility(true);
|
||||
this.submitRequest(false);
|
||||
|
||||
setTimeout(() => this.querySelector('.inputAdditionalCode').focus(), 100);
|
||||
|
@ -192,8 +195,8 @@ class LoginUserView extends AbstractViewNext {
|
|||
sLoginPassword,
|
||||
!!this.signMe(),
|
||||
this.bSendLanguage ? this.language() : '',
|
||||
this.additionalCode.visibility() ? this.additionalCode() : '',
|
||||
this.additionalCode.visibility() ? !!this.additionalCodeSignMe() : false
|
||||
this.additionalCodeVisibility() ? this.additionalCode() : '',
|
||||
this.additionalCodeVisibility() ? !!this.additionalCodeSignMe() : false
|
||||
);
|
||||
|
||||
Local.set(ClientSideKeyName.LastSignMe, this.signMe() ? '-1-' : '-0-');
|
||||
|
|
|
@ -108,97 +108,87 @@ class MessageListMailBoxUserView extends AbstractViewNext {
|
|||
this.userUsageSize = QuotaStore.usage;
|
||||
this.userUsageProc = QuotaStore.percentage;
|
||||
|
||||
this.moveDropdownTrigger = ko.observable(false);
|
||||
this.moreDropdownTrigger = ko.observable(false);
|
||||
this.addObservables({
|
||||
moveDropdownTrigger: false,
|
||||
moreDropdownTrigger: false,
|
||||
|
||||
dragOverArea: null,
|
||||
dragOverBodyArea: null,
|
||||
|
||||
inputMessageListSearchFocus: false
|
||||
});
|
||||
|
||||
// append drag and drop
|
||||
this.dragOver = ko.observable(false).extend({ 'throttle': 1 });
|
||||
this.dragOverEnter = ko.observable(false).extend({ 'throttle': 1 });
|
||||
this.dragOverArea = ko.observable(null);
|
||||
this.dragOverBodyArea = ko.observable(null);
|
||||
|
||||
this.messageListItemTemplate = ko.computed(() =>
|
||||
this.mobile || Layout.SidePreview === SettingsStore.layout()
|
||||
? 'MailMessageListItem'
|
||||
: 'MailMessageListItemNoPreviewPane'
|
||||
);
|
||||
|
||||
this.messageListSearchDesc = ko.computed(() => {
|
||||
const value = MessageStore.messageListEndSearch();
|
||||
return value ? i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', { 'SEARCH': value }) : '';
|
||||
});
|
||||
|
||||
this.messageListPaginator = ko.computed(
|
||||
computedPaginatorHelper(MessageStore.messageListPage, MessageStore.messageListPageCount)
|
||||
);
|
||||
|
||||
this.checkAll = ko.computed({
|
||||
read: () => 0 < MessageStore.messageListChecked().length,
|
||||
write: (value) => {
|
||||
value = !!value;
|
||||
MessageStore.messageList().forEach(message => message.checked(value));
|
||||
}
|
||||
});
|
||||
|
||||
this.inputMessageListSearchFocus = ko.observable(false);
|
||||
|
||||
this.sLastSearchValue = '';
|
||||
this.inputProxyMessageListSearch = ko.computed({
|
||||
read: this.mainMessageListSearch,
|
||||
write: value => this.sLastSearchValue = value
|
||||
|
||||
this.addComputables({
|
||||
messageListItemTemplate: () =>
|
||||
this.mobile || Layout.SidePreview === SettingsStore.layout()
|
||||
? 'MailMessageListItem'
|
||||
: 'MailMessageListItemNoPreviewPane',
|
||||
|
||||
messageListSearchDesc: () => {
|
||||
const value = MessageStore.messageListEndSearch();
|
||||
return value ? i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', { 'SEARCH': value }) : ''
|
||||
},
|
||||
|
||||
messageListPaginator: computedPaginatorHelper(MessageStore.messageListPage, MessageStore.messageListPageCount),
|
||||
|
||||
checkAll: {
|
||||
read: () => 0 < MessageStore.messageListChecked().length,
|
||||
write: (value) => {
|
||||
value = !!value;
|
||||
MessageStore.messageList().forEach(message => message.checked(value));
|
||||
}
|
||||
},
|
||||
|
||||
inputProxyMessageListSearch: {
|
||||
read: this.mainMessageListSearch,
|
||||
write: value => this.sLastSearchValue = value
|
||||
},
|
||||
|
||||
isIncompleteChecked: () => {
|
||||
const c = MessageStore.messageListChecked().length;
|
||||
return c && MessageStore.messageList().length > c;
|
||||
},
|
||||
|
||||
hasMessages: () => 0 < this.messageList().length,
|
||||
|
||||
hasCheckedOrSelectedLines: () => 0 < this.messageListCheckedOrSelected().length,
|
||||
|
||||
isSpamFolder: () => FolderStore.spamFolder() === this.messageListEndFolder() && FolderStore.spamFolder(),
|
||||
|
||||
isSpamDisabled: () => UNUSED_OPTION_VALUE === FolderStore.spamFolder(),
|
||||
|
||||
isTrashFolder: () => FolderStore.trashFolder() === this.messageListEndFolder() && FolderStore.trashFolder(),
|
||||
|
||||
isDraftFolder: () => FolderStore.draftFolder() === this.messageListEndFolder() && FolderStore.draftFolder(),
|
||||
|
||||
isSentFolder: () => FolderStore.sentFolder() === this.messageListEndFolder() && FolderStore.sentFolder(),
|
||||
|
||||
isArchiveFolder: () => FolderStore.archiveFolder() === this.messageListEndFolder() && FolderStore.archiveFolder(),
|
||||
|
||||
isArchiveDisabled: () => UNUSED_OPTION_VALUE === FolderStore.archiveFolder(),
|
||||
|
||||
isArchiveVisible: () => !this.isArchiveFolder() && !this.isArchiveDisabled() && !this.isDraftFolder(),
|
||||
|
||||
isSpamVisible: () =>
|
||||
!this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder(),
|
||||
|
||||
isUnSpamVisible: () =>
|
||||
this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder(),
|
||||
|
||||
mobileCheckedStateShow: () => this.mobile ? 0 < MessageStore.messageListChecked().length : true,
|
||||
|
||||
mobileCheckedStateHide: () => this.mobile ? !MessageStore.messageListChecked().length : true,
|
||||
|
||||
messageListFocused: () => Focused.MessageList === AppStore.focusedState()
|
||||
});
|
||||
|
||||
this.isIncompleteChecked = ko.computed(() => {
|
||||
const c = MessageStore.messageListChecked().length;
|
||||
return c && MessageStore.messageList().length > c;
|
||||
});
|
||||
|
||||
this.hasMessages = ko.computed(() => 0 < this.messageList().length);
|
||||
|
||||
this.hasCheckedOrSelectedLines = ko.computed(() => 0 < this.messageListCheckedOrSelected().length);
|
||||
|
||||
this.isSpamFolder = ko.computed(
|
||||
() => FolderStore.spamFolder() === this.messageListEndFolder() && FolderStore.spamFolder()
|
||||
);
|
||||
|
||||
this.isSpamDisabled = ko.computed(() => UNUSED_OPTION_VALUE === FolderStore.spamFolder());
|
||||
|
||||
this.isTrashFolder = ko.computed(
|
||||
() => FolderStore.trashFolder() === this.messageListEndFolder() && FolderStore.trashFolder()
|
||||
);
|
||||
|
||||
this.isDraftFolder = ko.computed(
|
||||
() => FolderStore.draftFolder() === this.messageListEndFolder() && FolderStore.draftFolder()
|
||||
);
|
||||
|
||||
this.isSentFolder = ko.computed(
|
||||
() => FolderStore.sentFolder() === this.messageListEndFolder() && FolderStore.sentFolder()
|
||||
);
|
||||
|
||||
this.isArchiveFolder = ko.computed(
|
||||
() => FolderStore.archiveFolder() === this.messageListEndFolder() && FolderStore.archiveFolder()
|
||||
);
|
||||
|
||||
this.isArchiveDisabled = ko.computed(() => UNUSED_OPTION_VALUE === FolderStore.archiveFolder());
|
||||
|
||||
this.isArchiveVisible = ko.computed(
|
||||
() => !this.isArchiveFolder() && !this.isArchiveDisabled() && !this.isDraftFolder()
|
||||
);
|
||||
|
||||
this.isSpamVisible = ko.computed(
|
||||
() => !this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder()
|
||||
);
|
||||
|
||||
this.isUnSpamVisible = ko.computed(
|
||||
() => this.isSpamFolder() && !this.isSpamDisabled() && !this.isDraftFolder() && !this.isSentFolder()
|
||||
);
|
||||
|
||||
// this.messageListChecked = MessageStore.messageListChecked;
|
||||
this.mobileCheckedStateShow = ko.computed(() => this.mobile ? 0 < MessageStore.messageListChecked().length : true);
|
||||
|
||||
this.mobileCheckedStateHide = ko.computed(() => this.mobile ? !MessageStore.messageListChecked().length : true);
|
||||
|
||||
this.messageListFocused = ko.computed(() => Focused.MessageList === AppStore.focusedState());
|
||||
|
||||
this.canBeMoved = this.hasCheckedOrSelectedLines;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import {
|
|||
import { $htmlCL, leftPanelDisabled, keyScopeReal, moveAction } from 'Common/Globals';
|
||||
|
||||
import { inFocus } from 'Common/Utils';
|
||||
import { mailToHelper, isTransparent } from 'Common/UtilsUser';
|
||||
import { mailToHelper } from 'Common/UtilsUser';
|
||||
|
||||
import Audio from 'Common/Audio';
|
||||
|
||||
|
@ -40,6 +40,10 @@ import { AbstractViewNext } from 'Knoin/AbstractViewNext';
|
|||
|
||||
const Settings = rl.settings;
|
||||
|
||||
function isTransparent(color) {
|
||||
return 'rgba(0, 0, 0, 0)' === color || 'transparent' === color;
|
||||
}
|
||||
|
||||
@view({
|
||||
name: 'View/User/MailBox/MessageView',
|
||||
type: ViewType.Right,
|
||||
|
@ -67,7 +71,14 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
|||
this.oHeaderDom = null;
|
||||
this.oMessageScrollerDom = null;
|
||||
|
||||
this.bodyBackgroundColor = ko.observable('');
|
||||
this.addObservables({
|
||||
bodyBackgroundColor: '',
|
||||
showAttachmnetControls: false,
|
||||
downloadAsZipLoading: false,
|
||||
lastReplyAction_: '',
|
||||
showFullInfo: '1' === Local.get(ClientSideKeyName.MessageHeaderFullInfo),
|
||||
moreDropdownTrigger: false
|
||||
});
|
||||
|
||||
this.pswp = null;
|
||||
|
||||
|
@ -103,50 +114,12 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
|||
this.messageListOfThreadsLoading = ko.observable(false).extend({ rateLimit: 1 });
|
||||
this.highlightUnselectedAttachments = ko.observable(false).extend({ falseTimeout: 2000 });
|
||||
|
||||
this.showAttachmnetControls = ko.observable(false);
|
||||
|
||||
this.showAttachmnetControlsState = v => Local.set(ClientSideKeyName.MessageAttachmentControls, !!v);
|
||||
|
||||
this.allowAttachmnetControls = ko.computed(
|
||||
() => this.attachmentsActions().length && Settings.capa(Capa.AttachmentsActions)
|
||||
);
|
||||
|
||||
this.downloadAsZipAllowed = ko.computed(
|
||||
() => this.attachmentsActions().includes('zip') && this.allowAttachmnetControls()
|
||||
);
|
||||
|
||||
this.downloadAsZipLoading = ko.observable(false);
|
||||
this.downloadAsZipError = ko.observable(false).extend({ falseTimeout: 7000 });
|
||||
|
||||
this.showAttachmnetControls.subscribe(v => this.message()
|
||||
&& this.message().attachments().forEach(item => item && item.checked(!!v))
|
||||
);
|
||||
|
||||
this.lastReplyAction_ = ko.observable('');
|
||||
this.lastReplyAction = ko.computed({
|
||||
read: this.lastReplyAction_,
|
||||
write: value => this.lastReplyAction_(
|
||||
[ComposeType.Reply, ComposeType.ReplyAll, ComposeType.Forward].includes(value)
|
||||
? ComposeType.Reply
|
||||
: value
|
||||
)
|
||||
});
|
||||
|
||||
this.lastReplyAction(Local.get(ClientSideKeyName.LastReplyAction) || ComposeType.Reply);
|
||||
|
||||
this.lastReplyAction_.subscribe(value => Local.set(ClientSideKeyName.LastReplyAction, value));
|
||||
|
||||
this.showFullInfo = ko.observable('1' === Local.get(ClientSideKeyName.MessageHeaderFullInfo));
|
||||
|
||||
this.moreDropdownTrigger = ko.observable(false);
|
||||
this.messageDomFocused = ko.observable(false).extend({ rateLimit: 0 });
|
||||
|
||||
this.messageVisibility = ko.computed(() => !this.messageLoadingThrottle() && !!this.message());
|
||||
|
||||
this.message.subscribe(message => (!message) && MessageStore.selectorMessageSelected(null));
|
||||
|
||||
this.canBeRepliedOrForwarded = ko.computed(() => !this.isDraftFolder() && this.messageVisibility());
|
||||
|
||||
// commands
|
||||
this.replyCommand = createCommandReplyHelper(ComposeType.Reply);
|
||||
this.replyAllCommand = createCommandReplyHelper(ComposeType.ReplyAll);
|
||||
|
@ -162,97 +135,85 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
|||
|
||||
// viewer
|
||||
|
||||
this.viewBodyTopValue = ko.observable(0);
|
||||
|
||||
this.viewFolder = '';
|
||||
this.viewUid = '';
|
||||
this.viewHash = '';
|
||||
this.viewSubject = ko.observable('');
|
||||
this.viewFromShort = ko.observable('');
|
||||
this.viewFromDkimData = ko.observable(['none', '']);
|
||||
this.viewToShort = ko.observable('');
|
||||
this.viewFrom = ko.observable('');
|
||||
this.viewTo = ko.observable('');
|
||||
this.viewCc = ko.observable('');
|
||||
this.viewBcc = ko.observable('');
|
||||
this.viewReplyTo = ko.observable('');
|
||||
this.viewTimeStamp = ko.observable(0);
|
||||
this.viewSize = ko.observable('');
|
||||
this.viewLineAsCss = ko.observable('');
|
||||
this.viewViewLink = ko.observable('');
|
||||
this.viewUnsubscribeLink = ko.observable('');
|
||||
this.viewDownloadLink = ko.observable('');
|
||||
this.viewIsImportant = ko.observable(false);
|
||||
this.viewIsFlagged = ko.observable(false);
|
||||
|
||||
this.viewFromDkimVisibility = ko.computed(() => 'none' !== this.viewFromDkimData()[0]);
|
||||
|
||||
this.viewFromDkimStatusIconClass = ko.computed(() => {
|
||||
switch (this.viewFromDkimData()[0]) {
|
||||
case 'none':
|
||||
return 'icon-none iconcolor-display-none';
|
||||
case 'pass':
|
||||
return 'icon-ok iconcolor-green';
|
||||
default:
|
||||
return 'icon-warning-alt iconcolor-red';
|
||||
}
|
||||
this.addObservables({
|
||||
viewBodyTopValue: 0,
|
||||
viewSubject: '',
|
||||
viewFromShort: '',
|
||||
viewFromDkimData: ['none', ''],
|
||||
viewToShort: '',
|
||||
viewFrom: '',
|
||||
viewTo: '',
|
||||
viewCc: '',
|
||||
viewBcc: '',
|
||||
viewReplyTo: '',
|
||||
viewTimeStamp: 0,
|
||||
viewSize: '',
|
||||
viewLineAsCss: '',
|
||||
viewViewLink: '',
|
||||
viewUnsubscribeLink: '',
|
||||
viewDownloadLink: '',
|
||||
viewIsImportant: false,
|
||||
viewIsFlagged: false
|
||||
});
|
||||
|
||||
this.viewFromDkimStatusTitle = ko.computed(() => {
|
||||
const status = this.viewFromDkimData();
|
||||
if (Array.isNotEmpty(status)) {
|
||||
if (status[0]) {
|
||||
return status[1] || 'DKIM: ' + status[0];
|
||||
}
|
||||
}
|
||||
this.addSubscribables({
|
||||
showAttachmnetControls: v => this.message()
|
||||
&& this.message().attachments().forEach(item => item && item.checked(!!v)),
|
||||
|
||||
return '';
|
||||
});
|
||||
lastReplyAction_: value => Local.set(ClientSideKeyName.LastReplyAction, value),
|
||||
|
||||
this.messageActiveDom.subscribe(dom => this.bodyBackgroundColor(this.detectDomBackgroundColor(dom)), this);
|
||||
messageActiveDom: dom => this.bodyBackgroundColor(this.detectDomBackgroundColor(dom)),
|
||||
|
||||
this.message.subscribe((message) => {
|
||||
this.messageActiveDom(null);
|
||||
message: message => {
|
||||
this.messageActiveDom(null);
|
||||
|
||||
if (message) {
|
||||
this.showAttachmnetControls(false);
|
||||
if (Local.get(ClientSideKeyName.MessageAttachmentControls)) {
|
||||
setTimeout(() => {
|
||||
this.showAttachmnetControls(true);
|
||||
}, 50);
|
||||
}
|
||||
if (message) {
|
||||
this.showAttachmnetControls(false);
|
||||
if (Local.get(ClientSideKeyName.MessageAttachmentControls)) {
|
||||
setTimeout(() => {
|
||||
this.showAttachmnetControls(true);
|
||||
}, 50);
|
||||
}
|
||||
|
||||
if (this.viewHash !== message.hash) {
|
||||
this.scrollMessageToTop();
|
||||
}
|
||||
|
||||
this.viewFolder = message.folder;
|
||||
this.viewUid = message.uid;
|
||||
this.viewHash = message.hash;
|
||||
this.viewSubject(message.subject());
|
||||
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.viewTimeStamp(message.dateTimeStampInUTC());
|
||||
this.viewSize(message.friendlySize());
|
||||
this.viewLineAsCss(message.lineAsCss());
|
||||
this.viewViewLink(message.viewLink());
|
||||
this.viewUnsubscribeLink(message.getFirstUnsubsribeLink());
|
||||
this.viewDownloadLink(message.downloadLink());
|
||||
this.viewIsImportant(message.isImportant());
|
||||
this.viewIsFlagged(message.isFlagged());
|
||||
} else {
|
||||
MessageStore.selectorMessageSelected(null);
|
||||
|
||||
this.viewFolder = '';
|
||||
this.viewUid = '';
|
||||
this.viewHash = '';
|
||||
|
||||
if (this.viewHash !== message.hash) {
|
||||
this.scrollMessageToTop();
|
||||
}
|
||||
},
|
||||
|
||||
this.viewFolder = message.folder;
|
||||
this.viewUid = message.uid;
|
||||
this.viewHash = message.hash;
|
||||
this.viewSubject(message.subject());
|
||||
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.viewTimeStamp(message.dateTimeStampInUTC());
|
||||
this.viewSize(message.friendlySize());
|
||||
this.viewLineAsCss(message.lineAsCss());
|
||||
this.viewViewLink(message.viewLink());
|
||||
this.viewUnsubscribeLink(message.getFirstUnsubsribeLink());
|
||||
this.viewDownloadLink(message.downloadLink());
|
||||
this.viewIsImportant(message.isImportant());
|
||||
this.viewIsFlagged(message.isFlagged());
|
||||
} else {
|
||||
this.viewFolder = '';
|
||||
this.viewUid = '';
|
||||
this.viewHash = '';
|
||||
|
||||
this.scrollMessageToTop();
|
||||
}
|
||||
fullScreenMode: value => $htmlCL.toggle('rl-message-fullscreen', value)
|
||||
});
|
||||
|
||||
this.message.viewTrigger.subscribe(() => {
|
||||
|
@ -260,13 +221,55 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
|
|||
message ? this.viewIsFlagged(message.isFlagged()) : this.viewIsFlagged(false);
|
||||
});
|
||||
|
||||
this.fullScreenMode.subscribe(value => $htmlCL.toggle('rl-message-fullscreen', value));
|
||||
this.addComputables({
|
||||
allowAttachmnetControls: () => this.attachmentsActions().length && Settings.capa(Capa.AttachmentsActions),
|
||||
|
||||
this.messageFocused = ko.computed(() => Focused.MessageView === AppStore.focusedState());
|
||||
downloadAsZipAllowed: () => this.attachmentsActions().includes('zip') && this.allowAttachmnetControls(),
|
||||
|
||||
this.messageListAndMessageViewLoading = ko.computed(
|
||||
() => MessageStore.messageListCompleteLoadingThrottle() || MessageStore.messageLoadingThrottle()
|
||||
);
|
||||
lastReplyAction: {
|
||||
read: this.lastReplyAction_,
|
||||
write: value => this.lastReplyAction_(
|
||||
[ComposeType.Reply, ComposeType.ReplyAll, ComposeType.Forward].includes(value)
|
||||
? ComposeType.Reply
|
||||
: value
|
||||
)
|
||||
},
|
||||
|
||||
messageVisibility: () => !this.messageLoadingThrottle() && !!this.message(),
|
||||
|
||||
canBeRepliedOrForwarded: () => !this.isDraftFolder() && this.messageVisibility(),
|
||||
|
||||
viewFromDkimVisibility: () => 'none' !== this.viewFromDkimData()[0],
|
||||
|
||||
viewFromDkimStatusIconClass:() => {
|
||||
switch (this.viewFromDkimData()[0]) {
|
||||
case 'none':
|
||||
return 'icon-none iconcolor-display-none';
|
||||
case 'pass':
|
||||
return 'icon-ok iconcolor-green';
|
||||
default:
|
||||
return 'icon-warning-alt iconcolor-red';
|
||||
}
|
||||
},
|
||||
|
||||
viewFromDkimStatusTitle:() => {
|
||||
const status = this.viewFromDkimData();
|
||||
if (Array.isNotEmpty(status)) {
|
||||
if (status[0]) {
|
||||
return status[1] || 'DKIM: ' + status[0];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
},
|
||||
|
||||
messageFocused: () => Focused.MessageView === AppStore.focusedState(),
|
||||
|
||||
messageListAndMessageViewLoading:
|
||||
() => MessageStore.messageListCompleteLoadingThrottle() || MessageStore.messageLoadingThrottle()
|
||||
});
|
||||
|
||||
this.lastReplyAction(Local.get(ClientSideKeyName.LastReplyAction) || ComposeType.Reply);
|
||||
|
||||
addEventListener('mailbox.message-view.toggle-full-screen', () => this.toggleFullScreen());
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ class Folder implements \JsonSerializable
|
|||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $bExisten;
|
||||
private $bExists;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
|
@ -50,7 +50,7 @@ class Folder implements \JsonSerializable
|
|||
/**
|
||||
* @throws \MailSo\Base\Exceptions\InvalidArgumentException
|
||||
*/
|
||||
function __construct(\MailSo\Imap\Folder $oImapFolder, bool $bSubscribed = true, bool $bExisten = true)
|
||||
function __construct(\MailSo\Imap\Folder $oImapFolder, bool $bSubscribed = true, bool $bExists = true)
|
||||
{
|
||||
$this->oImapFolder = $oImapFolder;
|
||||
$this->oSubFolders = null;
|
||||
|
@ -66,7 +66,7 @@ class Folder implements \JsonSerializable
|
|||
}
|
||||
|
||||
$this->bSubscribed = $bSubscribed;
|
||||
$this->bExisten = $bExisten;
|
||||
$this->bExists = $bExists;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -164,12 +164,12 @@ class Folder implements \JsonSerializable
|
|||
|
||||
public function IsExists() : bool
|
||||
{
|
||||
return $this->bExisten;
|
||||
return $this->bExists;
|
||||
}
|
||||
|
||||
public function IsSelectable() : bool
|
||||
{
|
||||
return $this->IsExists() && $this->oImapFolder->IsSelectable();
|
||||
return $this->bExists && $this->oImapFolder->IsSelectable();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -236,9 +236,9 @@ class Folder implements \JsonSerializable
|
|||
'FullNameRaw' => $this->FullNameRaw(),
|
||||
'Delimiter' => (string) $this->Delimiter(),
|
||||
'HasVisibleSubFolders' => $this->HasVisibleSubFolders(),
|
||||
'IsSubscribed' => $this->IsSubscribed(),
|
||||
'IsExists' => $this->IsExists(),
|
||||
'IsSelectable' => $this->IsSelectable(),
|
||||
'Subscribed' => $this->bSubscribed,
|
||||
'Exists' => $this->bExists,
|
||||
'Selectable' => $this->IsSelectable(),
|
||||
'Flags' => $this->FlagsLowerCase()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="controls"
|
||||
data-bind="visible: additionalCode.visibility(), css: {'error': additionalCode.error, 'animated': additionalCode.errorAnimation}">
|
||||
data-bind="visible: additionalCodeVisibility(), css: {'error': additionalCodeError, 'animated': additionalCodeErrorAnimation}">
|
||||
<div class="input-append">
|
||||
<input type="text" class="i18n input-block-level inputAdditionalCode" autocomplete="off"
|
||||
autocorrect="off" autocapitalize="off" spellcheck="false" style="padding-right: 35px;"
|
||||
|
@ -71,7 +71,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="controls plugin-mark-Login-BottomControlGroup"
|
||||
data-bind="visible: additionalCode.visibility()">
|
||||
data-bind="visible: additionalCodeVisibility()">
|
||||
<div class="additionalCodeSignMeLabel" data-bind="component: {
|
||||
name: 'CheckboxSimple',
|
||||
params: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<div class="e-item" data-bind="visible: visible, css: { 'i-am-inbox-wrapper': isInbox }">
|
||||
<a class="e-link" data-bind="dropmessages: $data,
|
||||
css: { 'i-am-inbox': isInbox, 'selected': selected() && !isSystemFolder(), 'selectable': selectableForFolderList, 'hidden' : hidden, 'print-count': hasUnreadMessages, 'unread-sub': hasSubScribedUnreadMessagesSubfolders, 'system': isSystemFolder, 'anim-action-class': actionBlink }">
|
||||
css: { 'i-am-inbox': isInbox, 'selected': selected() && !isSystemFolder(), 'selectable': selectableForFolderList, 'hidden' : hidden, 'print-count': hasUnreadMessages, 'unread-sub': hasSubscribedUnreadMessagesSubfolders, 'system': isSystemFolder, 'anim-action-class': actionBlink }">
|
||||
<span class="badge pull-right count" data-bind="text: printableUnreadCount"></span>
|
||||
<i data-bind="css: collapsedCss()"></i>
|
||||
<span class="focused-poiner"></span>
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
</h3>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert" data-bind="visible: key.error() && key.errorMessage(), text: key.errorMessage"></div>
|
||||
<div class="alert" data-bind="visible: keyError() && keyErrorMessage(), text: keyErrorMessage"></div>
|
||||
<div class="form-horizontal">
|
||||
<div class="control-group" data-bind="css: {'error': key.error}">
|
||||
<div class="control-group" data-bind="css: {'error': keyError}">
|
||||
<textarea class="inputKey input-xxlarge" rows="14" autofocus="" autocomplete="off" data-bind="value: key"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -111,7 +111,7 @@
|
|||
</label>
|
||||
</div>
|
||||
<div class="e-cell e-value">
|
||||
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" data-bind="emailsTags: to, emailsTagsFocus: to.focused, autoCompleteSource: emailsSource" />
|
||||
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" data-bind="emailsTags: to, emailsTagsFocus: toFocused, autoCompleteSource: emailsSource" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="e-row cc-row" data-bind="visible: showCc">
|
||||
|
@ -143,7 +143,7 @@
|
|||
<span class="i18n" data-i18n="COMPOSE/TITLE_SUBJECT"></span>
|
||||
</div>
|
||||
<div class="e-cell e-value">
|
||||
<input type="text" size="70" autocomplete="off" data-bind="textInput: subject, hasFocus: subject.focused" />
|
||||
<input type="text" size="70" autocomplete="off" data-bind="textInput: subject, hasFocus: subjectFocused" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="e-row">
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="uiInput inputName" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="textInput: folderName, hasfocus: folderName.focused, onEnter: createFolderCommand" />
|
||||
data-bind="textInput: folderName, hasfocus: folderNameFocused, onEnter: createFolderCommand" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<div class="controls">
|
||||
<input type="email" class="inputEmail input-xlarge" autofocus=""
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="value: email, onEnter: addOrEditIdentityCommand, hasfocus: email.focused" />
|
||||
data-bind="value: email, onEnter: addOrEditIdentityCommand, hasfocus: emailFocused" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group" data-bind="visible: owner">
|
||||
|
@ -41,7 +41,7 @@
|
|||
<div class="controls">
|
||||
<input type="text" class="inputReplyTo input-xlarge"
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="value: replyTo, onEnter: addOrEditIdentityCommand, hasfocus: replyTo.focused" />
|
||||
data-bind="value: replyTo, onEnter: addOrEditIdentityCommand, hasfocus: replyToFocused" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group" data-bind="visible: showBcc, css: {'error': bcc.hasError}">
|
||||
|
@ -49,7 +49,7 @@
|
|||
<div class="controls">
|
||||
<input type="text" class="inputBcc input-xlarge"
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="value: bcc, onEnter: addOrEditIdentityCommand, hasfocus: bcc.focused" />
|
||||
data-bind="value: bcc, onEnter: addOrEditIdentityCommand, hasfocus: bccFocused" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group" data-bind="visible: !showReplyTo() || !showBcc()">
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
<span data-bind="text: submitError"></span>
|
||||
</div>
|
||||
<br />
|
||||
<div class="control-group" data-bind="css: {'error': email.error}">
|
||||
<div class="control-group" data-bind="css: {'error': emailError}">
|
||||
<label class="i18n control-label" data-i18n="POPUPS_GENERATE_OPEN_PGP_KEYS/LABEL_EMAIL"></label>
|
||||
<div class="controls">
|
||||
<input type="email" class="inputEmail input-large"
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="value: email, hasfocus: email.focus" />
|
||||
data-bind="value: email, hasfocus: emailFocus" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
|
|
|
@ -14,17 +14,17 @@
|
|||
<span data-bind="text: submitError"></span>
|
||||
</div>
|
||||
<br />
|
||||
<div class="control-group" data-bind="css: {'error': name.error}">
|
||||
<div class="control-group" data-bind="css: {'error': nameError}">
|
||||
<label class="i18n control-label" data-i18n="POPUPS_ADD_TEMPLATE/LABEL_NAME"></label>
|
||||
<div class="controls">
|
||||
<input type="text" class="inputName input-xlarge" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="textInput: name, onEnter: addTemplateCommand, hasfocus: name.focus" />
|
||||
data-bind="textInput: name, onEnter: addTemplateCommand, hasfocus: nameFocus" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="form-horizontal">
|
||||
<div class="control-group" data-bind="css: {'error': body.error}">
|
||||
<div class="control-group" data-bind="css: {'error': bodyError}">
|
||||
<div class="e-template-place" data-bind="initDom: signatureDom"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,14 +16,14 @@
|
|||
<div class="controls">
|
||||
<input type="text" class="uiInput inputName"
|
||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||
data-bind="textInput: code, hasfocus: code.focused, onEnter: testCodeCommand" />
|
||||
data-bind="textInput: code, hasfocus: codeFocused, onEnter: testCodeCommand" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn" data-bind="command: testCodeCommand, css: { 'btn-success': true === code.status(), 'btn-danger': false === code.status() }">
|
||||
<i data-bind="css: {'icon-ok': !testing(), 'icon-spinner animated': testing(), 'icon-white': true === code.status() || false === code.status() }"></i>
|
||||
<a class="btn" data-bind="command: testCodeCommand, css: { 'btn-success': true === codeStatus(), 'btn-danger': false === codeStatus() }">
|
||||
<i data-bind="css: {'icon-ok': !testing(), 'icon-spinner animated': testing(), 'icon-white': true === codeStatus() || false === codeStatus() }"></i>
|
||||
|
||||
<span class="i18n" data-i18n="POPUPS_TWO_FACTOR_TEST/BUTTON_TEST"></span>
|
||||
</a>
|
||||
|
|
|
@ -18,20 +18,20 @@
|
|||
</span>
|
||||
</td>
|
||||
<td class="subscribe-folder-parent">
|
||||
<span class="unsubscribe-folder" data-bind="visible: canBeSubScribed() && !subScribed(), click: function(oFolder) { $root.subscribeFolder(oFolder); }">
|
||||
<span class="unsubscribe-folder" data-bind="visible: canBeSubscribed() && !subscribed(), click: function(oFolder) { $root.subscribeFolder(oFolder); }">
|
||||
<i class="icon-eye"></i>
|
||||
</span>
|
||||
<span class="subscribe-folder" data-bind="visible: canBeSubScribed() && subScribed(), click: function(oFolder) { $root.unSubscribeFolder(oFolder); }">
|
||||
<span class="subscribe-folder" data-bind="visible: canBeSubscribed() && subscribed(), click: function(oFolder) { $root.unSubscribeFolder(oFolder); }">
|
||||
<i class="icon-eye"></i>
|
||||
</span>
|
||||
</td>
|
||||
<td class="check-folder-parent" data-bind="visible: $root.displaySpecSetting">
|
||||
<span class="uncheck-folder" data-bind="visible: canBeChecked() && subScribed() && !checkable(), click: function(oFolder) { $root.checkableTrueFolder(oFolder); }">
|
||||
<span class="uncheck-folder" data-bind="visible: canBeChecked() && subscribed() && !checkable(), click: function(oFolder) { $root.checkableTrueFolder(oFolder); }">
|
||||
<i class="icon-check-mark-circle-two"></i>
|
||||
</span>
|
||||
<span class="check-folder" data-bind="visible: canBeChecked() && subScribed() && checkable(), click: function(oFolder) { $root.checkableFalseFolder(oFolder); }">
|
||||
<span class="check-folder" data-bind="visible: canBeChecked() && subscribed() && checkable(), click: function(oFolder) { $root.checkableFalseFolder(oFolder); }">
|
||||
<i class="icon-check-mark-circle-two"></i>
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- ko template: { name: 'SettingsFolderItem', foreach: subFolders } --><!-- /ko -->
|
||||
<!-- ko template: { name: 'SettingsFolderItem', foreach: subFolders } --><!-- /ko -->
|
||||
|
|
Loading…
Reference in a new issue