From a096f963ef2f692d6f8b6422e1d3f4d7444de430 Mon Sep 17 00:00:00 2001 From: the-djmaze <> Date: Thu, 10 Mar 2022 10:27:04 +0100 Subject: [PATCH] Added Sieve settings concept. It fails due to i18n conflicts --- dev/Screen/User/Settings.js | 3 + dev/Settings/User/Sieve.js | 73 +++++++++++++ dev/sieve.js | 206 ++++++++++++++++++++++++++++++++++++ tasks/js.js | 2 +- 4 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 dev/Settings/User/Sieve.js create mode 100644 dev/sieve.js diff --git a/dev/Screen/User/Settings.js b/dev/Screen/User/Settings.js index 00f19ab67..b3b81cb61 100644 --- a/dev/Screen/User/Settings.js +++ b/dev/Screen/User/Settings.js @@ -21,6 +21,8 @@ import { SystemDropDownUserView } from 'View/User/SystemDropDown'; import { SettingsMenuUserView } from 'View/User/Settings/Menu'; import { SettingsPaneUserView } from 'View/User/Settings/Pane'; +//import { staticLink } from 'Common/Links'; + export class SettingsUserScreen extends AbstractSettingsScreen { constructor() { super([SystemDropDownUserView, SettingsMenuUserView, SettingsPaneUserView]); @@ -39,6 +41,7 @@ export class SettingsUserScreen extends AbstractSettingsScreen { if (SettingsCapa('Sieve')) { views.push(UserSettingsFilters); +// rl.loadScript(staticLink('js/sieve.js')).then(() => 0).catch(e => console.error(e)); } if (SettingsCapa('AutoLogout') || SettingsCapa('OpenPGP') || SettingsCapa('GnuPG')) { diff --git a/dev/Settings/User/Sieve.js b/dev/Settings/User/Sieve.js new file mode 100644 index 000000000..5c2724aaf --- /dev/null +++ b/dev/Settings/User/Sieve.js @@ -0,0 +1,73 @@ +import { getNotification } from 'Common/Translator'; + +import Remote from 'Remote/User/Fetch'; + +//export class UserSettingsFilters /*extends AbstractViewSettings*/ { +export class UserSettingsSieve /*extends AbstractViewSettings*/ { + constructor() { + const Sieve = window.Sieve; + this.scripts = Sieve.scripts; + this.loading = Sieve.loading; + this.serverError = Sieve.serverError; + this.serverErrorDesc = Sieve.serverErrorDesc; + this.scriptForDeletion = ko.observable(null).askDeleteHelper(); + } + + setError(text) { + this.serverError(true); + this.serverErrorDesc(text); + } + + updateList() { + window.Sieve.updateList(); + } + + addScript() { + window.Sieve.ScriptView.showModal(); + } + + editScript(script) { + window.Sieve.ScriptView.showModal([script]); + } + + deleteScript(script) { + this.serverError(false); + Remote.request('FiltersScriptDelete', + (iError, data) => { + if (iError) { + this.setError((data && data.ErrorMessageAdditional) || getNotification(iError)); + } else { + this.scripts.remove(script); + } + }, + {name:script.name()} + ); + } + + toggleScript(script) { + let name = script.active() ? '' : script.name(); + this.serverError(false); + Remote.request('FiltersScriptActivate', + (iError, data) => { + if (iError) { + this.setError((data && data.ErrorMessageAdditional) || iError) + } else { + this.scripts.forEach(script => script.active(script.name() === name)); + } + }, + {name:name} + ); + } + + onBuild(oDom) { + oDom.addEventListener('click', event => { + const el = event.target.closestWithin('.script-item .e-action', oDom), + script = el && ko.dataFor(el); + script && this.editScript(script); + }); + } + + onShow() { + this.updateList(); + } +} diff --git a/dev/sieve.js b/dev/sieve.js new file mode 100644 index 000000000..3a9ac47c4 --- /dev/null +++ b/dev/sieve.js @@ -0,0 +1,206 @@ +import { parseScript } from 'Sieve/Parser'; + +import { FilterModel } from 'Model/Filter'; +import { SieveScriptModel } from 'Model/SieveScript'; +import { FilterPopupView } from 'View/Popup/Filter'; + +//import { getNotification, i18nToNodes } from 'Common/Translator'; +import { forEachObjectValue } from 'Common/Utils'; +import { koArrayWithDestroy } from 'External/ko'; + +// SieveUserStore +const +/* + getNotificationMessage = code => { + let key = getKeyByValue(Notification, code); + return key ? I18N_DATA.NOTIFICATIONS[i18nKey(key).replace('_NOTIFICATION', '_ERROR')] : ''; + rl.i18n('NOTIFICATIONS/') + }, + getNotification = (code, message = '', defCode = 0) => { + code = parseInt(code, 10) || 0; + if (Notification.ClientViewError === code && message) { + return message; + } + + return getNotificationMessage(code) + || getNotificationMessage(parseInt(defCode, 10)) + || ''; + }, +*/ + getNotification = code => 'ERROR ' + code, + + Remote = rl.app.Remote, + + Sieve = { + // capabilities + capa: ko.observableArray(), + + // Sieve scripts SieveScriptModel + scripts: koArrayWithDestroy(), + + parseScript: parseScript, + + setError: text => { + Sieve.serverError(true); + Sieve.serverErrorDesc(text); + }, + updateList: () => { + if (!Sieve.loading()) { + Sieve.loading(true); + Sieve.serverError(false); + + Remote.request('Filters', (iError, data) => { + Sieve.loading(false); + Sieve.scripts([]); + + if (iError) { + Sieve.capa([]); + Sieve.setError(getNotification(iError)); + } else { + Sieve.capa(data.Result.Capa); + /* + Sieve.scripts( + data.Result.Scripts.map(aItem => SieveScriptModel.reviveFromJson(aItem)).filter(v => v) + ); + */ + forEachObjectValue(data.Result.Scripts, value => { + value = SieveScriptModel.reviveFromJson(value); + value && Sieve.scripts.push(value) + }); + } + }); + } + }, + + loading: ko.observable(false).extend({ debounce: 200 }), + serverError: ko.observable(false), + serverErrorDesc: ko.observable('') + }; + +Sieve.ScriptView = class SieveScriptPopupView extends rl.pluginPopupView { + constructor() { + super('SieveScript'); + + this.addObservables({ + saveError: false, + saveErrorText: '', + rawActive: false, + allowToggle: false, + script: null + }); + + this.sieveCapabilities = Sieve.capa.join(' '); + this.saving = false; + + this.filterForDeletion = ko.observable(null).askDeleteHelper(); + } + + saveScript() { + let self = this, + script = self.script(); + if (!self.saving/* && script.hasChanges()*/) { + if (!script.verify()) { + return; + } + + if (!script.exists() && Sieve.scripts.find(item => item.name() === script.name())) { + script.nameError(true); + return; + } + + self.saving = true; + self.saveError(false); + + if (self.allowToggle()) { + script.body(script.filtersToRaw()); + } + + Remote.request('FiltersScriptSave', + (iError, data) => { + self.saving = false; + + if (iError) { + self.saveError(true); + self.saveErrorText((data && data.ErrorMessageAdditional) || getNotification(iError)); + } else { + script.exists() || Sieve.scripts.push(script); + script.exists(true); + script.hasChanges(false); + } + }, + script.toJson() + ); + } + } + + deleteFilter(filter) { + this.script().filters.remove(filter); + } + + addFilter() { + /* this = SieveScriptModel */ + const filter = new FilterModel(); + filter.generateID(); + FilterPopupView.showModal([ + filter, + () => this.filters.push(filter) + ]); + } + + editFilter(filter) { + const clonedFilter = filter.cloneSelf(); + FilterPopupView.showModal([ + clonedFilter, + () => { + const script = this.script(), + filters = script.filters(), + index = filters.indexOf(filter); + if (-1 < index) { + filters[index] = clonedFilter; + script.filters(filters); + } + }, + true + ]); + } + + toggleFiltersRaw() { + let script = this.script(), notRaw = !this.rawActive(); + if (notRaw) { + script.body(script.filtersToRaw()); + script.hasChanges(script.hasChanges()); + } + this.rawActive(notRaw); + } + + onBuild(oDom) { + oDom.addEventListener('click', event => { + const el = event.target.closestWithin('td.e-action', oDom), + filter = el && ko.dataFor(el); + filter && this.editFilter(filter); + }); + } + + onShow(oScript) { + oScript = oScript || new SieveScriptModel(); + let raw = !oScript.allowFilters(); + this.script(oScript); + this.rawActive(raw); + this.allowToggle(!raw); + this.saveError(false); + +/* + // TODO: Sieve GUI + let tree = parseScript(oScript.body(), oScript.name()); + console.dir(tree); + console.log(tree.join('\r\n')); +*/ + } + + afterShow() { + // Sometimes not everything is translated, try again +// i18nToNodes(this.viewModelDom); + } +} + +window.Sieve = Sieve; diff --git a/tasks/js.js b/tasks/js.js index f1f565e87..0e94fddd8 100644 --- a/tasks/js.js +++ b/tasks/js.js @@ -133,6 +133,6 @@ exports.jsLint = jsLint; exports.js = gulp.series( jsClean, jsLint, - gulp.parallel(jsBoot, jsServiceWorker, jsOpenPGP, jsLibs, jsSieve, jsApp, jsAdmin), + gulp.parallel(jsBoot, jsServiceWorker, jsOpenPGP, jsLibs/*, jsSieve*/, jsApp, jsAdmin), jsMin );