Some cleanups for new AddressBook

This commit is contained in:
djmaze 2022-07-22 22:59:50 +02:00
parent c162a3acc6
commit 052f34a9f5
4 changed files with 43 additions and 72 deletions

View file

@ -15,7 +15,6 @@ export class ContactModel extends AbstractModel {
constructor() {
super();
this.properties = [];
this.jCard = new JCard();
this.addObservables({
@ -30,8 +29,7 @@ export class ContactModel extends AbstractModel {
surName: '', // LastName
middleName: '', // MiddleName
namePrefix: '', // NamePrefix
nameSuffix: '', // NameSuffix
nickname: null
nameSuffix: '' // NameSuffix
});
// this.email = koArrayWithDestroy();
this.email = ko.observableArray();
@ -43,6 +41,15 @@ export class ContactModel extends AbstractModel {
fullName: () => (this.givenName() + ' ' + this.surName()).trim(),
nickname: {
read: () => {
let prop = this.jCard.getOne('nickname');
return prop && prop.value;
},
write: value =>
value ? this.jCard.set('nickname', value/*, params, group*/) : this.jCard.remove('nickname')
},
display: () => {
let a = this.jCard.getOne('fn')?.value,
b = this.fullName(),
@ -85,17 +92,12 @@ export class ContactModel extends AbstractModel {
static reviveFromJson(json) {
const contact = super.reviveFromJson(json);
if (contact) {
let list = [];
let jCard = new JCard(json.jCard),
props = jCard.getOne('n')?.value;
props && props.forEach((value, index) =>
value && contact[nProps[index]](value)
);
props = jCard.getOne('nickname');
props && contact.nickname(props.value);
['email', 'tel', 'url'].forEach(field => {
props = jCard.get(field);
props && props.forEach(prop => {
@ -106,7 +108,6 @@ export class ContactModel extends AbstractModel {
});
});
contact.properties = list;
contact.jCard = jCard;
}
return contact;
@ -116,7 +117,7 @@ export class ContactModel extends AbstractModel {
* @returns {string}
*/
generateUid() {
return ''+this.id;
return '' + this.id;
}
addEmail() {
@ -160,8 +161,6 @@ export class ContactModel extends AbstractModel {
]/*, params, group*/);
// jCard.parseFullName({set:true});
this.nickname() ? jCard.set('nickname', this.nickname()/*, params, group*/) : jCard.remove('nickname');
['email', 'tel', 'url'].forEach(field => {
let values = this[field].map(item => item.value());
jCard.get(field).forEach(prop => {

View file

@ -148,10 +148,6 @@
font-weight: bold;
}
}
&.read-only .button-save-contact {
display: none;
}
}
.b-view-content {

View file

@ -23,7 +23,6 @@ import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { AskPopupView } from 'View/Popup/Ask';
const
viewProperties = koArrayWithDestroy(),
CONTACTS_PER_PAGE = 50,
ScopeContacts = 'Contacts';
@ -38,20 +37,15 @@ export class ContactsPopupView extends AbstractViewPopup {
search: '',
contactsCount: 0,
currentContact: null,
selectorContact: null,
importUploaderButton: null,
importButton: null,
contactsPage: 1,
viewClearSearch: false,
viewReadOnly: false,
viewSaving: false,
watchDirty: false,
watchHash: false,
hasChanges: false,
contact: null
});
@ -62,7 +56,7 @@ export class ContactsPopupView extends AbstractViewPopup {
this.selector = new Selector(
ContactUserStore,
this.currentContact,
this.selectorContact,
null,
'.e-contact-item .actionHandle',
'.e-contact-item .checkboxItem',
@ -87,7 +81,7 @@ export class ContactsPopupView extends AbstractViewPopup {
contactsCheckedOrSelected: () => {
const checked = ContactUserStore.filter(item => item.checked && item.checked()),
selected = this.currentContact();
selected = this.selectorContact();
return selected
? [...checked, selected].unique()
@ -96,34 +90,27 @@ export class ContactsPopupView extends AbstractViewPopup {
contactsCheckedOrSelectedUids: () => this.contactsCheckedOrSelected().map(contact => contact.id()),
contactsSyncEnabled: () => ContactUserStore.allowSync() && ContactUserStore.syncMode(),
viewHash: () => '' + viewProperties.map(property => property.value && property.value()).join('')
contactsSyncEnabled: () => ContactUserStore.allowSync() && ContactUserStore.syncMode()
});
this.search.subscribe(() => this.reloadContactList());
this.viewHash.subscribe(() => {
if (this.watchHash() && !this.viewReadOnly() && !this.watchDirty()) {
this.watchDirty(true);
}
});
this.saveCommand = this.saveCommand.bind(this);
// this.hasChanges(!!contact()?.toJSON().jCard);
decorateKoCommands(this, {
// close: self => !self.watchDirty(),
// close: self => !self.hasChanges(),
deleteCommand: self => 0 < self.contactsCheckedOrSelected().length,
newMessageCommand: self => 0 < self.contactsCheckedOrSelected().length,
saveCommand: self => !self.viewSaving() && !self.viewReadOnly()
&& (self.contact()?.hasValidName() || self.contact()?.email().length),
saveCommand: self => !self.viewSaving() && !self.hasChanges(),
syncCommand: self => !self.contacts.syncing() && !self.contacts.importing()
});
}
newContact() {
this.populateViewContact(null);
this.currentContact(null);
this.selectorContact(null);
}
deleteCommand() {
@ -207,7 +194,7 @@ export class ContactsPopupView extends AbstractViewPopup {
}
if (res) {
this.watchDirty(false);
this.hasChanges(false);
}
}, {
RequestUid: requestUid,
@ -237,14 +224,14 @@ export class ContactsPopupView extends AbstractViewPopup {
removeCheckedOrSelectedContactsFromList() {
const contacts = this.contactsCheckedOrSelected();
let currentContact = this.currentContact(),
let selectorContact = this.selectorContact(),
count = ContactUserStore.length;
if (contacts.length) {
contacts.forEach(contact => {
if (currentContact && currentContact.id() === contact.id()) {
currentContact = null;
this.currentContact(null);
if (selectorContact && selectorContact.id() === contact.id()) {
selectorContact = null;
this.selectorContact(null);
}
contact.deleted(true);
@ -282,18 +269,12 @@ export class ContactsPopupView extends AbstractViewPopup {
* @param {?ContactModel} contact
*/
populateViewContact(contact) {
this.watchHash(false);
if (!contact) {
contact = new ContactModel;
}
this.viewReadOnly(contact.readOnly());
this.contact(contact);
viewProperties(contact.properties);
this.watchDirty(false);
this.watchHash(true);
this.hasChanges(false);
}
/**
@ -330,7 +311,6 @@ export class ContactsPopupView extends AbstractViewPopup {
ContactUserStore(list);
ContactUserStore.loading(false);
this.viewClearSearch(!!this.search());
},
{
Offset: offset,
@ -368,12 +348,12 @@ export class ContactsPopupView extends AbstractViewPopup {
// initUploader
if (this.importUploaderButton()) {
if (this.importButton()) {
const j = new Jua({
action: serverRequest('UploadContacts'),
limit: 1,
disableDocumentDropPrevent: true,
clickElement: this.importUploaderButton()
clickElement: this.importButton()
});
if (j) {
@ -391,7 +371,7 @@ export class ContactsPopupView extends AbstractViewPopup {
}
onClose() {
if (this.watchDirty() && AskPopupView.hidden()) {
if (this.hasChanges() && AskPopupView.hidden()) {
showScreenPopup(AskPopupView, [
i18n('POPUPS_ASK/DESC_WANT_CLOSE_THIS_WINDOW'),
() => this.close()
@ -408,17 +388,15 @@ export class ContactsPopupView extends AbstractViewPopup {
onHide() {
this.contact(null);
this.currentContact(null);
this.selectorContact(null);
this.search('');
this.contactsCount(0);
ContactUserStore([]);
this.sLastComposeFocusedField = '';
if (this.bBackToCompose) {
this.bBackToCompose = false;
showMessageComposer();
}
}

View file

@ -14,7 +14,7 @@
<a id="contacts-more-dropdown-id" class="btn dropdown-toggle fontastic" href="#" tabindex="-1"></a>
<menu class="dropdown-menu right-edge" role="menu" aria-labelledby="contacts-more-dropdown-id">
<li role="presentation">
<a href="#" tabindex="-1" data-bind="initDom: importUploaderButton">
<a href="#" tabindex="-1" data-bind="initDom: importButton">
<i data-bind="css: {'icon-import': !contacts.importing(), 'icon-spinner': contacts.importing}"></i>
<span data-i18n="CONTACTS/BUTTON_IMPORT"></span>
</a>
@ -48,7 +48,7 @@
</div>
<div class="b-list-content g-ui-user-select-none" data-bind="css: {'hideContactListCheckbox': !useCheckboxesInList()}">
<div class="content">
<div class="listClear" data-bind="visible: viewClearSearch() && '' !== search()">
<div class="listClear" data-bind="visible: !!search()">
<span class="g-ui-link" data-i18n="CONTACTS/CLEAR_SEARCH" data-bind="click: clearSearch"></span>
</div>
<div class="listEmptyList" data-bind="visible: 0 === contacts().length && '' === search() && !contacts.loading()"
@ -72,16 +72,16 @@
<!-- ko template: { name: 'Paginator', data: contactsPaginator } --><!-- /ko -->
</div>
</div>
<div class="b-view-content-toolbar btn-toolbar" data-bind="css: {'read-only': viewReadOnly}, i18nUpdate: contact">
<div class="b-view-content-toolbar btn-toolbar" data-bind="i18nUpdate: contact">
<!-- ko with: contact -->
<div class="btn-group">
<button class="btn button-save-contact" data-bind="command: $root.saveCommand, css: {'dirty': $root.watchDirty}">
<button class="btn button-save-contact" data-bind="visible: !readOnly(), command: $root.saveCommand, css: {'dirty': $root.hasChanges}">
<i data-bind="css: {'icon-ok': !$root.viewSaving(), 'icon-spinner': $root.viewSaving()}"></i>
<span data-i18n="CONTACTS/BUTTON_CREATE_CONTACT" data-bind="visible: !id"></span>
<span data-i18n="CONTACTS/BUTTON_CREATE_CONTACT" data-bind="visible: !id()"></span>
<span data-i18n="CONTACTS/BUTTON_UPDATE_CONTACT" data-bind="visible: id"></span>
</button>
</div>
<div class="btn-group dropdown" data-bind="registerBootstrapDropdown: true">
<div class="btn-group dropdown" data-bind="visible: !readOnly(), registerBootstrapDropdown: true">
<a id="button-add-prop-dropdown-id" href="#" tabindex="-1" class="btn dropdown-toggle" data-i18n="CONTACTS/ADD_MENU_LABEL"></a>
<menu class="dropdown-menu right-edge" style="text-align: left" tabindex="-1" role="menu" aria-labelledby="button-add-prop-dropdown-id">
<li role="presentation">
@ -118,15 +118,15 @@
</div>
<!-- /ko -->
</div>
<div class="b-view-content" data-bind="css: {'read-only': viewReadOnly}">
<div class="b-view-content">
<div class="b-contact-view-desc" data-bind="visible: !contact"
data-i18n="CONTACTS/CONTACT_VIEW_DESC"></div>
<div data-bind="visible: contact, i18nUpdate: contact">
<div class="form-horizontal top-part">
<div class="control-group" data-bind="visible: !viewReadOnly() || hasValidName()">
<!-- ko with: contact -->
<div class="form-horizontal top-part" data-bind="css: {'read-only': readOnly}">
<div class="control-group" data-bind="visible: !readOnly() || hasValidName()">
<label class="fontastic iconsize24">👤</label>
<div>
<!-- ko with: contact -->
<div class="property-line">
<span data-bind="text: givenName"></span>
<input type="text"
@ -145,10 +145,8 @@
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: nickname" data-i18n="[placeholder]CONTACTS/PLACEHOLDER_ENTER_NICK_NAME">
</div>
<!-- /ko -->
</div>
</div>
<!-- ko with: contact -->
<div class="control-group" data-bind="email().length">
<label class="fontastic iconsize24" data-i18n="[title]GLOBAL/EMAIL">@</label>
<div>
@ -191,8 +189,8 @@
<a href="#" class="btn fontastic" data-bind="visible: !readOnly(), click: $root.addUrl"></a>
</div>
</div>
<!-- /ko -->
</div>
<!-- /ko -->
<!--
<div class="e-read-only-sign fontastic iconsize24" data-i18n="[title]CONTACTS/LABEL_READ_ONLY">🔒</div>
-->