diff --git a/README.md b/README.md index 3512dacbd..2598653b5 100644 --- a/README.md +++ b/README.md @@ -113,23 +113,23 @@ RainLoop 1.14 vs SnappyMail |js/* |RainLoop |Snappy | |--------------- |--------: |--------: | -|admin.js |2.130.942 | 120.785 | -|app.js |4.184.455 | 529.074 | +|admin.js |2.130.942 | 119.180 | +|app.js |4.184.455 | 527.492 | |boot.js | 671.522 | 4.842 | |libs.js | 647.614 | 235.475 | |polyfills.js | 325.834 | 0 | |serviceworker.js | 0 | 285 | -|TOTAL |7.960.367 | 890.449 | +|TOTAL |7.960.367 | 887.274 | |js/min/* |RainLoop |Snappy |Rain gzip |gzip |brotli | |--------------- |--------: |--------: |--------: |--------: |--------: | -|admin.min.js | 252.147 | 62.863 | 73.657 | 18.009 | 15.992 | -|app.min.js | 511.202 | 259.534 |140.462 | 74.005 | 62.184 | +|admin.min.js | 252.147 | 61.128 | 73.657 | 17.416 | 15.445 | +|app.min.js | 511.202 | 256.673 |140.462 | 73.698 | 61.839 | |boot.min.js | 66.007 | 2.630 | 22.567 | 1.375 | 1.189 | |libs.min.js | 572.545 | 130.930 |176.720 | 47.397 | 42.116 | |polyfills.min.js | 32.452 | 0 | 11.312 | 0 | 0 | -|TOTAL |1.434.353 | 455.957 |424.718 |140.786 |121.481 | -|TOTAL (no admin) |1.182.206 | 393.094 |351.061 |122.777 |105.489 | +|TOTAL |1.434.353 | 451.361 |424.718 |139.886 |120.589 | +|TOTAL (no admin) |1.182.206 | 390.233 |351.061 |122.470 |105.144 | For a user its around 65% smaller and faster than traditional RainLoop. diff --git a/dev/App/Abstract.js b/dev/App/Abstract.js index 304ceffcb..3ae56927b 100644 --- a/dev/App/Abstract.js +++ b/dev/App/Abstract.js @@ -9,17 +9,17 @@ import { import { KeyState } from 'Common/Enums'; import { rootAdmin, rootUser } from 'Common/Links'; -import { initOnStartOrLangChange } from 'Common/Translator'; +import { i18nToNodes, initOnStartOrLangChange } from 'Common/Translator'; -import LanguageStore from 'Stores/Language'; +import { LanguageStore } from 'Stores/Language'; import { ThemeStore } from 'Stores/Theme'; -import SaveTriggerComponent from 'Component/SaveTrigger'; -import InputComponent from 'Component/Input'; -import SelectComponent from 'Component/Select'; -import TextAreaComponent from 'Component/TextArea'; -import CheckboxMaterialDesignComponent from 'Component/MaterialDesign/Checkbox'; -import CheckboxComponent from 'Component/Checkbox'; +import { SaveTriggerComponent } from 'Component/SaveTrigger'; +import { InputComponent } from 'Component/Input'; +import { SelectComponent } from 'Component/Select'; +import { TextAreaComponent } from 'Component/TextArea'; +import { CheckboxMaterialDesignComponent } from 'Component/MaterialDesign/Checkbox'; +import { CheckboxComponent } from 'Component/Checkbox'; export class AbstractApp { /** @@ -84,16 +84,39 @@ export class AbstractApp { bootstart() { const mobile = Settings.app('mobile'), - register = (key, obj) => ko.components.register(key, obj); + register = (key, ClassObject, templateID) => ko.components.register(key, { + template: { element: templateID || (key + 'Component') }, + viewModel: { + createViewModel: (params, componentInfo) => { + params = params || {}; + params.element = null; + + if (componentInfo && componentInfo.element) { + params.component = componentInfo; + params.element = componentInfo.element; + + i18nToNodes(componentInfo.element); + + if (undefined !== params.inline && ko.unwrap(params.inline)) { + params.element.style.display = 'inline-block'; + } + } + + return new ClassObject(params); + } + } + }); register('SaveTrigger', SaveTriggerComponent); register('Input', InputComponent); register('Select', SelectComponent); register('TextArea', TextAreaComponent); - register('CheckboxSimple', CheckboxComponent); - register('Checkbox', Settings.app('materialDesign') && !mobile - ? CheckboxMaterialDesignComponent - : CheckboxComponent); + register('CheckboxSimple', CheckboxComponent, 'CheckboxComponent'); + if (mobile || !Settings.app('materialDesign')) { + register('Checkbox', CheckboxComponent); + } else { + register('Checkbox', CheckboxMaterialDesignComponent, 'CheckboxMaterialDesignComponent'); + } initOnStartOrLangChange(); diff --git a/dev/Common/Plugins.js b/dev/Common/Plugins.js index cf2858d13..e49164fd4 100644 --- a/dev/Common/Plugins.js +++ b/dev/Common/Plugins.js @@ -9,11 +9,9 @@ const USER_VIEW_MODELS_HOOKS = [], * @param {Object=} parameters * @param {?number=} timeout */ -export function remoteRequest(callback, action, parameters, timeout) { - if (rl.app) { - rl.app.remote().defaultRequest(callback, 'Plugin' + action, parameters, timeout); - } -} +rl.pluginRemoteRequest = (callback, action, parameters, timeout) => { + rl.app && rl.app.remote().defaultRequest(callback, 'Plugin' + action, parameters, timeout); +}; /** * @param {Function} SettingsViewModelClass @@ -21,9 +19,9 @@ export function remoteRequest(callback, action, parameters, timeout) { * @param {string} template * @param {string} route */ -export function addSettingsViewModel(SettingsViewModelClass, template, labelName, route) { +rl.addSettingsViewModel = (SettingsViewModelClass, template, labelName, route) => { USER_VIEW_MODELS_HOOKS.push([SettingsViewModelClass, template, labelName, route]); -} +}; /** * @param {Function} SettingsViewModelClass @@ -31,9 +29,9 @@ export function addSettingsViewModel(SettingsViewModelClass, template, labelName * @param {string} template * @param {string} route */ -export function addSettingsViewModelForAdmin(SettingsViewModelClass, template, labelName, route) { +rl.addSettingsViewModelForAdmin = (SettingsViewModelClass, template, labelName, route) => { ADMIN_VIEW_MODELS_HOOKS.push([SettingsViewModelClass, template, labelName, route]); -} +}; /** * @param {boolean} admin @@ -49,8 +47,8 @@ export function runSettingsViewModelHooks(admin) { * @param {string} name * @returns {?} */ -export function settingsGet(pluginSection, name) { +rl.pluginSettingsGet = (pluginSection, name) => { let plugins = rl.settings.get('Plugins'); plugins = plugins && null != plugins[pluginSection] ? plugins[pluginSection] : null; return plugins ? (null == plugins[name] ? null : plugins[name]) : null; -} +}; diff --git a/dev/Component/Abstract.js b/dev/Component/Abstract.js index 42b3754c8..61640cae0 100644 --- a/dev/Component/Abstract.js +++ b/dev/Component/Abstract.js @@ -1,8 +1,5 @@ -import ko from 'ko'; -import { i18nToNodes } from 'Common/Translator'; - -class AbstractComponent { +export class AbstractComponent { disposable = []; dispose() { @@ -13,33 +10,3 @@ class AbstractComponent { }); } } - -/** - * @param {*} ClassObject - * @param {string} templateID = '' - * @returns {Object} - */ -const componentExportHelper = (ClassObject, templateID = '') => ({ - template: templateID ? { element: templateID } : '', - viewModel: { - createViewModel: (params, componentInfo) => { - params = params || {}; - params.element = null; - - if (componentInfo && componentInfo.element) { - params.component = componentInfo; - params.element = componentInfo.element; - - i18nToNodes(componentInfo.element); - - if (undefined !== params.inline && ko.unwrap(params.inline)) { - params.element.style.display = 'inline-block'; - } - } - - return new ClassObject(params); - } - } -}); - -export { AbstractComponent, componentExportHelper }; diff --git a/dev/Component/Checkbox.js b/dev/Component/Checkbox.js index a8c7f6fd6..9927babdc 100644 --- a/dev/Component/Checkbox.js +++ b/dev/Component/Checkbox.js @@ -1,6 +1,3 @@ -import { componentExportHelper } from 'Component/Abstract'; import { AbstractCheckbox } from 'Component/AbstractCheckbox'; -class CheckboxComponent extends AbstractCheckbox {} - -export default componentExportHelper(CheckboxComponent, 'CheckboxComponent'); +export class CheckboxComponent extends AbstractCheckbox {} diff --git a/dev/Component/Input.js b/dev/Component/Input.js index c9df0a461..ca0a450fa 100644 --- a/dev/Component/Input.js +++ b/dev/Component/Input.js @@ -1,6 +1,3 @@ -import { componentExportHelper } from 'Component/Abstract'; import { AbstractInput } from 'Component/AbstractInput'; -class InputComponent extends AbstractInput {} - -export default componentExportHelper(InputComponent, 'InputComponent'); +export class InputComponent extends AbstractInput {} diff --git a/dev/Component/MaterialDesign/Checkbox.js b/dev/Component/MaterialDesign/Checkbox.js index 2aefa32ad..547fb1b69 100644 --- a/dev/Component/MaterialDesign/Checkbox.js +++ b/dev/Component/MaterialDesign/Checkbox.js @@ -1,8 +1,7 @@ import ko from 'ko'; -import { componentExportHelper } from 'Component/Abstract'; import { AbstractCheckbox } from 'Component/AbstractCheckbox'; -class CheckboxMaterialDesignComponent extends AbstractCheckbox { +export class CheckboxMaterialDesignComponent extends AbstractCheckbox { /** * @param {Object} params */ @@ -40,5 +39,3 @@ class CheckboxMaterialDesignComponent extends AbstractCheckbox { } } } - -export default componentExportHelper(CheckboxMaterialDesignComponent, 'CheckboxMaterialDesignComponent'); diff --git a/dev/Component/SaveTrigger.js b/dev/Component/SaveTrigger.js index 220ea6548..166535547 100644 --- a/dev/Component/SaveTrigger.js +++ b/dev/Component/SaveTrigger.js @@ -1,7 +1,7 @@ import { SaveSettingsStep } from 'Common/Enums'; -import { AbstractComponent, componentExportHelper } from 'Component/Abstract'; +import { AbstractComponent } from 'Component/Abstract'; -class SaveTriggerComponent extends AbstractComponent { +export class SaveTriggerComponent extends AbstractComponent { /** * @param {Object} params */ @@ -36,5 +36,3 @@ class SaveTriggerComponent extends AbstractComponent { this.element.querySelector('.error').hidden = value !== SaveSettingsStep.FalseResult; } } - -export default componentExportHelper(SaveTriggerComponent, 'SaveTriggerComponent'); diff --git a/dev/Component/Script.js b/dev/Component/Script.js deleted file mode 100644 index 0f9b1fa92..000000000 --- a/dev/Component/Script.js +++ /dev/null @@ -1,31 +0,0 @@ -import { AbstractComponent, componentExportHelper } from 'Component/Abstract'; - -class ScriptComponent extends AbstractComponent { - /** - * @param {Object} params - */ - constructor(params) { - super(); - - if ( - params.component && - params.component.templateNodes && - params.element - ) { - let el = params.element, script = el.outerHTML; - script = script ? script.replace(/<\/b><\/x-script>/i, '') : ''; - - if (script) { - const koNodes = params.component.templateNodes[0]; - el.textContent = ''; - el.replaceWith( - Element.fromHTML(script).textContent = koNodes && koNodes.nodeValue ? koNodes.nodeValue : '' - ); - } else { - el.remove(); - } - } - } -} - -export default componentExportHelper(ScriptComponent, 'ScriptComponent'); diff --git a/dev/Component/Select.js b/dev/Component/Select.js index 37205869d..b7390f7ba 100644 --- a/dev/Component/Select.js +++ b/dev/Component/Select.js @@ -1,9 +1,8 @@ import { i18n } from 'Common/Translator'; import { defaultOptionsAfterRender } from 'Common/Utils'; -import { componentExportHelper } from 'Component/Abstract'; import { AbstractInput } from 'Component/AbstractInput'; -class SelectComponent extends AbstractInput { +export class SelectComponent extends AbstractInput { /** * @param {Object} params */ @@ -23,5 +22,3 @@ class SelectComponent extends AbstractInput { this.defaultOptionsAfterRender = defaultOptionsAfterRender; } } - -export default componentExportHelper(SelectComponent, 'SelectComponent'); diff --git a/dev/Component/TextArea.js b/dev/Component/TextArea.js index 97d05d6b4..bc2ad55a9 100644 --- a/dev/Component/TextArea.js +++ b/dev/Component/TextArea.js @@ -1,18 +1,13 @@ -import { componentExportHelper } from 'Component/Abstract'; import { AbstractInput } from 'Component/AbstractInput'; -const DEFAULT_ROWS = 5; - -class TextAreaComponent extends AbstractInput { +export class TextAreaComponent extends AbstractInput { /** * @param {Object} params */ constructor(params) { super(params); - this.rows = params.rows || DEFAULT_ROWS; + this.rows = params.rows || 5; this.spellcheck = !!params.spellcheck; } } - -export default componentExportHelper(TextAreaComponent, 'TextAreaComponent'); diff --git a/dev/Settings/Admin/General.js b/dev/Settings/Admin/General.js index fade40f7d..464530be0 100644 --- a/dev/Settings/Admin/General.js +++ b/dev/Settings/Admin/General.js @@ -15,7 +15,7 @@ import { showScreenPopup } from 'Knoin/Knoin'; import Remote from 'Remote/Admin/Fetch'; import { ThemeStore } from 'Stores/Theme'; -import LanguageStore from 'Stores/Language'; +import { LanguageStore } from 'Stores/Language'; import AppAdminStore from 'Stores/Admin/App'; import CapaAdminStore from 'Stores/Admin/Capa'; import LanguagesPopupView from 'View/Popup/Languages'; @@ -26,8 +26,12 @@ export class GeneralAdminSettings { constructor() { this.language = LanguageStore.language; this.languages = LanguageStore.languages; - this.languageAdmin = LanguageStore.languageAdmin; - this.languagesAdmin = LanguageStore.languagesAdmin; + + const aLanguagesAdmin = rl.settings.app('languagesAdmin'); + this.languagesAdmin = ko.observableArray(Array.isArray(aLanguagesAdmin) ? aLanguagesAdmin : []); + this.languageAdmin = ko + .observable(settingsGet('LanguageAdmin')) + .extend({ limitedList: this.languagesAdmin, reversible: true }); this.theme = ThemeStore.theme; this.themes = ThemeStore.themes; @@ -174,7 +178,7 @@ export class GeneralAdminSettings { showScreenPopup(LanguagesPopupView, [ this.languageAdmin, this.languagesAdmin(), - LanguageStore.userLanguageAdmin() + settingsGet('UserLanguageAdmin') ]); } } diff --git a/dev/Settings/User/General.js b/dev/Settings/User/General.js index f828eb311..4cc9088b7 100644 --- a/dev/Settings/User/General.js +++ b/dev/Settings/User/General.js @@ -12,7 +12,7 @@ import { i18n, trigger as translatorTrigger, reload as translatorReload, convert import { showScreenPopup } from 'Knoin/Knoin'; import AppStore from 'Stores/User/App'; -import LanguageStore from 'Stores/Language'; +import { LanguageStore } from 'Stores/Language'; import SettingsStore from 'Stores/User/Settings'; import IdentityStore from 'Stores/User/Identity'; import NotificationStore from 'Stores/User/Notification'; diff --git a/dev/Stores/Language.js b/dev/Stores/Language.js index a2d1139e0..ed7e96421 100644 --- a/dev/Stores/Language.js +++ b/dev/Stores/Language.js @@ -1,36 +1,17 @@ import ko from 'ko'; -class LanguageStore { - constructor() { - this.languages = ko.observableArray(); - this.languagesAdmin = ko.observableArray(); +export const LanguageStore = { + languages: ko.observableArray(), + userLanguage: ko.observable(''), - this.language = ko - .observable('') - .extend({ limitedList: this.languages, reversible: true }); - - this.languageAdmin = ko - .observable('') - .extend({ limitedList: this.languagesAdmin, reversible: true }); - - this.userLanguage = ko.observable(''); - this.userLanguageAdmin = ko.observable(''); - } - - populate() { + populate: function() { const Settings = rl.settings, - aLanguages = Settings.app('languages'), - aLanguagesAdmin = Settings.app('languagesAdmin'); - + aLanguages = Settings.app('languages'); this.languages(Array.isArray(aLanguages) ? aLanguages : []); - this.languagesAdmin(Array.isArray(aLanguagesAdmin) ? aLanguagesAdmin : []); - this.language(Settings.get('Language')); - this.languageAdmin(Settings.get('LanguageAdmin')); - this.userLanguage(Settings.get('UserLanguage')); - this.userLanguageAdmin(Settings.get('UserLanguageAdmin')); } } -export default new LanguageStore(); +LanguageStore.language = ko.observable('') + .extend({ limitedList: LanguageStore.languages, reversible: true }); diff --git a/dev/View/Popup/Languages.js b/dev/View/Popup/Languages.js index 2f42af61f..350b8e775 100644 --- a/dev/View/Popup/Languages.js +++ b/dev/View/Popup/Languages.js @@ -33,7 +33,7 @@ class LanguagesPopupView extends AbstractViewPopup { setLanguageSelection() { const currentLang = this.fLang ? ko.unwrap(this.fLang) : ''; - this.languages.forEach(item => item.selected(item.key === currentLang)); + this.languages().forEach(item => item.selected(item.key === currentLang)); } onBeforeShow() { @@ -51,10 +51,7 @@ class LanguagesPopupView extends AbstractViewPopup { } changeLanguage(lang) { - if (this.fLang) { - this.fLang(lang); - } - + this.fLang && this.fLang(lang); this.cancelCommand(); } } diff --git a/dev/View/User/Login.js b/dev/View/User/Login.js index 2ea37d9c0..e781dee1e 100644 --- a/dev/View/User/Login.js +++ b/dev/View/User/Login.js @@ -10,7 +10,7 @@ import { ClientSideKeyName } from 'Common/EnumsUser'; import { getNotification, getNotificationFromResponse, reload as translatorReload, convertLangName } from 'Common/Translator'; import AppStore from 'Stores/User/App'; -import LanguageStore from 'Stores/Language'; +import { LanguageStore } from 'Stores/Language'; import * as Local from 'Storage/Client'; diff --git a/dev/bootstrap.js b/dev/bootstrap.js index 87ec39f2f..479399823 100644 --- a/dev/bootstrap.js +++ b/dev/bootstrap.js @@ -1,6 +1,5 @@ import { doc, dropdownVisibility } from 'Common/Globals'; -import * as Enums from 'Common/Enums'; -import * as Plugins from 'Common/Plugins'; +import { StorageResultType } from 'Common/Enums'; import { i18n } from 'Common/Translator'; import { root } from 'Common/Links'; @@ -35,13 +34,9 @@ export default (App) => { rl.i18n = i18n; - rl.addSettingsViewModel = Plugins.addSettingsViewModel; - rl.addSettingsViewModelForAdmin = Plugins.addSettingsViewModelForAdmin; - - rl.pluginSettingsGet = Plugins.settingsGet; - rl.pluginRemoteRequest = Plugins.remoteRequest; - - rl.Enums = Enums; + rl.Enums = { + StorageResultType: StorageResultType + }; rl.Dropdowns = []; rl.Dropdowns.register = function(element) { this.push(element); };