snappymail/dev/View/Popup/Contacts.js

335 lines
8.1 KiB
JavaScript
Raw Normal View History

import { addObservablesTo, addComputablesTo } from 'External/ko';
2021-01-25 05:58:06 +08:00
import { ComposeType } from 'Common/EnumsUser';
import { registerShortcut } from 'Common/Globals';
2021-07-22 03:34:17 +08:00
import { arrayLength, pInt } from 'Common/Utils';
import { download, computedPaginatorHelper, showMessageComposer } from 'Common/UtilsUser';
2019-07-05 03:19:24 +08:00
import { Selector } from 'Common/Selector';
2021-02-04 18:25:00 +08:00
import { serverRequestRaw, serverRequest } from 'Common/Links';
2019-07-05 03:19:24 +08:00
import { i18n, getNotification } from 'Common/Translator';
import { SettingsUserStore } from 'Stores/User/Settings';
import { ContactUserStore } from 'Stores/User/Contact';
import Remote from 'Remote/User/Fetch';
2019-07-05 03:19:24 +08:00
import { EmailModel } from 'Model/Email';
import { ContactModel } from 'Model/Contact';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews';
2022-03-03 23:41:34 +08:00
import { AskPopupView } from 'View/Popup/Ask';
const
CONTACTS_PER_PAGE = 50,
2022-05-29 06:22:50 +08:00
ScopeContacts = 'Contacts';
2022-09-07 19:45:30 +08:00
let
bOpenCompose = false,
sComposeRecipientsField = '';
2022-02-24 21:01:41 +08:00
export class ContactsPopupView extends AbstractViewPopup {
constructor() {
super('Contacts');
addObservablesTo(this, {
search: '',
contactsCount: 0,
2022-07-23 04:59:50 +08:00
selectorContact: null,
2016-06-30 08:02:45 +08:00
2022-07-23 04:59:50 +08:00
importButton: null,
2016-06-30 08:02:45 +08:00
contactsPage: 1,
2016-06-30 08:02:45 +08:00
2022-07-25 16:13:50 +08:00
isSaving: false,
2022-05-29 06:22:50 +08:00
contact: null
});
this.contacts = ContactUserStore;
this.useCheckboxesInList = SettingsUserStore.useCheckboxesInList;
this.selector = new Selector(
ContactUserStore,
2022-07-23 04:59:50 +08:00
this.selectorContact,
2019-07-05 03:19:24 +08:00
null,
'.e-contact-item .actionHandle',
'.e-contact-item .checkboxItem',
'.e-contact-item.focused'
);
2015-02-16 05:55:59 +08:00
this.selector.on('ItemSelect', contact => this.populateViewContact(contact));
2021-07-19 17:57:47 +08:00
this.selector.on('ItemGetUid', contact => contact ? contact.generateUid() : '');
addComputablesTo(this, {
2022-09-07 19:45:30 +08:00
contactsPaginator: computedPaginatorHelper(
this.contactsPage,
() => Math.max(1, Math.ceil(this.contactsCount() / CONTACTS_PER_PAGE))
),
contactsCheckedOrSelected: () => {
const checked = ContactUserStore.filter(item => item.checked()),
2022-07-23 04:59:50 +08:00
selected = this.selectorContact();
2022-09-07 19:45:30 +08:00
return checked.length ? checked : (selected ? [selected] : []);
},
2022-09-07 19:45:30 +08:00
contactsSyncEnabled: () => ContactUserStore.allowSync() && ContactUserStore.syncMode(),
2022-09-07 19:45:30 +08:00
isBusy: () => ContactUserStore.syncing() | ContactUserStore.importing() | ContactUserStore.loading()
| this.isSaving()
});
this.search.subscribe(() => this.reloadContactList());
2022-05-29 06:22:50 +08:00
this.saveCommand = this.saveCommand.bind(this);
decorateKoCommands(this, {
2022-09-07 19:45:30 +08:00
deleteCommand: self => !self.isBusy() && 0 < self.contactsCheckedOrSelected().length,
newMessageCommand: self => !self.isBusy() && 0 < self.contactsCheckedOrSelected().length,
saveCommand: self => !self.isBusy(),
syncCommand: self => !self.isBusy()
});
2016-09-10 06:38:16 +08:00
}
2022-02-21 22:36:34 +08:00
newContact() {
2022-09-07 19:45:30 +08:00
this.populateViewContact(new ContactModel);
2022-07-23 04:59:50 +08:00
this.selectorContact(null);
2016-09-10 06:38:16 +08:00
}
2016-09-10 06:38:16 +08:00
deleteCommand() {
2022-09-07 19:45:30 +08:00
const contacts = this.contactsCheckedOrSelected();
if (contacts.length) {
let selectorContact = this.selectorContact(),
uids = [],
2022-09-07 19:45:30 +08:00
count = 0;
contacts.forEach(contact => {
uids.push(contact.id());
2022-09-07 19:45:30 +08:00
if (selectorContact && selectorContact.id() === contact.id()) {
this.selectorContact(selectorContact = null);
}
contact.deleted(true);
++count;
});
Remote.request('ContactsDelete',
(iError, oData) => {
if (iError) {
alert(oData?.ErrorMessage || getNotification(iError));
} else {
const page = this.contactsPage();
if (page > Math.max(1, Math.ceil((this.contactsCount() - count) / CONTACTS_PER_PAGE))) {
this.contactsPage(page - 1);
}
// contacts.forEach(contact => ContactUserStore.remove(contact));
}
this.reloadContactList();
}, {
uids: uids.join(',')
2022-09-07 19:45:30 +08:00
}
);
}
2016-09-10 06:38:16 +08:00
}
2016-09-10 06:38:16 +08:00
newMessageCommand() {
2019-07-05 03:19:24 +08:00
let aE = [],
2022-09-07 19:45:30 +08:00
recipients = {to:null,cc:null,bcc:null};
2022-09-07 19:45:30 +08:00
this.contactsCheckedOrSelected().forEach(oContact => {
const data = oContact?.getNameAndEmailHelper(),
email = data ? new EmailModel(data[0], data[1]) : null;
2023-02-14 00:05:44 +08:00
email?.valid() && aE.push(email);
2022-09-07 19:45:30 +08:00
});
2021-07-22 03:34:17 +08:00
if (arrayLength(aE)) {
2022-09-07 19:45:30 +08:00
bOpenCompose = false;
this.close();
2022-09-07 19:45:30 +08:00
recipients[sComposeRecipientsField] = aE;
showMessageComposer([ComposeType.Empty, null, recipients.to, recipients.cc, recipients.bcc])
2016-09-10 06:38:16 +08:00
}
}
2022-02-21 22:36:34 +08:00
clearSearch() {
2016-09-10 06:38:16 +08:00
this.search('');
}
2014-08-21 23:08:34 +08:00
2016-09-10 06:38:16 +08:00
saveCommand() {
this.saveContact(this.contact());
}
saveContact(contact) {
const data = contact.toJSON();
if (data.jCard != JSON.stringify(contact.jCard)) {
this.isSaving(true);
Remote.request('ContactSave',
(iError, oData) => {
if (iError) {
alert(oData?.ErrorMessage || getNotification(iError));
} else if (oData.Result.ResultID) {
if (contact.id()) {
contact.id(oData.Result.ResultID);
contact.jCard = JSON.parse(data.jCard);
} else {
this.reloadContactList(); // TODO: remove when e-contact-foreach is dynamic
}
}
2022-09-07 19:45:30 +08:00
this.isSaving(false);
}, data
);
}
2016-09-10 06:38:16 +08:00
}
2016-09-10 06:38:16 +08:00
syncCommand() {
2021-09-23 20:24:06 +08:00
ContactUserStore.sync(iError => {
iError && alert(getNotification(iError));
2016-09-10 06:38:16 +08:00
this.reloadContactList(true);
});
2016-06-30 08:02:45 +08:00
}
exportVcf() {
download(serverRequestRaw('ContactsVcf'), 'contacts.vcf');
}
2016-06-30 08:02:45 +08:00
exportCsv() {
download(serverRequestRaw('ContactsCsv'), 'contacts.csv');
}
/**
* @param {?ContactModel} contact
*/
populateViewContact(contact) {
const oldContact = this.contact(),
fn = () => this.contact(contact);
if (oldContact?.hasChanges()) {
AskPopupView.showModal([
i18n('GLOBAL/SAVE_CHANGES'),
() => this.saveContact(oldContact) | fn(),
fn
]);
} else fn();
}
/**
* @param {boolean=} dropPagePosition = false
*/
reloadContactList(dropPagePosition = false) {
let offset = (this.contactsPage() - 1) * CONTACTS_PER_PAGE;
2014-08-21 23:08:34 +08:00
2019-07-05 03:19:24 +08:00
if (dropPagePosition) {
this.contactsPage(1);
offset = 0;
}
2014-08-21 23:08:34 +08:00
ContactUserStore.loading(true);
Remote.abort('Contacts').request('Contacts',
(iError, data) => {
2019-07-05 03:19:24 +08:00
let count = 0,
list = [];
2022-09-05 17:04:12 +08:00
if (iError) {
// console.error(data);
alert(data?.ErrorMessage || getNotification(iError));
} else if (arrayLength(data.Result.List)) {
2021-03-18 21:48:21 +08:00
data.Result.List.forEach(item => {
item = ContactModel.reviveFromJson(item);
item && list.push(item);
});
count = pInt(data.Result.Count);
}
2022-09-07 19:45:30 +08:00
this.contactsCount(0 < count ? count : 0);
ContactUserStore(list);
ContactUserStore.loading(false);
2019-07-05 03:19:24 +08:00
},
{
Offset: offset,
Limit: CONTACTS_PER_PAGE,
Search: this.search()
}
2019-07-05 03:19:24 +08:00
);
}
onBuild(dom) {
this.selector.init(dom.querySelector('.b-list-content'), ScopeContacts);
registerShortcut('delete', '', ScopeContacts, () => {
this.deleteCommand();
return false;
});
2016-06-30 08:02:45 +08:00
registerShortcut('c,w', '', ScopeContacts, () => {
this.newMessageCommand();
return false;
});
const self = this;
2014-08-21 23:08:34 +08:00
dom.addEventListener('click', event => {
2021-11-05 18:17:46 +08:00
let el = event.target.closestWithin('.e-paginator a', dom);
2022-09-07 19:45:30 +08:00
if (el && (el = pInt(ko.dataFor(el)?.value))) {
self.contactsPage(el);
2019-07-05 03:19:24 +08:00
self.reloadContactList();
}
});
2014-08-21 23:08:34 +08:00
2021-08-13 02:17:37 +08:00
// initUploader
2022-07-23 04:59:50 +08:00
if (this.importButton()) {
2021-08-13 02:17:37 +08:00
const j = new Jua({
action: serverRequest('UploadContacts'),
2021-09-14 18:50:56 +08:00
limit: 1,
2022-07-23 04:59:50 +08:00
clickElement: this.importButton()
2021-08-13 02:17:37 +08:00
});
if (j) {
j.on('onStart', () => {
ContactUserStore.importing(true);
}).on('onComplete', (id, result, data) => {
ContactUserStore.importing(false);
this.reloadContactList();
if (!id || !result || !data || !data.Result) {
alert(i18n('CONTACTS/ERROR_IMPORT_FILE'));
}
});
}
}
}
tryToClose() {
(false === this.onClose()) || this.close();
}
2022-03-03 23:41:34 +08:00
onClose() {
const contact = this.contact();
if (AskPopupView.hidden() && contact?.hasChanges()) {
AskPopupView.showModal([
i18n('GLOBAL/SAVE_CHANGES'),
() => this.close() | this.saveContact(contact),
() => this.close()
2022-03-03 23:41:34 +08:00
]);
return false;
}
}
2022-09-07 19:45:30 +08:00
onShow(bBackToCompose, sRecipientsField) {
bOpenCompose = !!bBackToCompose;
sComposeRecipientsField = ['to','cc','bcc'].includes(sRecipientsField) ? sRecipientsField : 'to';
this.reloadContactList(true);
}
2014-08-21 23:08:34 +08:00
onHide() {
2022-05-29 06:22:50 +08:00
this.contact(null);
2022-07-23 04:59:50 +08:00
this.selectorContact(null);
this.search('');
this.contactsCount(0);
2014-10-04 19:58:01 +08:00
ContactUserStore([]);
2022-09-07 19:45:30 +08:00
bOpenCompose && showMessageComposer();
2016-06-30 08:02:45 +08:00
}
}