Cleanup some JavaScript

This commit is contained in:
the-djmaze 2022-02-21 15:36:34 +01:00
parent 18fbf332c2
commit 24b638cd82
16 changed files with 64 additions and 88 deletions

View file

@ -328,6 +328,10 @@ export const
l && l.remove(); l && l.remove();
}, },
/**
* Used by ko.bindingHandlers.command (template data-bind="command: ")
* to enable/disable click/submit action.
*/
decorateKoCommands = (thisArg, commands) => decorateKoCommands = (thisArg, commands) =>
forEachObjectEntry(commands, (key, canExecute) => { forEachObjectEntry(commands, (key, canExecute) => {
let command = thisArg[key], let command = thisArg[key],

View file

@ -411,11 +411,4 @@ export class FolderModel extends AbstractModel {
: 'icon-none' : 'icon-none'
); );
} }
/**
* @returns {string}
*/
printableFullName() {
return this.fullName.replace(this.delimiter, ' / ');
}
} }

View file

@ -1,4 +1,4 @@
import ko from 'ko'; import { addObservablesTo } from 'External/ko';
import { SaveSettingsStep, UploadErrorCode, Capa } from 'Common/Enums'; import { SaveSettingsStep, UploadErrorCode, Capa } from 'Common/Enums';
import { changeTheme, convertThemeName } from 'Common/Utils'; import { changeTheme, convertThemeName } from 'Common/Utils';
@ -10,24 +10,29 @@ import { ThemeStore } from 'Stores/Theme';
import Remote from 'Remote/User/Fetch'; import Remote from 'Remote/User/Fetch';
const themeBackground = {
name: ThemeStore.userBackgroundName,
hash: ThemeStore.userBackgroundHash
};
addObservablesTo(themeBackground, {
uploaderButton: null,
loading: false,
error: ''
});
export class ThemesUserSettings /*extends AbstractViewSettings*/ { export class ThemesUserSettings /*extends AbstractViewSettings*/ {
constructor() { constructor() {
this.theme = ThemeStore.theme; this.theme = ThemeStore.theme;
this.themes = ThemeStore.themes; this.themes = ThemeStore.themes;
this.themesObjects = ko.observableArray(); this.themesObjects = ko.observableArray();
this.background = {}; this.background = themeBackground;
this.background.name = ThemeStore.userBackgroundName;
this.background.hash = ThemeStore.userBackgroundHash;
this.background.uploaderButton = ko.observable(null);
this.background.loading = ko.observable(false);
this.background.error = ko.observable('');
this.capaUserBackground = ko.observable(Settings.capa(Capa.UserBackground)); this.capaUserBackground = Settings.capa(Capa.UserBackground);
this.themeTrigger = ko.observable(SaveSettingsStep.Idle).extend({ debounce: 100 }); this.themeTrigger = ko.observable(SaveSettingsStep.Idle).extend({ debounce: 100 });
this.theme.subscribe((value) => { ThemeStore.theme.subscribe(value => {
this.themesObjects.forEach(theme => { this.themesObjects.forEach(theme => {
theme.selected(value === theme.name); theme.selected(value === theme.name);
}); });
@ -41,10 +46,10 @@ export class ThemesUserSettings /*extends AbstractViewSettings*/ {
} }
onBuild() { onBuild() {
const currentTheme = this.theme(); const currentTheme = ThemeStore.theme();
this.themesObjects( this.themesObjects(
this.themes.map(theme => ({ ThemeStore.themes.map(theme => ({
name: theme, name: theme,
nameDisplay: convertThemeName(theme), nameDisplay: convertThemeName(theme),
selected: ko.observable(theme === currentTheme), selected: ko.observable(theme === currentTheme),
@ -54,28 +59,28 @@ export class ThemesUserSettings /*extends AbstractViewSettings*/ {
// initUploader // initUploader
if (this.background.uploaderButton() && this.capaUserBackground()) { if (themeBackground.uploaderButton() && this.capaUserBackground) {
const oJua = new Jua({ const oJua = new Jua({
action: serverRequest('UploadBackground'), action: serverRequest('UploadBackground'),
limit: 1, limit: 1,
clickElement: this.background.uploaderButton() clickElement: themeBackground.uploaderButton()
}); });
oJua oJua
.on('onStart', () => { .on('onStart', () => {
this.background.loading(true); themeBackground.loading(true);
this.background.error(''); themeBackground.error('');
return true; return true;
}) })
.on('onComplete', (id, result, data) => { .on('onComplete', (id, result, data) => {
this.background.loading(false); themeBackground.loading(false);
if (result && id && data && data.Result && data.Result.Name && data.Result.Hash) { if (result && id && data && data.Result && data.Result.Name && data.Result.Hash) {
this.background.name(data.Result.Name); themeBackground.name(data.Result.Name);
this.background.hash(data.Result.Hash); themeBackground.hash(data.Result.Hash);
} else { } else {
this.background.name(''); themeBackground.name('');
this.background.hash(''); themeBackground.hash('');
let errorMsg = ''; let errorMsg = '';
if (data.ErrorCode) { if (data.ErrorCode) {
@ -94,7 +99,7 @@ export class ThemesUserSettings /*extends AbstractViewSettings*/ {
errorMsg = data.ErrorMessage; errorMsg = data.ErrorMessage;
} }
this.background.error(errorMsg || i18n('SETTINGS_THEMES/ERROR_UNKNOWN')); themeBackground.error(errorMsg || i18n('SETTINGS_THEMES/ERROR_UNKNOWN'));
} }
return true; return true;
@ -103,14 +108,14 @@ export class ThemesUserSettings /*extends AbstractViewSettings*/ {
} }
onShow() { onShow() {
this.background.error(''); themeBackground.error('');
} }
clearBackground() { clearBackground() {
if (this.capaUserBackground()) { if (this.capaUserBackground) {
Remote.request('ClearUserBackground', () => { Remote.request('ClearUserBackground', () => {
this.background.name(''); themeBackground.name('');
this.background.hash(''); themeBackground.hash('');
}); });
} }
} }

View file

@ -4,7 +4,6 @@ import { i18n, trigger as translatorTrigger } from 'Common/Translator';
import { MessageUserStore } from 'Stores/User/Message'; import { MessageUserStore } from 'Stores/User/Message';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { FolderUserStore } from 'Stores/User/Folder'; import { FolderUserStore } from 'Stores/User/Folder';
@ -50,13 +49,9 @@ class AdvancedSearchPopupView extends AbstractViewPopup {
{ id: 'subtree', name: i18n(prefix + 'SUBTREE') } { id: 'subtree', name: i18n(prefix + 'SUBTREE') }
]; ];
}); });
decorateKoCommands(this, {
searchCommand: 1
});
} }
searchCommand() { submitForm() {
const search = this.buildSearchString(); const search = this.buildSearchString();
if (search) { if (search) {
MessageUserStore.mainMessageListSearch(search); MessageUserStore.mainMessageListSearch(search);

View file

@ -136,17 +136,15 @@ class ContactsPopupView extends AbstractViewPopup {
}); });
decorateKoCommands(this, { decorateKoCommands(this, {
newCommand: 1,
deleteCommand: self => 0 < self.contactsCheckedOrSelected().length, deleteCommand: self => 0 < self.contactsCheckedOrSelected().length,
newMessageCommand: self => 0 < self.contactsCheckedOrSelected().length, newMessageCommand: self => 0 < self.contactsCheckedOrSelected().length,
clearCommand: 1,
saveCommand: self => !self.viewSaving() && !self.viewReadOnly() saveCommand: self => !self.viewSaving() && !self.viewReadOnly()
&& (self.contactHasValidName() || self.viewProperties.find(prop => propertyIsMail(prop) && prop.isValid())), && (self.contactHasValidName() || self.viewProperties.find(prop => propertyIsMail(prop) && prop.isValid())),
syncCommand: self => !self.contacts.syncing() && !self.contacts.importing() syncCommand: self => !self.contacts.syncing() && !self.contacts.importing()
}); });
} }
newCommand() { newContact() {
this.populateViewContact(null); this.populateViewContact(null);
this.currentContact(null); this.currentContact(null);
} }
@ -207,7 +205,7 @@ class ContactsPopupView extends AbstractViewPopup {
return true; return true;
} }
clearCommand() { clearSearch() {
this.search(''); this.search('');
} }

View file

@ -9,7 +9,6 @@ import { i18n, initOnStartOrLangChange } from 'Common/Translator';
import { SieveUserStore } from 'Stores/User/Sieve'; import { SieveUserStore } from 'Stores/User/Sieve';
import { decorateKoCommands } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { folderListOptionsBuilder } from 'Common/UtilsUser'; import { folderListOptionsBuilder } from 'Common/UtilsUser';
@ -45,13 +44,9 @@ class FilterPopupView extends AbstractViewPopup {
initOnStartOrLangChange(this.populateOptions.bind(this)); initOnStartOrLangChange(this.populateOptions.bind(this));
SieveUserStore.capa.subscribe(this.populateOptions, this); SieveUserStore.capa.subscribe(this.populateOptions, this);
decorateKoCommands(this, {
saveFilterCommand: 1
});
} }
saveFilterCommand() { saveFilter() {
if (this.filter()) { if (this.filter()) {
if (FilterAction.MoveTo === this.filter().actionType()) { if (FilterAction.MoveTo === this.filter().actionType()) {
this.filter().actionValue(this.selectedFolderValue()); this.filter().actionValue(this.selectedFolderValue());

View file

@ -19,17 +19,11 @@ class FolderClearPopupView extends AbstractViewPopup {
}); });
this.addComputables({ this.addComputables({
folderFullNameForClear: () => { dangerDescHtml: () => {
const folder = this.selectedFolder(); const folder = this.selectedFolder();
return folder ? folder.printableFullName() : ''; // return i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { FOLDER: folder ? folder.fullName.replace(folder.delimiter, ' / ') : '' });
}, return i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { FOLDER: folder ? folder.localName() : '' });
}
folderNameForClear: () => {
const folder = this.selectedFolder();
return folder ? folder.localName() : '';
},
dangerDescHtml: () => i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { FOLDER: this.folderNameForClear() })
}); });
decorateKoCommands(this, { decorateKoCommands(this, {

View file

@ -7,7 +7,7 @@ import Remote from 'Remote/User/Fetch';
import { FilterModel } from 'Model/Filter'; import { FilterModel } from 'Model/Filter';
import { SieveUserStore } from 'Stores/User/Sieve'; import { SieveUserStore } from 'Stores/User/Sieve';
import { showScreenPopup/*, decorateKoCommands*/ } from 'Knoin/Knoin'; import { showScreenPopup } from 'Knoin/Knoin';
import { AbstractViewPopup } from 'Knoin/AbstractViews'; import { AbstractViewPopup } from 'Knoin/AbstractViews';
import { FilterPopupView } from 'View/Popup/Filter'; import { FilterPopupView } from 'View/Popup/Filter';
@ -28,14 +28,9 @@ class SieveScriptPopupView extends AbstractViewPopup {
this.saving = false; this.saving = false;
this.filterForDeletion = ko.observable(null).askDeleteHelper(); this.filterForDeletion = ko.observable(null).askDeleteHelper();
/*
decorateKoCommands(this, {
saveScriptCommand: 1
});
*/
} }
saveScriptCommand() { saveScript() {
let self = this, let self = this,
script = self.script(); script = self.script();
if (!self.saving/* && script.hasChanges()*/) { if (!self.saving/* && script.hasChanges()*/) {

View file

@ -237,8 +237,6 @@ export class MailMessageList extends AbstractViewRight {
).throttle(50)); ).throttle(50));
decorateKoCommands(this, { decorateKoCommands(this, {
clearCommand: 1,
reloadCommand: 1,
multyForwardCommand: canBeMovedHelper, multyForwardCommand: canBeMovedHelper,
deleteWithoutMoveCommand: canBeMovedHelper, deleteWithoutMoveCommand: canBeMovedHelper,
deleteCommand: canBeMovedHelper, deleteCommand: canBeMovedHelper,
@ -252,16 +250,16 @@ export class MailMessageList extends AbstractViewRight {
changeSort(self, event) { changeSort(self, event) {
FolderUserStore.sortMode(event.target.closest('li').dataset.sort); FolderUserStore.sortMode(event.target.closest('li').dataset.sort);
this.reloadCommand(); this.reload();
} }
clearCommand() { clear() {
if (SettingsCapa(Capa.DangerousActions)) { if (SettingsCapa(Capa.DangerousActions)) {
showScreenPopup(FolderClearPopupView, [FolderUserStore.currentFolder()]); showScreenPopup(FolderClearPopupView, [FolderUserStore.currentFolder()]);
} }
} }
reloadCommand() { reload() {
if (!MessageUserStore.listIsLoading()) { if (!MessageUserStore.listIsLoading()) {
rl.app.reloadMessageList(false, true); rl.app.reloadMessageList(false, true);
} }
@ -707,7 +705,7 @@ export class MailMessageList extends AbstractViewRight {
// check mail // check mail
shortcuts.add('r', 'meta', [Scope.FolderList, Scope.MessageList, Scope.MessageView], () => { shortcuts.add('r', 'meta', [Scope.FolderList, Scope.MessageList, Scope.MessageView], () => {
this.reloadCommand(); this.reload();
return false; return false;
}); });

View file

@ -231,14 +231,13 @@ export class MailMessageView extends AbstractViewRight {
addEventListener('mailbox.message-view.toggle-full-screen', () => this.toggleFullScreen()); addEventListener('mailbox.message-view.toggle-full-screen', () => this.toggleFullScreen());
decorateKoCommands(this, { decorateKoCommands(this, {
closeMessageCommand: 1,
messageEditCommand: self => self.messageVisibility(), messageEditCommand: self => self.messageVisibility(),
goUpCommand: self => !self.messageListOrViewLoading(), goUpCommand: self => !self.messageListOrViewLoading(),
goDownCommand: self => !self.messageListOrViewLoading() goDownCommand: self => !self.messageListOrViewLoading()
}); });
} }
closeMessageCommand() { closeMessage() {
MessageUserStore.message(null); MessageUserStore.message(null);
} }

View file

@ -5,7 +5,7 @@
<i class="icon-paper-plane"></i> <i class="icon-paper-plane"></i>
</a> </a>
<!-- /ko --> <!-- /ko -->
<a class="btn" data-bind="command: reloadCommand, visible: mobileCheckedStateHide()" data-i18n="[title]MESSAGE_LIST/BUTTON_RELOAD"> <a class="btn" data-bind="click: reload, visible: mobileCheckedStateHide()" data-i18n="[title]MESSAGE_LIST/BUTTON_RELOAD">
<i class="icon-spinner not-animated"></i> <i class="icon-spinner not-animated"></i>
</a> </a>
<!-- ko if: !newMoveToFolder --> <!-- ko if: !newMoveToFolder -->
@ -62,7 +62,7 @@
<li class="dividerbar" role="presentation" data-bind="visible: allowDangerousActions, command: deleteWithoutMoveCommand"> <li class="dividerbar" role="presentation" data-bind="visible: allowDangerousActions, command: deleteWithoutMoveCommand">
<a href="#" tabindex="-1" data-icon="🗑" data-i18n="MESSAGE_LIST/BUTTON_DELETE_WITHOUT_MOVE"></a> <a href="#" tabindex="-1" data-icon="🗑" data-i18n="MESSAGE_LIST/BUTTON_DELETE_WITHOUT_MOVE"></a>
</li> </li>
<li role="presentation" data-bind="visible: allowDangerousActions, command: clearCommand"> <li role="presentation" data-bind="visible: allowDangerousActions, click: clear">
<a href="#" tabindex="-1" data-icon="🔥" data-i18n="MESSAGE_LIST/BUTTON_EMPTY_FOLDER"></a> <a href="#" tabindex="-1" data-icon="🔥" data-i18n="MESSAGE_LIST/BUTTON_EMPTY_FOLDER"></a>
</li> </li>
</ul> </ul>
@ -116,7 +116,7 @@
<div class="listDragOver" data-bind="css: {'viewAppendArea': dragOver() && !messageListError() && !popupVisibility(), 'dragOverEnter': dragOverEnter }, initDom: dragOverArea" <div class="listDragOver" data-bind="css: {'viewAppendArea': dragOver() && !messageListError() && !popupVisibility(), 'dragOverEnter': dragOverEnter }, initDom: dragOverArea"
data-icon="⬇" data-i18n="MESSAGE_LIST/PUT_MESSAGE_HERE"></div> data-icon="⬇" data-i18n="MESSAGE_LIST/PUT_MESSAGE_HERE"></div>
<div class="listClear" data-bind="visible: clearListIsVisible()"> <div class="listClear" data-bind="visible: clearListIsVisible()">
<a href="#" class="g-ui-link" data-i18n="MESSAGE_LIST/BUTTON_EMPTY_FOLDER" data-bind="command: clearCommand"></a> <a href="#" class="g-ui-link" data-i18n="MESSAGE_LIST/BUTTON_EMPTY_FOLDER" data-bind="click: clear"></a>
</div> </div>
<div class="listError error" data-bind="visible: !dragOver() && messageListError(), text: messageListError"></div> <div class="listError error" data-bind="visible: !dragOver() && messageListError(), text: messageListError"></div>
<div class="listEmptyMessage" data-bind="visible: listEmptyMessage(), text: listEmptyMessage()"></div> <div class="listEmptyMessage" data-bind="visible: listEmptyMessage(), text: listEmptyMessage()"></div>

View file

@ -2,7 +2,7 @@
<div class="toolbar top-toolbar g-ui-user-select-none"> <div class="toolbar top-toolbar g-ui-user-select-none">
<div class="messageButtons btn-toolbar"> <div class="messageButtons btn-toolbar">
<div class="btn-group" data-i18n="[title]GLOBAL/CLOSE"> <div class="btn-group" data-i18n="[title]GLOBAL/CLOSE">
<a class="btn buttonClose fontastic" data-bind="command: closeMessageCommand"></a> <a class="btn buttonClose fontastic" data-bind="click: closeMessage"></a>
</div> </div>
<div class="btn-group" data-bind="visible: isDraftFolder()" data-i18n="[title]MESSAGE/BUTTON_EDIT"> <div class="btn-group" data-bind="visible: isDraftFolder()" data-i18n="[title]MESSAGE/BUTTON_EDIT">
<a class="btn btn-success buttonEdit fontastic" data-bind="command: messageEditCommand">🖉</a> <a class="btn btn-success buttonEdit fontastic" data-bind="command: messageEditCommand">🖉</a>
@ -131,7 +131,7 @@
<b style="color: red; margin-right: 5px" data-bind="visible: message().isImportant()">!</b> <b style="color: red; margin-right: 5px" data-bind="visible: message().isImportant()">!</b>
<span class="subject" data-bind="hidden: !message().subject(), text: message().subject, title: message().subject, event: { 'dblclick': toggleFullScreen }"></span> <span class="subject" data-bind="hidden: !message().subject(), text: message().subject, title: message().subject, event: { 'dblclick': toggleFullScreen }"></span>
<span class="emptySubjectText" data-i18n="MESSAGE/EMPTY_SUBJECT_TEXT" data-bind="hidden: message().subject(), event: { 'dblclick': toggleFullScreen }"></span> <span class="emptySubjectText" data-i18n="MESSAGE/EMPTY_SUBJECT_TEXT" data-bind="hidden: message().subject(), event: { 'dblclick': toggleFullScreen }"></span>
<a href="#" class="close" data-bind="command: closeMessageCommand" style="margin-top: -8px;">×</a> <a href="#" class="close" data-bind="click: closeMessage" style="margin-top: -8px;">×</a>
</div> </div>
<div data-bind="hidden: showFullInfo(), event: { 'dblclick': toggleFullScreen }"> <div data-bind="hidden: showFullInfo(), event: { 'dblclick': toggleFullScreen }">
<div class="informationShort"> <div class="informationShort">

View file

@ -3,28 +3,28 @@
<h3 data-i18n="SEARCH/TITLE_ADV"></h3> <h3 data-i18n="SEARCH/TITLE_ADV"></h3>
</header> </header>
<div class="modal-body"> <div class="modal-body">
<form class="form-horizontal" action="#/" autocomplete="off" onsubmit="return false;" data-bind="command: searchCommand"> <form id="searchform" class="form-horizontal" action="#/" autocomplete="off" data-bind="submit: submitForm">
<div class="row"> <div class="row">
<div class="span4"> <div class="span4">
<div class="control-group"> <div class="control-group">
<label data-i18n="GLOBAL/FROM"></label> <label data-i18n="GLOBAL/FROM"></label>
<input type="text" autofocus="" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" <input type="text" autofocus="" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: from, onEnter: searchCommand, onEsc: cancelCommand"> data-bind="value: from, onEsc: cancelCommand">
</div> </div>
<div class="control-group"> <div class="control-group">
<label data-i18n="GLOBAL/TO"></label> <label data-i18n="GLOBAL/TO"></label>
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: to, onEnter: searchCommand, onEsc: cancelCommand"> data-bind="value: to, onEsc: cancelCommand">
</div> </div>
<div class="control-group"> <div class="control-group">
<label data-i18n="GLOBAL/SUBJECT"></label> <label data-i18n="GLOBAL/SUBJECT"></label>
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: subject, onEnter: searchCommand, onEsc: cancelCommand"> data-bind="value: subject, onEsc: cancelCommand">
</div> </div>
<div class="control-group"> <div class="control-group">
<label data-i18n="SEARCH/LABEL_ADV_TEXT"></label> <label data-i18n="SEARCH/LABEL_ADV_TEXT"></label>
<input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
data-bind="value: text, onEnter: searchCommand, onEsc: cancelCommand"> data-bind="value: text, onEsc: cancelCommand">
</div> </div>
</div> </div>
<div class="span4"> <div class="span4">
@ -85,5 +85,5 @@
</form> </form>
</div> </div>
<footer> <footer>
<button type="submit" class="btn buttonAdvSearch" data-bind="command: searchCommand" data-icon="🔎" data-i18n="GLOBAL/SEARCH"></button> <button type="submit" form="searchform" class="btn buttonAdvSearch" data-icon="🔎" data-i18n="GLOBAL/SEARCH"></button>
</footer> </footer>

View file

@ -4,7 +4,7 @@
<div class="btn-toolbar"> <div class="btn-toolbar">
<a class="btn" data-bind="command: newCommand" data-icon="✚" data-i18n="CONTACTS/BUTTON_ADD_CONTACT"></a> <a class="btn" data-bind="click: newContact" data-icon="✚" data-i18n="CONTACTS/BUTTON_ADD_CONTACT"></a>
<a class="btn btn-success fontastic" data-bind="command: newMessageCommand"></a> <a class="btn btn-success fontastic" data-bind="command: newMessageCommand"></a>
@ -49,7 +49,7 @@
<div class="b-list-content g-ui-user-select-none" data-bind="css: {'hideContactListCheckbox': !useCheckboxesInList()}"> <div class="b-list-content g-ui-user-select-none" data-bind="css: {'hideContactListCheckbox': !useCheckboxesInList()}">
<div class="content"> <div class="content">
<div class="listClear" data-bind="visible: viewClearSearch() && '' !== search()"> <div class="listClear" data-bind="visible: viewClearSearch() && '' !== search()">
<span class="g-ui-link" data-i18n="CONTACTS/CLEAR_SEARCH" data-bind="command: clearCommand"></span> <span class="g-ui-link" data-i18n="CONTACTS/CLEAR_SEARCH" data-bind="click: clearSearch"></span>
</div> </div>
<div class="listEmptyList" data-bind="visible: 0 === contacts().length && '' === search() && !contacts.loading()" <div class="listEmptyList" data-bind="visible: 0 === contacts().length && '' === search() && !contacts.loading()"
data-i18n="CONTACTS/EMPTY_LIST"></div> data-i18n="CONTACTS/EMPTY_LIST"></div>

View file

@ -45,5 +45,5 @@
</div> </div>
</div> </div>
<footer> <footer>
<a class="btn buttonSave" data-bind="command: saveFilterCommand" data-icon="✔" data-i18n="GLOBAL/DONE"></a> <a class="btn buttonSave" data-bind="click: saveFilter" data-icon="✔" data-i18n="GLOBAL/DONE"></a>
</footer> </footer>

View file

@ -64,7 +64,7 @@
<a class="btn" data-bind="visible: $root.allowToggle, click: function() { $root.toggleFiltersRaw(); }, css: {'active': $root.rawActive }" data-i18n="[title]POPUPS_SIEVE_SCRIPT/BUTTON_RAW_SCRIPT"> <a class="btn" data-bind="visible: $root.allowToggle, click: function() { $root.toggleFiltersRaw(); }, css: {'active': $root.rawActive }" data-i18n="[title]POPUPS_SIEVE_SCRIPT/BUTTON_RAW_SCRIPT">
<i class="icon-file-code"></i> <i class="icon-file-code"></i>
</a> </a>
<a class="btn buttonSave" data-bind="visible: hasChanges, click: function() { $root.saveScriptCommand(); }, css: {'btn-danger': $root.saveError}"> <a class="btn buttonSave" data-bind="visible: hasChanges, click: function() { $root.saveScript(); }, css: {'btn-danger': $root.saveError}">
<i class="fontastic" data-bind="css: {'icon-spinner': $root.saving}">💾</i> <i class="fontastic" data-bind="css: {'icon-spinner': $root.saving}">💾</i>
<span data-i18n="GLOBAL/SAVE"></span> <span data-i18n="GLOBAL/SAVE"></span>
</a> </a>