mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Prevent memory leaks in *Model
This commit is contained in:
parent
48a9a03762
commit
d7a4639d6b
22 changed files with 221 additions and 225 deletions
|
|
@ -5,50 +5,52 @@ function disposeOne(disposable) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function typeCast(current, value) {
|
function typeCast(curValue, newValue) {
|
||||||
switch (typeof current)
|
switch (typeof curValue)
|
||||||
{
|
{
|
||||||
case 'boolean': return !!value;
|
case 'boolean': return !!newValue;
|
||||||
case 'number': return isFinite(value) ? parseFloat(value) : 0;
|
case 'number': return isFinite(newValue) ? parseFloat(newValue) : 0;
|
||||||
case 'string': return null != value ? '' + value : '';
|
case 'string': return null != newValue ? '' + newValue : '';
|
||||||
case 'object':
|
case 'object':
|
||||||
if (current.constructor.reviveFromJson) {
|
if (curValue.constructor.reviveFromJson) {
|
||||||
return current.constructor.reviveFromJson(value) || undefined;
|
return curValue.constructor.reviveFromJson(newValue) || undefined;
|
||||||
}
|
}
|
||||||
if (!Array.isArray(current) || !Array.isArray(value))
|
if (!Array.isArray(curValue) || !Array.isArray(newValue))
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
return value;
|
return newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AbstractModel {
|
export class AbstractModel {
|
||||||
disposables = [];
|
disposables = [];
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} modelName = ''
|
|
||||||
*/
|
|
||||||
constructor() {
|
constructor() {
|
||||||
/*
|
/*
|
||||||
if (new.target === AbstractModel) {
|
if (new.target === AbstractModel) {
|
||||||
throw new Error("Can't instantiate AbstractModel!");
|
throw new Error("Can't instantiate AbstractModel!");
|
||||||
}
|
}
|
||||||
this.sModelName = new.target.name;
|
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
regDisposables(value) {
|
addObservables(obj) {
|
||||||
if (Array.isArray(value)) {
|
Object.entries(obj).forEach(([key, value]) => this[key] = ko.observable(value) );
|
||||||
value.forEach(item => this.disposables.push(item));
|
/*
|
||||||
} else if (value) {
|
Object.entries(obj).forEach(([key, value]) =>
|
||||||
this.disposables.push(value);
|
this[key] = Array.isArray(value) ? ko.observableArray(value) : ko.observable(value)
|
||||||
}
|
);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
addSubscribables(obj) {
|
||||||
|
Object.entries(obj).forEach(([key, fn]) => this.disposables.push( this[key].subscribe(fn) ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy() {
|
onDestroy() {
|
||||||
if (Array.isArray(this.disposables)) {
|
this.disposables.forEach(disposeOne);
|
||||||
this.disposables.forEach(disposeOne);
|
Object.entries(this).forEach(([key, value]) => {
|
||||||
}
|
disposeOne(value);
|
||||||
Object.values(this).forEach(disposeOne);
|
this[key] = null;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import ko from 'ko';
|
|
||||||
|
|
||||||
import { change } from 'Common/Links';
|
import { change } from 'Common/Links';
|
||||||
|
|
||||||
import { AbstractModel } from 'Knoin/AbstractModel';
|
import { AbstractModel } from 'Knoin/AbstractModel';
|
||||||
|
|
@ -15,10 +13,11 @@ class AccountModel extends AbstractModel {
|
||||||
|
|
||||||
this.email = email;
|
this.email = email;
|
||||||
|
|
||||||
this.count = ko.observable(count);
|
this.addObservables({
|
||||||
|
count: count,
|
||||||
this.deleteAccess = ko.observable(false);
|
deleteAccess: false,
|
||||||
this.canBeDeleted = ko.observable(!!canBeDelete);
|
canBeDeleted: !!canBeDelete
|
||||||
|
});
|
||||||
this.canBeEdit = this.canBeDeleted;
|
this.canBeEdit = this.canBeDeleted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,16 +24,18 @@ class ComposeAttachmentModel extends AbstractModel {
|
||||||
this.contentLocation = contentLocation;
|
this.contentLocation = contentLocation;
|
||||||
this.fromMessage = false;
|
this.fromMessage = false;
|
||||||
|
|
||||||
this.fileName = ko.observable(fileName);
|
this.addObservables({
|
||||||
this.size = ko.observable(size);
|
fileName: fileName,
|
||||||
this.tempName = ko.observable('');
|
size: size,
|
||||||
|
tempName: '',
|
||||||
|
|
||||||
this.progress = ko.observable(0);
|
progress: 0,
|
||||||
this.error = ko.observable('');
|
error: '',
|
||||||
this.waiting = ko.observable(true);
|
waiting: true,
|
||||||
this.uploading = ko.observable(false);
|
uploading: false,
|
||||||
this.enabled = ko.observable(true);
|
enabled: true,
|
||||||
this.complete = ko.observable(false);
|
complete: false
|
||||||
|
});
|
||||||
|
|
||||||
this.progressText = ko.computed(() => {
|
this.progressText = ko.computed(() => {
|
||||||
const p = this.progress();
|
const p = this.progress();
|
||||||
|
|
@ -56,15 +58,6 @@ class ComposeAttachmentModel extends AbstractModel {
|
||||||
|
|
||||||
this.mimeType = ko.computed(() => File.getContentType(this.fileName()));
|
this.mimeType = ko.computed(() => File.getContentType(this.fileName()));
|
||||||
this.fileExt = ko.computed(() => File.getExtension(this.fileName()));
|
this.fileExt = ko.computed(() => File.getExtension(this.fileName()));
|
||||||
|
|
||||||
this.regDisposables([
|
|
||||||
this.progressText,
|
|
||||||
this.progressStyle,
|
|
||||||
this.title,
|
|
||||||
this.friendlySize,
|
|
||||||
this.mimeType,
|
|
||||||
this.fileExt
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromAttachment(item)
|
static fromAttachment(item)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import ko from 'ko';
|
|
||||||
|
|
||||||
import { ContactPropertyModel } from 'Model/ContactProperty';
|
import { ContactPropertyModel } from 'Model/ContactProperty';
|
||||||
import { ContactPropertyType } from 'Common/Enums';
|
import { ContactPropertyType } from 'Common/Enums';
|
||||||
|
|
||||||
|
|
@ -14,10 +12,12 @@ class ContactModel extends AbstractModel {
|
||||||
this.properties = [];
|
this.properties = [];
|
||||||
this.readOnly = false;
|
this.readOnly = false;
|
||||||
|
|
||||||
this.focused = ko.observable(false);
|
this.addObservables({
|
||||||
this.selected = ko.observable(false);
|
focused: false,
|
||||||
this.checked = ko.observable(false);
|
selected: false,
|
||||||
this.deleted = ko.observable(false);
|
checked: false,
|
||||||
|
deleted: false
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,14 @@ class ContactPropertyModel extends AbstractModel {
|
||||||
constructor(type = ContactPropertyType.Unknown, typeStr = '', value = '', focused = false, placeholder = '') {
|
constructor(type = ContactPropertyType.Unknown, typeStr = '', value = '', focused = false, placeholder = '') {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.type = ko.observable(pInt(type));
|
this.addObservables({
|
||||||
this.typeStr = ko.observable(pString(typeStr));
|
type: pInt(type),
|
||||||
this.focused = ko.observable(!!focused);
|
typeStr: pString(typeStr),
|
||||||
this.value = ko.observable(pString(value));
|
focused: !!focused,
|
||||||
|
value: pString(value),
|
||||||
|
|
||||||
this.placeholder = ko.observable(placeholder);
|
placeholder: placeholder
|
||||||
|
});
|
||||||
|
|
||||||
this.placeholderValue = ko.computed(() => {
|
this.placeholderValue = ko.computed(() => {
|
||||||
const v = this.placeholder();
|
const v = this.placeholder();
|
||||||
|
|
@ -30,8 +32,6 @@ class ContactPropertyModel extends AbstractModel {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.largeValue = ko.computed(() => ContactPropertyType.Note === this.type());
|
this.largeValue = ko.computed(() => ContactPropertyType.Note === this.type());
|
||||||
|
|
||||||
this.regDisposables([this.placeholderValue, this.largeValue]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
|
|
|
||||||
|
|
@ -15,42 +15,38 @@ class FilterModel extends AbstractModel {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.enabled = ko.observable(true);
|
|
||||||
|
|
||||||
this.id = '';
|
this.id = '';
|
||||||
|
|
||||||
this.name = ko.observable('');
|
this.addObservables({
|
||||||
this.name.error = ko.observable(false);
|
enabled: true,
|
||||||
this.name.focused = ko.observable(false);
|
deleteAccess: false,
|
||||||
|
canBeDeleted: true,
|
||||||
|
|
||||||
|
name: '',
|
||||||
|
nameError: false,
|
||||||
|
nameFocused: false,
|
||||||
|
|
||||||
|
conditionsType: FilterRulesType.Any,
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
actionValue: '',
|
||||||
|
actionValueError: false,
|
||||||
|
|
||||||
|
actionValueSecond: '',
|
||||||
|
actionValueThird: '',
|
||||||
|
|
||||||
|
actionValueFourth: '',
|
||||||
|
actionValueFourthError: false,
|
||||||
|
|
||||||
|
actionMarkAsRead: false,
|
||||||
|
|
||||||
|
actionKeep: true,
|
||||||
|
actionNoStop: false,
|
||||||
|
|
||||||
|
actionType: FiltersAction.MoveTo
|
||||||
|
});
|
||||||
|
|
||||||
this.conditions = ko.observableArray([]);
|
this.conditions = ko.observableArray([]);
|
||||||
this.conditionsType = ko.observable(FilterRulesType.Any);
|
|
||||||
|
|
||||||
// Actions
|
|
||||||
this.actionValue = ko.observable('');
|
|
||||||
this.actionValue.error = ko.observable(false);
|
|
||||||
|
|
||||||
this.actionValueSecond = ko.observable('');
|
|
||||||
this.actionValueThird = ko.observable('');
|
|
||||||
|
|
||||||
this.actionValueFourth = ko.observable('');
|
|
||||||
this.actionValueFourth.error = ko.observable(false);
|
|
||||||
|
|
||||||
this.actionMarkAsRead = ko.observable(false);
|
|
||||||
|
|
||||||
this.actionKeep = ko.observable(true);
|
|
||||||
this.actionNoStop = ko.observable(false);
|
|
||||||
|
|
||||||
this.actionType = ko.observable(FiltersAction.MoveTo);
|
|
||||||
|
|
||||||
this.actionType.subscribe(() => {
|
|
||||||
this.actionValue('');
|
|
||||||
this.actionValue.error(false);
|
|
||||||
this.actionValueSecond('');
|
|
||||||
this.actionValueThird('');
|
|
||||||
this.actionValueFourth('');
|
|
||||||
this.actionValueFourth.error(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
const fGetRealFolderName = (folderFullNameRaw) => {
|
const fGetRealFolderName = (folderFullNameRaw) => {
|
||||||
const folder = getFolderFromCacheList(folderFullNameRaw);
|
const folder = getFolderFromCacheList(folderFullNameRaw);
|
||||||
|
|
@ -115,14 +111,18 @@ class FilterModel extends AbstractModel {
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
this.regDisposables(this.name.subscribe(sValue => this.name.error(!sValue)));
|
this.addSubscribables({
|
||||||
|
name: sValue => this.nameError(!sValue),
|
||||||
this.regDisposables(this.actionValue.subscribe(sValue => this.actionValue.error(!sValue)));
|
actionValue: sValue => this.actionValueError(!sValue),
|
||||||
|
actionType: () => {
|
||||||
this.regDisposables([this.actionNoStop, this.actionTemplate]);
|
this.actionValue('');
|
||||||
|
this.actionValueError(false);
|
||||||
this.deleteAccess = ko.observable(false);
|
this.actionValueSecond('');
|
||||||
this.canBeDeleted = ko.observable(true);
|
this.actionValueThird('');
|
||||||
|
this.actionValueFourth('');
|
||||||
|
this.actionValueFourthError(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
generateID() {
|
generateID() {
|
||||||
|
|
@ -131,14 +131,12 @@ class FilterModel extends AbstractModel {
|
||||||
|
|
||||||
verify() {
|
verify() {
|
||||||
if (!this.name()) {
|
if (!this.name()) {
|
||||||
this.name.error(true);
|
this.nameError(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.conditions().length) {
|
if (this.conditions().length && this.conditions().find(cond => cond && !cond.verify())) {
|
||||||
if (this.conditions().find(cond => cond && !cond.verify())) {
|
return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.actionValue()) {
|
if (!this.actionValue()) {
|
||||||
|
|
@ -149,13 +147,13 @@ class FilterModel extends AbstractModel {
|
||||||
FiltersAction.Vacation
|
FiltersAction.Vacation
|
||||||
].includes(this.actionType())
|
].includes(this.actionType())
|
||||||
) {
|
) {
|
||||||
this.actionValue.error(true);
|
this.actionValueError(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FiltersAction.Forward === this.actionType() && !this.actionValue().includes('@')) {
|
if (FiltersAction.Forward === this.actionType() && !this.actionValue().includes('@')) {
|
||||||
this.actionValue.error(true);
|
this.actionValueError(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,12 +162,12 @@ class FilterModel extends AbstractModel {
|
||||||
this.actionValueFourth() &&
|
this.actionValueFourth() &&
|
||||||
!this.actionValueFourth().includes('@')
|
!this.actionValueFourth().includes('@')
|
||||||
) {
|
) {
|
||||||
this.actionValueFourth.error(true);
|
this.actionValueFourthError(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.name.error(false);
|
this.nameError(false);
|
||||||
this.actionValue.error(false);
|
this.actionValueError(false);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -240,7 +238,7 @@ class FilterModel extends AbstractModel {
|
||||||
filter.enabled(this.enabled());
|
filter.enabled(this.enabled());
|
||||||
|
|
||||||
filter.name(this.name());
|
filter.name(this.name());
|
||||||
filter.name.error(this.name.error());
|
filter.nameError(this.nameError());
|
||||||
|
|
||||||
filter.conditionsType(this.conditionsType());
|
filter.conditionsType(this.conditionsType());
|
||||||
|
|
||||||
|
|
@ -249,7 +247,7 @@ class FilterModel extends AbstractModel {
|
||||||
filter.actionType(this.actionType());
|
filter.actionType(this.actionType());
|
||||||
|
|
||||||
filter.actionValue(this.actionValue());
|
filter.actionValue(this.actionValue());
|
||||||
filter.actionValue.error(this.actionValue.error());
|
filter.actionValueError(this.actionValueError());
|
||||||
|
|
||||||
filter.actionValueSecond(this.actionValueSecond());
|
filter.actionValueSecond(this.actionValueSecond());
|
||||||
filter.actionValueThird(this.actionValueThird());
|
filter.actionValueThird(this.actionValueThird());
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,15 @@ class FilterConditionModel extends AbstractModel {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.field = ko.observable(FilterConditionField.From);
|
this.addObservables({
|
||||||
this.type = ko.observable(FilterConditionType.Contains);
|
field: FilterConditionField.From,
|
||||||
this.value = ko.observable('');
|
type: FilterConditionType.Contains,
|
||||||
this.value.error = ko.observable(false);
|
value: '',
|
||||||
|
valueError: false,
|
||||||
|
|
||||||
this.valueSecond = ko.observable('');
|
valueSecond: '',
|
||||||
this.valueSecond.error = ko.observable(false);
|
valueSecondError: false
|
||||||
|
});
|
||||||
|
|
||||||
this.template = ko.computed(() => {
|
this.template = ko.computed(() => {
|
||||||
let template = '';
|
let template = '';
|
||||||
|
|
@ -33,22 +35,22 @@ class FilterConditionModel extends AbstractModel {
|
||||||
return template;
|
return template;
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.field.subscribe(() => {
|
this.addSubscribables({
|
||||||
this.value('');
|
field: () => {
|
||||||
this.valueSecond('');
|
this.value('');
|
||||||
|
this.valueSecond('');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.regDisposables([this.template]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
verify() {
|
verify() {
|
||||||
if (!this.value()) {
|
if (!this.value()) {
|
||||||
this.value.error(true);
|
this.valueError(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FilterConditionField.Header === this.field() && !this.valueSecond()) {
|
if (FilterConditionField.Header === this.field() && !this.valueSecond()) {
|
||||||
this.valueSecond.error(true);
|
this.valueSecondError(true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ class FolderModel extends AbstractModel {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = ko.observable('');
|
|
||||||
this.fullName = '';
|
this.fullName = '';
|
||||||
this.fullNameRaw = '';
|
this.fullNameRaw = '';
|
||||||
this.fullNameHash = '';
|
this.fullNameHash = '';
|
||||||
|
|
@ -23,23 +22,27 @@ class FolderModel extends AbstractModel {
|
||||||
this.selectable = false;
|
this.selectable = false;
|
||||||
this.existen = true;
|
this.existen = true;
|
||||||
|
|
||||||
this.type = ko.observable(FolderType.User);
|
this.addObservables({
|
||||||
|
name: '',
|
||||||
|
type: FolderType.User,
|
||||||
|
|
||||||
|
focused: false,
|
||||||
|
selected: false,
|
||||||
|
edited: false,
|
||||||
|
subScribed: true,
|
||||||
|
checkable: false,
|
||||||
|
deleteAccess: false,
|
||||||
|
|
||||||
|
nameForEdit: '',
|
||||||
|
|
||||||
|
privateMessageCountAll: 0,
|
||||||
|
privateMessageCountUnread: 0,
|
||||||
|
|
||||||
|
collapsedPrivate: true
|
||||||
|
});
|
||||||
|
|
||||||
this.focused = ko.observable(false);
|
|
||||||
this.selected = ko.observable(false);
|
|
||||||
this.edited = ko.observable(false);
|
|
||||||
this.subScribed = ko.observable(true);
|
|
||||||
this.checkable = ko.observable(false);
|
|
||||||
this.subFolders = ko.observableArray(new FolderCollectionModel);
|
this.subFolders = ko.observableArray(new FolderCollectionModel);
|
||||||
this.deleteAccess = ko.observable(false);
|
|
||||||
this.actionBlink = ko.observable(false).extend({ falseTimeout: 1000 });
|
this.actionBlink = ko.observable(false).extend({ falseTimeout: 1000 });
|
||||||
|
|
||||||
this.nameForEdit = ko.observable('');
|
|
||||||
|
|
||||||
this.privateMessageCountAll = ko.observable(0);
|
|
||||||
this.privateMessageCountUnread = ko.observable(0);
|
|
||||||
|
|
||||||
this.collapsedPrivate = ko.observable(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -230,14 +233,15 @@ class FolderModel extends AbstractModel {
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// subscribe
|
folder.addSubscribables({
|
||||||
folder.name.subscribe(value => folder.nameForEdit(value));
|
name: value => folder.nameForEdit(value),
|
||||||
|
|
||||||
folder.edited.subscribe(value => value && folder.nameForEdit(folder.name()));
|
edited: value => value && folder.nameForEdit(folder.name()),
|
||||||
|
|
||||||
folder.messageCountUnread.subscribe((unread) => {
|
messageCountUnread: unread => {
|
||||||
if (FolderType.Inbox === folder.type()) {
|
if (FolderType.Inbox === folder.type()) {
|
||||||
dispatchEvent(new CustomEvent('mailbox.inbox-unread-count', {detail:unread}));
|
dispatchEvent(new CustomEvent('mailbox.inbox-unread-count', {detail:unread}));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,17 +10,20 @@ class IdentityModel extends AbstractModel {
|
||||||
constructor(id, email) {
|
constructor(id, email) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.id = ko.observable(id || '');
|
this.addObservables({
|
||||||
this.email = ko.observable(email);
|
id: id || '',
|
||||||
this.name = ko.observable('');
|
email: email,
|
||||||
|
name: '',
|
||||||
|
|
||||||
this.replyTo = ko.observable('');
|
replyTo: '',
|
||||||
this.bcc = ko.observable('');
|
bcc: '',
|
||||||
|
|
||||||
this.signature = ko.observable('');
|
signature: '',
|
||||||
this.signatureInsertBefore = ko.observable(false);
|
signatureInsertBefore: false,
|
||||||
|
|
||||||
|
deleteAccess: false
|
||||||
|
});
|
||||||
|
|
||||||
this.deleteAccess = ko.observable(false);
|
|
||||||
this.canBeDeleted = ko.computed(() => !!this.id());
|
this.canBeDeleted = ko.computed(() => !!this.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,57 +31,56 @@ class MessageModel extends AbstractModel {
|
||||||
|
|
||||||
this._reset();
|
this._reset();
|
||||||
|
|
||||||
this.subject = ko.observable('');
|
this.addObservables({
|
||||||
this.subjectPrefix = ko.observable('');
|
subject: '',
|
||||||
this.subjectSuffix = ko.observable('');
|
subjectPrefix: '',
|
||||||
this.size = ko.observable(0);
|
subjectSuffix: '',
|
||||||
this.dateTimeStampInUTC = ko.observable(0);
|
size: 0,
|
||||||
this.priority = ko.observable(MessagePriority.Normal);
|
dateTimeStampInUTC: 0,
|
||||||
|
priority: MessagePriority.Normal,
|
||||||
|
|
||||||
this.senderEmailsString = ko.observable('');
|
senderEmailsString: '',
|
||||||
this.senderClearEmailsString = ko.observable('');
|
senderClearEmailsString: '',
|
||||||
|
|
||||||
this.newForAnimation = ko.observable(false);
|
newForAnimation: false,
|
||||||
|
|
||||||
this.deleted = ko.observable(false);
|
deleted: false,
|
||||||
this.isDeleted = ko.observable(false);
|
isDeleted: false,
|
||||||
this.isUnseen = ko.observable(false);
|
isUnseen: false,
|
||||||
this.isFlagged = ko.observable(false);
|
isFlagged: false,
|
||||||
this.isAnswered = ko.observable(false);
|
isAnswered: false,
|
||||||
this.isForwarded = ko.observable(false);
|
isForwarded: false,
|
||||||
this.isReadReceipt = ko.observable(false);
|
isReadReceipt: false,
|
||||||
|
|
||||||
this.focused = ko.observable(false);
|
focused: false,
|
||||||
this.selected = ko.observable(false);
|
selected: false,
|
||||||
this.checked = ko.observable(false);
|
checked: false,
|
||||||
this.hasAttachments = ko.observable(false);
|
hasAttachments: false,
|
||||||
this.attachmentsSpecData = ko.observableArray([]);
|
|
||||||
|
isHtml: false,
|
||||||
|
hasImages: false,
|
||||||
|
|
||||||
|
isPgpSigned: false,
|
||||||
|
isPgpEncrypted: false,
|
||||||
|
pgpSignedVerifyStatus: SignedVerifyStatus.None,
|
||||||
|
pgpSignedVerifyUser: '',
|
||||||
|
|
||||||
|
readReceipt: '',
|
||||||
|
|
||||||
|
hasUnseenSubMessage: false,
|
||||||
|
hasFlaggedSubMessage: false
|
||||||
|
});
|
||||||
|
|
||||||
this.attachmentIconClass = ko.computed(() =>
|
this.attachmentIconClass = ko.computed(() =>
|
||||||
File.getCombinedIconClass(this.hasAttachments() ? this.attachmentsSpecData() : [])
|
File.getCombinedIconClass(this.hasAttachments() ? this.attachmentsSpecData() : [])
|
||||||
);
|
);
|
||||||
|
|
||||||
this.isHtml = ko.observable(false);
|
this.attachments = ko.observableArray(new AttachmentCollectionModel);
|
||||||
this.hasImages = ko.observable(false);
|
this.attachmentsSpecData = ko.observableArray([]);
|
||||||
this.attachments = ko.observable(new AttachmentCollectionModel);
|
|
||||||
|
|
||||||
this.isPgpSigned = ko.observable(false);
|
|
||||||
this.isPgpEncrypted = ko.observable(false);
|
|
||||||
this.pgpSignedVerifyStatus = ko.observable(SignedVerifyStatus.None);
|
|
||||||
this.pgpSignedVerifyUser = ko.observable('');
|
|
||||||
|
|
||||||
this.priority = ko.observable(MessagePriority.Normal);
|
|
||||||
this.readReceipt = ko.observable('');
|
|
||||||
|
|
||||||
this.hasUnseenSubMessage = ko.observable(false);
|
|
||||||
this.hasFlaggedSubMessage = ko.observable(false);
|
|
||||||
|
|
||||||
this.threads = ko.observableArray([]);
|
this.threads = ko.observableArray([]);
|
||||||
|
|
||||||
this.threadsLen = ko.computed(() => this.threads().length);
|
this.threadsLen = ko.computed(() => this.threads().length);
|
||||||
this.isImportant = ko.computed(() => MessagePriority.High === this.priority());
|
this.isImportant = ko.computed(() => MessagePriority.High === this.priority());
|
||||||
|
|
||||||
this.regDisposables([this.attachmentIconClass, this.threadsLen, this.isImportant]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_reset() {
|
_reset() {
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,9 @@ class ContactsPopupView extends AbstractViewNext {
|
||||||
this.importUploaderButton = ko.observable(null);
|
this.importUploaderButton = ko.observable(null);
|
||||||
|
|
||||||
this.contactsPage = ko.observable(1);
|
this.contactsPage = ko.observable(1);
|
||||||
this.contactsPageCount = ko.computed(() => {
|
this.contactsPageCount = ko.computed(() =>
|
||||||
const iPage = Math.ceil(this.contactsCount() / CONTACTS_PER_PAGE);
|
Math.max(1, Math.ceil(this.contactsCount() / CONTACTS_PER_PAGE))
|
||||||
return 0 >= iPage ? 1 : iPage;
|
);
|
||||||
});
|
|
||||||
|
|
||||||
this.contactsPaginator = ko.computed(computedPaginatorHelper(this.contactsPage, this.contactsPageCount));
|
this.contactsPaginator = ko.computed(computedPaginatorHelper(this.contactsPage, this.contactsPageCount));
|
||||||
|
|
||||||
|
|
@ -104,10 +103,7 @@ class ContactsPopupView extends AbstractViewNext {
|
||||||
this.viewPropertiesNames().filter(property => !!trim(property.value()))
|
this.viewPropertiesNames().filter(property => !!trim(property.value()))
|
||||||
);
|
);
|
||||||
|
|
||||||
const propertyFocused = (property) => {
|
const propertyFocused = property => !trim(property.value()) && !property.focused();
|
||||||
const focused = property.focused();
|
|
||||||
return !trim(property.value()) && !focused;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.viewPropertiesEmailsEmptyAndOnFocused = ko.computed(() =>
|
this.viewPropertiesEmailsEmptyAndOnFocused = ko.computed(() =>
|
||||||
this.viewPropertiesEmails().filter(propertyFocused)
|
this.viewPropertiesEmails().filter(propertyFocused)
|
||||||
|
|
@ -117,7 +113,9 @@ class ContactsPopupView extends AbstractViewNext {
|
||||||
this.viewPropertiesPhones().filter(propertyFocused)
|
this.viewPropertiesPhones().filter(propertyFocused)
|
||||||
);
|
);
|
||||||
|
|
||||||
this.viewPropertiesWebEmptyAndOnFocused = ko.computed(() => this.viewPropertiesWeb().filter(propertyFocused));
|
this.viewPropertiesWebEmptyAndOnFocused = ko.computed(() =>
|
||||||
|
this.viewPropertiesWeb().filter(propertyFocused)
|
||||||
|
);
|
||||||
|
|
||||||
this.viewPropertiesOtherEmptyAndOnFocused = ko.computed(() =>
|
this.viewPropertiesOtherEmptyAndOnFocused = ko.computed(() =>
|
||||||
this.viewPropertiesOther().filter(propertyFocused)
|
this.viewPropertiesOther().filter(propertyFocused)
|
||||||
|
|
@ -141,9 +139,7 @@ class ContactsPopupView extends AbstractViewNext {
|
||||||
|
|
||||||
this.useCheckboxesInList = SettingsStore.useCheckboxesInList;
|
this.useCheckboxesInList = SettingsStore.useCheckboxesInList;
|
||||||
|
|
||||||
this.search.subscribe(() => {
|
this.search.subscribe(() => this.reloadContactList());
|
||||||
this.reloadContactList();
|
|
||||||
});
|
|
||||||
|
|
||||||
this.contactsChecked = ko.computed(() => this.contacts().filter(item => item.checked()));
|
this.contactsChecked = ko.computed(() => this.contacts().filter(item => item.checked()));
|
||||||
|
|
||||||
|
|
@ -170,14 +166,14 @@ class ContactsPopupView extends AbstractViewNext {
|
||||||
'.e-contact-item.focused'
|
'.e-contact-item.focused'
|
||||||
);
|
);
|
||||||
|
|
||||||
this.selector.on('onItemSelect', (contact) => {
|
this.selector.on('onItemSelect', contact => {
|
||||||
this.populateViewContact(contact ? contact : null);
|
this.populateViewContact(contact || null);
|
||||||
if (!contact) {
|
if (!contact) {
|
||||||
this.emptySelection(true);
|
this.emptySelection(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.selector.on('onItemGetUid', (contact) => (contact ? contact.generateUid() : ''));
|
this.selector.on('onItemGetUid', contact => contact ? contact.generateUid() : '');
|
||||||
|
|
||||||
this.bDropPageAfterDelete = false;
|
this.bDropPageAfterDelete = false;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ class FilterPopupView extends AbstractViewNext {
|
||||||
|
|
||||||
this.selectedFolderValue.subscribe(() => {
|
this.selectedFolderValue.subscribe(() => {
|
||||||
if (this.filter()) {
|
if (this.filter()) {
|
||||||
this.filter().actionValue.error(false);
|
this.filter().actionValueError(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -157,13 +157,13 @@ class FilterPopupView extends AbstractViewNext {
|
||||||
this.isNew(!bEdit);
|
this.isNew(!bEdit);
|
||||||
|
|
||||||
if (!bEdit && oFilter) {
|
if (!bEdit && oFilter) {
|
||||||
oFilter.name.focused(true);
|
oFilter.nameFocused(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onShowWithDelay() {
|
onShowWithDelay() {
|
||||||
if (this.isNew() && this.filter()/* && !rl.settings.app('mobile')*/) {
|
if (this.isNew() && this.filter()/* && !rl.settings.app('mobile')*/) {
|
||||||
this.filter().name.focused(true);
|
this.filter().nameFocused(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,10 +11,10 @@
|
||||||
<div class="row filter" data-bind="with: filter, i18nInit: filter">
|
<div class="row filter" data-bind="with: filter, i18nInit: filter">
|
||||||
<div class="span9" data-bind="i18nInit: true">
|
<div class="span9" data-bind="i18nInit: true">
|
||||||
|
|
||||||
<div class="control-group" data-bind="css: {'error': name.error}">
|
<div class="control-group" data-bind="css: {'error': nameError}">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<input type="text" class="i18n span5"
|
<input type="text" class="i18n span5"
|
||||||
data-bind="value: name, hasFocus: name.focused"
|
data-bind="value: name, hasFocus: nameFocused"
|
||||||
autocorrect="off" autocapitalize="off" spellcheck="false"
|
autocorrect="off" autocapitalize="off" spellcheck="false"
|
||||||
data-i18n="[placeholder]POPUPS_FILTER/FILTER_NAME"
|
data-i18n="[placeholder]POPUPS_FILTER/FILTER_NAME"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="control-group" data-bind="css: {'error': actionValue.error}" style="margin-bottom: 0">
|
<div class="control-group" data-bind="css: {'error': actionValueError}" style="margin-bottom: 0">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div data-bind="component: {
|
<div data-bind="component: {
|
||||||
name: 'Checkbox',
|
name: 'Checkbox',
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="control-group" data-bind="css: {'error': actionValue.error}">
|
<div class="control-group" data-bind="css: {'error': actionValueError}">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<input type="text" class="span3 i18n" data-bind="value: actionValue"
|
<input type="text" class="span3 i18n" data-bind="value: actionValue"
|
||||||
data-i18n="[placeholder]POPUPS_FILTER/EMAIL_LABEL" />
|
data-i18n="[placeholder]POPUPS_FILTER/EMAIL_LABEL" />
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="control-group" data-bind="css: {'error': actionValue.error}">
|
<div class="control-group" data-bind="css: {'error': actionValueError}">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<select class="span3" data-bind="options: $root.folderSelectList, value: $root.selectedFolderValue,
|
<select class="span3" data-bind="options: $root.folderSelectList, value: $root.selectedFolderValue,
|
||||||
optionsText: 'name', optionsValue: 'id', optionsAfterRender: $root.defaultOptionsAfterRender"></select>
|
optionsText: 'name', optionsValue: 'id', optionsAfterRender: $root.defaultOptionsAfterRender"></select>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="control-group" data-bind="css: {'error': actionValue.error}" style="margin-bottom: 0">
|
<div class="control-group" data-bind="css: {'error': actionValueError}" style="margin-bottom: 0">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<div data-bind="component: {
|
<div data-bind="component: {
|
||||||
name: 'Checkbox',
|
name: 'Checkbox',
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="control-group" data-bind="css: {'error': actionValue.error}" style="margin-bottom: 0">
|
<div class="control-group" data-bind="css: {'error': actionValueError}" style="margin-bottom: 0">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<textarea class="span5 i18n" data-bind="value: actionValue" style="height: 100px;"
|
<textarea class="span5 i18n" data-bind="value: actionValue" style="height: 100px;"
|
||||||
data-i18n="[placeholder]POPUPS_FILTER/REJECT_MESSAGE_LABEL"></textarea>
|
data-i18n="[placeholder]POPUPS_FILTER/REJECT_MESSAGE_LABEL"></textarea>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
}"></div>
|
}"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group" data-bind="css: {'error': actionValueFourth.error}" style="margin-bottom: 0">
|
<div class="control-group" data-bind="css: {'error': actionValueFourthError}" style="margin-bottom: 0">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<input type="text" class="span5 i18n" data-bind="value: actionValueFourth"
|
<input type="text" class="span5 i18n" data-bind="value: actionValueFourth"
|
||||||
data-i18n="[placeholder]POPUPS_FILTER/VACATION_RECIPIENTS_LABEL" />
|
data-i18n="[placeholder]POPUPS_FILTER/VACATION_RECIPIENTS_LABEL" />
|
||||||
|
|
@ -26,7 +26,7 @@
|
||||||
data-i18n="[placeholder]POPUPS_FILTER/VACATION_SUBJECT_LABEL" />
|
data-i18n="[placeholder]POPUPS_FILTER/VACATION_SUBJECT_LABEL" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="control-group" data-bind="css: {'error': actionValue.error}" style="margin-bottom: 0">
|
<div class="control-group" data-bind="css: {'error': actionValueError}" style="margin-bottom: 0">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<textarea class="span5 i18n" data-bind="value: actionValue" style="height: 100px;"
|
<textarea class="span5 i18n" data-bind="value: actionValue" style="height: 100px;"
|
||||||
data-i18n="[placeholder]POPUPS_FILTER/VACATION_MESSAGE_LABEL"></textarea>
|
data-i18n="[placeholder]POPUPS_FILTER/VACATION_MESSAGE_LABEL"></textarea>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="control-group" data-bind="css: {'error': value.error}" style="margin-bottom: 0">
|
<div class="control-group" data-bind="css: {'error': valueError}" style="margin-bottom: 0">
|
||||||
<select class="span3" data-bind="options: $root.fieldOptions, value: field, optionsText: 'name', optionsValue: 'id'"></select>
|
<select class="span3" data-bind="options: $root.fieldOptions, value: field, optionsText: 'name', optionsValue: 'id'"></select>
|
||||||
|
|
||||||
<select class="span2" data-bind="options: $root.typeOptions, value: type, optionsText: 'name', optionsValue: 'id'"></select>
|
<select class="span2" data-bind="options: $root.typeOptions, value: type, optionsText: 'name', optionsValue: 'id'"></select>
|
||||||
|
|
@ -9,4 +9,4 @@
|
||||||
data-bind="click: function (oCondition) { $root.removeCondition(oCondition); }">
|
data-bind="click: function (oCondition) { $root.removeCondition(oCondition); }">
|
||||||
<i class="icon-trash"></i>
|
<i class="icon-trash"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="control-group" data-bind="css: {'error': value.error}" style="margin-bottom: 0">
|
<div class="control-group" data-bind="css: {'error': valueError}" style="margin-bottom: 0">
|
||||||
<select class="span2" data-bind="options: $root.fieldOptions, value: field, optionsText: 'name', optionsValue: 'id'"></select>
|
<select class="span2" data-bind="options: $root.fieldOptions, value: field, optionsText: 'name', optionsValue: 'id'"></select>
|
||||||
|
|
||||||
<input class="span2" type="text" data-bind="value: valueSecond" />
|
<input class="span2" type="text" data-bind="value: valueSecond" />
|
||||||
|
|
@ -11,4 +11,4 @@
|
||||||
data-bind="click: function (oCondition) { $root.removeCondition(oCondition); }">
|
data-bind="click: function (oCondition) { $root.removeCondition(oCondition); }">
|
||||||
<i class="icon-trash"></i>
|
<i class="icon-trash"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
<div class="control-group" data-bind="css: {'error': value.error}" style="margin-bottom: 0">
|
<div class="control-group" data-bind="css: {'error': valueError}" style="margin-bottom: 0">
|
||||||
<select class="span3" data-bind="options: $root.fieldOptions, value: field, optionsText: 'name', optionsValue: 'id'"></select>
|
<select class="span3" data-bind="options: $root.fieldOptions, value: field, optionsText: 'name', optionsValue: 'id'"></select>
|
||||||
|
|
||||||
<select class="span2" data-bind="options: $root.typeOptionsSize, value: type, optionsText: 'name', optionsValue: 'id'"></select>
|
<select class="span2" data-bind="options: $root.typeOptionsSize, value: type, optionsText: 'name', optionsValue: 'id'"></select>
|
||||||
|
|
@ -9,4 +9,4 @@
|
||||||
data-bind="click: function (oCondition) { $root.removeCondition(oCondition); }">
|
data-bind="click: function (oCondition) { $root.removeCondition(oCondition); }">
|
||||||
<i class="icon-trash"></i>
|
<i class="icon-trash"></i>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue