mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
When login don't reload the whole browser. Just rebuilt screens
This commit is contained in:
parent
d3500e2921
commit
e52addf346
16 changed files with 74 additions and 57 deletions
|
|
@ -1,9 +1,6 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
|
|
||||||
import {
|
import { Settings, SettingsGet } from 'Common/Globals';
|
||||||
elementById,
|
|
||||||
Settings
|
|
||||||
} from 'Common/Globals';
|
|
||||||
|
|
||||||
import { logoutLink } from 'Common/Links';
|
import { logoutLink } from 'Common/Links';
|
||||||
import { i18nToNodes, initOnStartOrLangChange } from 'Common/Translator';
|
import { i18nToNodes, initOnStartOrLangChange } from 'Common/Translator';
|
||||||
|
|
@ -37,6 +34,12 @@ export class AbstractApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
refresh() {
|
||||||
|
// rl.adminArea() || !translatorReload(false, );
|
||||||
|
rl.adminArea() || LanguageStore.language(SettingsGet('Language'));
|
||||||
|
this.start();
|
||||||
|
}
|
||||||
|
|
||||||
bootstart() {
|
bootstart() {
|
||||||
const register = (key, ClassObject, templateID) => ko.components.register(key, {
|
const register = (key, ClassObject, templateID) => ko.components.register(key, {
|
||||||
template: { element: templateID || (key + 'Component') },
|
template: { element: templateID || (key + 'Component') },
|
||||||
|
|
@ -68,14 +71,7 @@ export class AbstractApp {
|
||||||
|
|
||||||
LanguageStore.populate();
|
LanguageStore.populate();
|
||||||
ThemeStore.populate();
|
ThemeStore.populate();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
this.start();
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
hideLoading() {
|
|
||||||
elementById('rl-content').hidden = false;
|
|
||||||
elementById('rl-loading').remove();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,7 @@ class AdminApp extends AbstractApp {
|
||||||
this.weakPassword = ko.observable(false);
|
this.weakPassword = ko.observable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootstart() {
|
start() {
|
||||||
super.bootstart();
|
|
||||||
if (!Settings.app('allowAdminPanel')) {
|
if (!Settings.app('allowAdminPanel')) {
|
||||||
rl.route.root();
|
rl.route.root();
|
||||||
setTimeout(() => location.href = '/', 1);
|
setTimeout(() => location.href = '/', 1);
|
||||||
|
|
@ -27,7 +26,6 @@ class AdminApp extends AbstractApp {
|
||||||
} else {
|
} else {
|
||||||
startScreens([LoginAdminScreen]);
|
startScreens([LoginAdminScreen]);
|
||||||
}
|
}
|
||||||
this.hideLoading();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import 'External/User/ko';
|
import 'External/User/ko';
|
||||||
|
|
||||||
import { isArray, arrayLength, pInt, pString } from 'Common/Utils';
|
import { isArray, arrayLength, pInt, pString, forEachObjectValue } from 'Common/Utils';
|
||||||
import { isPosNumeric, delegateRunOnDestroy, mailToHelper } from 'Common/UtilsUser';
|
import { isPosNumeric, delegateRunOnDestroy, mailToHelper } from 'Common/UtilsUser';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
|
@ -187,7 +187,7 @@ class AppUser extends AbstractApp {
|
||||||
const sTrashFolder = FolderUserStore.trashFolder(),
|
const sTrashFolder = FolderUserStore.trashFolder(),
|
||||||
sSpamFolder = FolderUserStore.spamFolder();
|
sSpamFolder = FolderUserStore.spamFolder();
|
||||||
|
|
||||||
Object.values(this.moveCache).forEach(item => {
|
forEachObjectValue(this.moveCache, item => {
|
||||||
const isSpam = sSpamFolder === item.To,
|
const isSpam = sSpamFolder === item.To,
|
||||||
isTrash = sTrashFolder === item.To,
|
isTrash = sTrashFolder === item.To,
|
||||||
isHam = !isSpam && sSpamFolder === item.From && getFolderInboxName() === item.To;
|
isHam = !isSpam && sSpamFolder === item.From && getFolderInboxName() === item.To;
|
||||||
|
|
@ -810,7 +810,9 @@ class AppUser extends AbstractApp {
|
||||||
return event.returnValue = "Are you sure you want to exit?";
|
return event.returnValue = "Are you sure you want to exit?";
|
||||||
}
|
}
|
||||||
}, {capture: true});
|
}, {capture: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
if (SettingsGet('Auth')) {
|
if (SettingsGet('Auth')) {
|
||||||
rl.setWindowTitle(i18n('GLOBAL/LOADING'));
|
rl.setWindowTitle(i18n('GLOBAL/LOADING'));
|
||||||
|
|
||||||
|
|
@ -830,7 +832,6 @@ class AppUser extends AbstractApp {
|
||||||
MailBoxUserScreen,
|
MailBoxUserScreen,
|
||||||
SettingsUserScreen
|
SettingsUserScreen
|
||||||
]);
|
]);
|
||||||
this.hideLoading();
|
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
const cF = FolderUserStore.currentFolderFullNameRaw(),
|
const cF = FolderUserStore.currentFolderFullNameRaw(),
|
||||||
|
|
@ -916,7 +917,6 @@ class AppUser extends AbstractApp {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
startScreens([LoginUserScreen]);
|
startScreens([LoginUserScreen]);
|
||||||
this.hideLoading();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ export const
|
||||||
* @param {boolean} admin
|
* @param {boolean} admin
|
||||||
* @param {string} language
|
* @param {string} language
|
||||||
*/
|
*/
|
||||||
reload = (admin, language) =>
|
translatorReload = (admin, language) =>
|
||||||
new Promise((resolve, reject) => {
|
new Promise((resolve, reject) => {
|
||||||
const script = createElement('script');
|
const script = createElement('script');
|
||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ export const
|
||||||
isFunction = v => typeof v === 'function',
|
isFunction = v => typeof v === 'function',
|
||||||
pString = value => null != value ? '' + value : '',
|
pString = value => null != value ? '' + value : '',
|
||||||
|
|
||||||
|
forEachObjectValue = (obj, fn) => Object.values(obj).forEach(fn),
|
||||||
|
|
||||||
pInt = (value, defaultValue = 0) => {
|
pInt = (value, defaultValue = 0) => {
|
||||||
value = parseInt(value, 10);
|
value = parseInt(value, 10);
|
||||||
return isNaN(value) || !isFinite(value) ? defaultValue : value;
|
return isNaN(value) || !isFinite(value) ? defaultValue : value;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { isArray, isFunction, addObservablesTo, addComputablesTo } from 'Common/Utils';
|
import { isArray, isFunction, addObservablesTo, addComputablesTo, forEachObjectValue } from 'Common/Utils';
|
||||||
|
|
||||||
function dispose(disposable) {
|
function dispose(disposable) {
|
||||||
if (disposable && isFunction(disposable.dispose)) {
|
if (disposable && isFunction(disposable.dispose)) {
|
||||||
|
|
@ -52,7 +52,7 @@ export class AbstractModel {
|
||||||
this.subscribables.forEach(dispose);
|
this.subscribables.forEach(dispose);
|
||||||
/** clear object entries */
|
/** clear object entries */
|
||||||
// Object.entries(this).forEach(([key, value]) => {
|
// Object.entries(this).forEach(([key, value]) => {
|
||||||
Object.values(this).forEach(value => {
|
forEachObjectValue(this, value => {
|
||||||
/** clear CollectionModel */
|
/** clear CollectionModel */
|
||||||
let arr = ko.isObservableArray(value) ? value() : value;
|
let arr = ko.isObservableArray(value) ? value() : value;
|
||||||
arr && arr.onDestroy && value.onDestroy();
|
arr && arr.onDestroy && value.onDestroy();
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,14 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
|
|
||||||
import { doc, $htmlCL } from 'Common/Globals';
|
import { doc, $htmlCL, elementById } from 'Common/Globals';
|
||||||
import { isFunction } from 'Common/Utils';
|
import { isFunction, forEachObjectValue } from 'Common/Utils';
|
||||||
|
|
||||||
let currentScreen = null,
|
let
|
||||||
|
SCREENS = {},
|
||||||
|
currentScreen = null,
|
||||||
defaultScreenName = '';
|
defaultScreenName = '';
|
||||||
|
|
||||||
const SCREENS = {},
|
const
|
||||||
autofocus = dom => {
|
autofocus = dom => {
|
||||||
const af = dom.querySelector('[autofocus]');
|
const af = dom.querySelector('[autofocus]');
|
||||||
af && af.focus();
|
af && af.focus();
|
||||||
|
|
@ -123,6 +125,15 @@ const SCREENS = {},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
hideScreen = (screenToHide, destroy) => {
|
||||||
|
screenToHide.onHide && screenToHide.onHide();
|
||||||
|
forEachViewModel(screenToHide, (vm, dom) => {
|
||||||
|
dom.hidden = true;
|
||||||
|
vm.onHide && vm.onHide();
|
||||||
|
destroy && vm.viewModelDom.remove();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} screenName
|
* @param {string} screenName
|
||||||
* @param {string} subPart
|
* @param {string} subPart
|
||||||
|
|
@ -167,12 +178,7 @@ const SCREENS = {},
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
// hide screen
|
// hide screen
|
||||||
if (currentScreen && !isSameScreen) {
|
if (currentScreen && !isSameScreen) {
|
||||||
currentScreen.onHide && currentScreen.onHide();
|
hideScreen(currentScreen);
|
||||||
|
|
||||||
forEachViewModel(currentScreen, (vm, dom) => {
|
|
||||||
dom.hidden = true;
|
|
||||||
vm.onHide && vm.onHide();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
// --
|
// --
|
||||||
|
|
||||||
|
|
@ -275,6 +281,12 @@ export const
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
startScreens = screensClasses => {
|
startScreens = screensClasses => {
|
||||||
|
hasher.clear();
|
||||||
|
forEachObjectValue(SCREENS, screen => hideScreen(screen, 1));
|
||||||
|
SCREENS = {};
|
||||||
|
currentScreen = null,
|
||||||
|
defaultScreenName = '';
|
||||||
|
|
||||||
screensClasses.forEach(CScreen => {
|
screensClasses.forEach(CScreen => {
|
||||||
if (CScreen) {
|
if (CScreen) {
|
||||||
const vmScreen = new CScreen(),
|
const vmScreen = new CScreen(),
|
||||||
|
|
@ -284,7 +296,7 @@ export const
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.values(SCREENS).forEach(vmScreen => vmScreen.onStart());
|
forEachObjectValue(SCREENS, vmScreen => vmScreen.onStart());
|
||||||
|
|
||||||
const cross = new Crossroads();
|
const cross = new Crossroads();
|
||||||
cross.addRoute(/^([a-zA-Z0-9-]*)\/?(.*)$/, screenOnRoute);
|
cross.addRoute(/^([a-zA-Z0-9-]*)\/?(.*)$/, screenOnRoute);
|
||||||
|
|
@ -294,6 +306,10 @@ export const
|
||||||
|
|
||||||
setTimeout(() => $htmlCL.remove('rl-started-trigger'), 100);
|
setTimeout(() => $htmlCL.remove('rl-started-trigger'), 100);
|
||||||
setTimeout(() => $htmlCL.add('rl-started-delay'), 200);
|
setTimeout(() => $htmlCL.add('rl-started-delay'), 200);
|
||||||
|
|
||||||
|
const c = elementById('rl-content'), l = elementById('rl-loading');
|
||||||
|
c && (c.hidden = false);
|
||||||
|
l && l.remove();
|
||||||
},
|
},
|
||||||
|
|
||||||
decorateKoCommands = (thisArg, commands) =>
|
decorateKoCommands = (thisArg, commands) =>
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ import {
|
||||||
|
|
||||||
import { Capa, SaveSettingsStep } from 'Common/Enums';
|
import { Capa, SaveSettingsStep } from 'Common/Enums';
|
||||||
import { Settings, SettingsGet } from 'Common/Globals';
|
import { Settings, SettingsGet } from 'Common/Globals';
|
||||||
import { reload as translatorReload, convertLangName } from 'Common/Translator';
|
import { translatorReload, convertLangName } from 'Common/Translator';
|
||||||
|
|
||||||
import { showScreenPopup } from 'Knoin/Knoin';
|
import { showScreenPopup } from 'Knoin/Knoin';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
|
|
||||||
import { getNotification } from 'Common/Translator';
|
import { getNotification } from 'Common/Translator';
|
||||||
import { addObservablesTo } from 'Common/Utils';
|
import { addObservablesTo, forEachObjectValue } from 'Common/Utils';
|
||||||
import { delegateRunOnDestroy } from 'Common/UtilsUser';
|
import { delegateRunOnDestroy } from 'Common/UtilsUser';
|
||||||
|
|
||||||
import { SieveUserStore } from 'Stores/User/Sieve';
|
import { SieveUserStore } from 'Stores/User/Sieve';
|
||||||
|
|
@ -50,7 +50,7 @@ export class FiltersUserSettings /*extends AbstractViewSettings*/ {
|
||||||
data.Result.Scripts.map(aItem => SieveScriptModel.reviveFromJson(aItem)).filter(v => v)
|
data.Result.Scripts.map(aItem => SieveScriptModel.reviveFromJson(aItem)).filter(v => v)
|
||||||
);
|
);
|
||||||
*/
|
*/
|
||||||
Object.values(data.Result.Scripts).forEach(value => {
|
forEachObjectValue(data.Result.Scripts, value => {
|
||||||
value = SieveScriptModel.reviveFromJson(value);
|
value = SieveScriptModel.reviveFromJson(value);
|
||||||
value && this.scripts.push(value)
|
value && this.scripts.push(value)
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { SaveSettingsStep } from 'Common/Enums';
|
||||||
import { EditorDefaultType, Layout } from 'Common/EnumsUser';
|
import { EditorDefaultType, Layout } from 'Common/EnumsUser';
|
||||||
import { Settings, SettingsGet } from 'Common/Globals';
|
import { Settings, SettingsGet } from 'Common/Globals';
|
||||||
import { isArray, settingsSaveHelperSimpleFunction, addObservablesTo, addSubscribablesTo, addComputablesTo } from 'Common/Utils';
|
import { isArray, settingsSaveHelperSimpleFunction, addObservablesTo, addSubscribablesTo, addComputablesTo } from 'Common/Utils';
|
||||||
import { i18n, trigger as translatorTrigger, reload as translatorReload, convertLangName } from 'Common/Translator';
|
import { i18n, trigger as translatorTrigger, translatorReload, convertLangName } from 'Common/Translator';
|
||||||
|
|
||||||
import { showScreenPopup } from 'Knoin/Knoin';
|
import { showScreenPopup } from 'Knoin/Knoin';
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,12 @@ class LoginAdminView extends AbstractViewCenter {
|
||||||
this.submitRequest(true);
|
this.submitRequest(true);
|
||||||
|
|
||||||
Remote.adminLogin(
|
Remote.adminLogin(
|
||||||
iError => {
|
(iError, oData) => {
|
||||||
if (iError) {
|
if (iError) {
|
||||||
this.submitRequest(false);
|
this.submitRequest(false);
|
||||||
this.submitError(getNotification(iError));
|
this.submitError(getNotification(iError));
|
||||||
} else {
|
} else {
|
||||||
rl.route.reload();
|
rl.setData(oData.Result);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
name,
|
name,
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import ko from 'ko';
|
||||||
import { Notification } from 'Common/Enums';
|
import { Notification } from 'Common/Enums';
|
||||||
import { ClientSideKeyName } from 'Common/EnumsUser';
|
import { ClientSideKeyName } from 'Common/EnumsUser';
|
||||||
import { Settings, SettingsGet } from 'Common/Globals';
|
import { Settings, SettingsGet } from 'Common/Globals';
|
||||||
import { getNotification, reload as translatorReload, convertLangName } from 'Common/Translator';
|
import { getNotification, translatorReload, convertLangName } from 'Common/Translator';
|
||||||
|
|
||||||
import { LanguageStore } from 'Stores/Language';
|
import { LanguageStore } from 'Stores/Language';
|
||||||
|
|
||||||
|
|
@ -116,7 +116,8 @@ class LoginUserView extends AbstractViewCenter {
|
||||||
Notification.UnknownNotification));
|
Notification.UnknownNotification));
|
||||||
this.submitErrorAddidional((oData && oData.ErrorMessageAdditional) || '');
|
this.submitErrorAddidional((oData && oData.ErrorMessageAdditional) || '');
|
||||||
} else {
|
} else {
|
||||||
rl.route.reload();
|
rl.setData(oData.Result);
|
||||||
|
// rl.route.reload();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
data
|
data
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,11 @@ win.rl = {
|
||||||
showError(e.message);
|
showError(e.message);
|
||||||
throw e;
|
throw e;
|
||||||
});
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setData: appData => {
|
||||||
|
RL_APP_DATA = appData;
|
||||||
|
rl.app.refresh();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -198,7 +198,7 @@ trait Admin
|
||||||
$sToken = $this->getAdminToken();
|
$sToken = $this->getAdminToken();
|
||||||
$this->setAdminAuthToken($sToken);
|
$this->setAdminAuthToken($sToken);
|
||||||
|
|
||||||
return $this->DefaultResponse(__FUNCTION__, $sToken ? true : false);
|
return $this->DefaultResponse(__FUNCTION__, $sToken ? $this->AppData(true) : false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function DoAdminLogout() : array
|
public function DoAdminLogout() : array
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ trait User
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->TrueResponse(__FUNCTION__);
|
return $this->DefaultResponse(__FUNCTION__, $this->AppData(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
27
vendors/routes/hasher.js
vendored
27
vendors/routes/hasher.js
vendored
|
|
@ -11,8 +11,6 @@
|
||||||
// Private
|
// Private
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
var _hash, _bindings = [];
|
|
||||||
|
|
||||||
const
|
const
|
||||||
_hashValRegexp = /#(.*)$/,
|
_hashValRegexp = /#(.*)$/,
|
||||||
_hashRegexp = /^#/,
|
_hashRegexp = /^#/,
|
||||||
|
|
@ -44,11 +42,12 @@
|
||||||
// we should store raw value
|
// we should store raw value
|
||||||
_registerChange(path);
|
_registerChange(path);
|
||||||
if (path === _hash) {
|
if (path === _hash) {
|
||||||
|
path = '#' + encodeURI(path)
|
||||||
// we check if path is still === _hash to avoid error in
|
// we check if path is still === _hash to avoid error in
|
||||||
// case of multiple consecutive redirects [issue #39]
|
// case of multiple consecutive redirects [issue #39]
|
||||||
replace
|
replace
|
||||||
? location.replace('#' + encodeURI(path))
|
? location.replace(path)
|
||||||
: (location.hash = '#' + encodeURI(path));
|
: (location.hash = path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -58,6 +57,10 @@
|
||||||
//--------------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------------
|
||||||
|
|
||||||
hasher = /** @lends hasher */ {
|
hasher = /** @lends hasher */ {
|
||||||
|
clear : () => {
|
||||||
|
_bindings = [];
|
||||||
|
hasher.active = true;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal dispatched when hash value changes.
|
* Signal dispatched when hash value changes.
|
||||||
|
|
@ -74,16 +77,7 @@
|
||||||
* <li>hasher won't dispatch CHANGE events by manually typing a new value or pressing the back/forward buttons before calling this method.</li>
|
* <li>hasher won't dispatch CHANGE events by manually typing a new value or pressing the back/forward buttons before calling this method.</li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
init : () => {
|
init : () => hasher.dispatch(_trimHash(_hash)),
|
||||||
hasher.init = ()=>0;
|
|
||||||
_hash = _getWindowHash();
|
|
||||||
|
|
||||||
//thought about branching/overloading hasher.init() to avoid checking multiple times but
|
|
||||||
//don't think worth doing it since it probably won't be called multiple times.
|
|
||||||
addEventListener('hashchange', _checkHistory);
|
|
||||||
|
|
||||||
hasher.dispatch(_trimHash(_hash));
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Hash value, generating a new history record.
|
* Set Hash value, generating a new history record.
|
||||||
|
|
@ -101,5 +95,10 @@
|
||||||
replaceHash : (...path) => _setHash(path, true)
|
replaceHash : (...path) => _setHash(path, true)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var _hash = _getWindowHash(),
|
||||||
|
_bindings = [];
|
||||||
|
|
||||||
|
addEventListener('hashchange', _checkHistory);
|
||||||
|
|
||||||
global.hasher = hasher;
|
global.hasher = hasher;
|
||||||
})(this);
|
})(this);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue