mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-07-13 03:27:39 +03:00
Reduce JavaScript footprint
This commit is contained in:
parent
fea65b7ebf
commit
cc03546484
12 changed files with 811 additions and 942 deletions
|
|
@ -11,152 +11,129 @@ let FOLDERS_CACHE = {},
|
||||||
|
|
||||||
const REQUESTED_MESSAGE_CACHE = {};
|
const REQUESTED_MESSAGE_CACHE = {};
|
||||||
|
|
||||||
/**
|
export const
|
||||||
* @returns {void}
|
/**
|
||||||
*/
|
* @returns {void}
|
||||||
export function clear() {
|
*/
|
||||||
FOLDERS_CACHE = {};
|
clear = () => {
|
||||||
FOLDERS_NAME_CACHE = {};
|
FOLDERS_CACHE = {};
|
||||||
FOLDERS_HASH_CACHE = {};
|
FOLDERS_NAME_CACHE = {};
|
||||||
FOLDERS_UID_NEXT_CACHE = {};
|
FOLDERS_HASH_CACHE = {};
|
||||||
MESSAGE_FLAGS_CACHE = {};
|
FOLDERS_UID_NEXT_CACHE = {};
|
||||||
}
|
MESSAGE_FLAGS_CACHE = {};
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
* @param {string} uid
|
* @param {string} uid
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getMessageKey(folderFullNameRaw, uid) {
|
getMessageKey = (folderFullNameRaw, uid) => `${folderFullNameRaw}#${uid}`,
|
||||||
return `${folderFullNameRaw}#${uid}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folder
|
* @param {string} folder
|
||||||
* @param {string} uid
|
* @param {string} uid
|
||||||
*/
|
*/
|
||||||
export function addRequestedMessage(folder, uid) {
|
addRequestedMessage = (folder, uid) => REQUESTED_MESSAGE_CACHE[getMessageKey(folder, uid)] = true,
|
||||||
REQUESTED_MESSAGE_CACHE[getMessageKey(folder, uid)] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folder
|
* @param {string} folder
|
||||||
* @param {string} uid
|
* @param {string} uid
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
export function hasRequestedMessage(folder, uid) {
|
hasRequestedMessage = (folder, uid) => true === REQUESTED_MESSAGE_CACHE[getMessageKey(folder, uid)],
|
||||||
return true === REQUESTED_MESSAGE_CACHE[getMessageKey(folder, uid)];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
* @param {string} uid
|
* @param {string} uid
|
||||||
*/
|
*/
|
||||||
export function addNewMessageCache(folderFullNameRaw, uid) {
|
addNewMessageCache = (folderFullNameRaw, uid) => NEW_MESSAGE_CACHE[getMessageKey(folderFullNameRaw, uid)] = true,
|
||||||
NEW_MESSAGE_CACHE[getMessageKey(folderFullNameRaw, uid)] = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
* @param {string} uid
|
* @param {string} uid
|
||||||
*/
|
*/
|
||||||
export function hasNewMessageAndRemoveFromCache(folderFullNameRaw, uid) {
|
hasNewMessageAndRemoveFromCache = (folderFullNameRaw, uid) => {
|
||||||
if (NEW_MESSAGE_CACHE[getMessageKey(folderFullNameRaw, uid)]) {
|
if (NEW_MESSAGE_CACHE[getMessageKey(folderFullNameRaw, uid)]) {
|
||||||
NEW_MESSAGE_CACHE[getMessageKey(folderFullNameRaw, uid)] = null;
|
NEW_MESSAGE_CACHE[getMessageKey(folderFullNameRaw, uid)] = null;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
export function clearNewMessageCache() {
|
clearNewMessageCache = () => NEW_MESSAGE_CACHE = {},
|
||||||
NEW_MESSAGE_CACHE = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getFolderInboxName() {
|
getFolderInboxName = () => inboxFolderName,
|
||||||
return inboxFolderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function setFolderInboxName(name) {
|
setFolderInboxName = name => inboxFolderName = name,
|
||||||
inboxFolderName = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderHash
|
* @param {string} folderHash
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getFolderFullNameRaw(folderHash) {
|
getFolderFullNameRaw = folderHash =>
|
||||||
return folderHash && FOLDERS_NAME_CACHE[folderHash] ? FOLDERS_NAME_CACHE[folderHash] : '';
|
folderHash && FOLDERS_NAME_CACHE[folderHash] ? FOLDERS_NAME_CACHE[folderHash] : '',
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderHash
|
* @param {string} folderHash
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
* @param {?FolderModel} folder
|
* @param {?FolderModel} folder
|
||||||
*/
|
*/
|
||||||
export function setFolder(folderHash, folderFullNameRaw, folder) {
|
setFolder = (folderHash, folderFullNameRaw, folder) => {
|
||||||
FOLDERS_CACHE[folderFullNameRaw] = folder;
|
FOLDERS_CACHE[folderFullNameRaw] = folder;
|
||||||
FOLDERS_NAME_CACHE[folderHash] = folderFullNameRaw;
|
FOLDERS_NAME_CACHE[folderHash] = folderFullNameRaw;
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getFolderHash(folderFullNameRaw) {
|
getFolderHash = folderFullNameRaw =>
|
||||||
return folderFullNameRaw && FOLDERS_HASH_CACHE[folderFullNameRaw] ? FOLDERS_HASH_CACHE[folderFullNameRaw] : '';
|
folderFullNameRaw && FOLDERS_HASH_CACHE[folderFullNameRaw] ? FOLDERS_HASH_CACHE[folderFullNameRaw] : '',
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
* @param {string} folderHash
|
* @param {string} folderHash
|
||||||
*/
|
*/
|
||||||
export function setFolderHash(folderFullNameRaw, folderHash) {
|
setFolderHash = (folderFullNameRaw, folderHash) =>
|
||||||
if (folderFullNameRaw) {
|
folderFullNameRaw && (FOLDERS_HASH_CACHE[folderFullNameRaw] = folderHash),
|
||||||
FOLDERS_HASH_CACHE[folderFullNameRaw] = folderHash;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function getFolderUidNext(folderFullNameRaw) {
|
getFolderUidNext = folderFullNameRaw =>
|
||||||
return folderFullNameRaw && FOLDERS_UID_NEXT_CACHE[folderFullNameRaw]
|
folderFullNameRaw && FOLDERS_UID_NEXT_CACHE[folderFullNameRaw]
|
||||||
? FOLDERS_UID_NEXT_CACHE[folderFullNameRaw]
|
? FOLDERS_UID_NEXT_CACHE[folderFullNameRaw]
|
||||||
: '';
|
: '',
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
* @param {string} uidNext
|
* @param {string} uidNext
|
||||||
*/
|
*/
|
||||||
export function setFolderUidNext(folderFullNameRaw, uidNext) {
|
setFolderUidNext = (folderFullNameRaw, uidNext) =>
|
||||||
FOLDERS_UID_NEXT_CACHE[folderFullNameRaw] = uidNext;
|
FOLDERS_UID_NEXT_CACHE[folderFullNameRaw] = uidNext,
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
* @returns {?FolderModel}
|
* @returns {?FolderModel}
|
||||||
*/
|
*/
|
||||||
export function getFolderFromCacheList(folderFullNameRaw) {
|
getFolderFromCacheList = folderFullNameRaw =>
|
||||||
return folderFullNameRaw && FOLDERS_CACHE[folderFullNameRaw] ? FOLDERS_CACHE[folderFullNameRaw] : null;
|
folderFullNameRaw && FOLDERS_CACHE[folderFullNameRaw] ? FOLDERS_CACHE[folderFullNameRaw] : null,
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} folderFullNameRaw
|
* @param {string} folderFullNameRaw
|
||||||
*/
|
*/
|
||||||
export function removeFolderFromCacheList(folderFullNameRaw) {
|
removeFolderFromCacheList = folderFullNameRaw => delete FOLDERS_CACHE[folderFullNameRaw];
|
||||||
delete FOLDERS_CACHE[folderFullNameRaw];
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MessageFlagsCache
|
export class MessageFlagsCache
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,8 @@
|
||||||
*/
|
*/
|
||||||
export const FolderType = {
|
export const FolderType = {
|
||||||
Inbox: 10,
|
Inbox: 10,
|
||||||
SentItems: 11,
|
Sent: 11,
|
||||||
Draft: 12,
|
Drafts: 12,
|
||||||
Trash: 13,
|
Trash: 13,
|
||||||
Spam: 14,
|
Spam: 14,
|
||||||
Archive: 15,
|
Archive: 15,
|
||||||
|
|
|
||||||
|
|
@ -1,46 +1,33 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
import { Scope } from 'Common/Enums';
|
import { Scope } from 'Common/Enums';
|
||||||
|
|
||||||
export const doc = document;
|
let keyScopeFake = Scope.All;
|
||||||
|
|
||||||
export const $htmlCL = doc.documentElement.classList;
|
export const
|
||||||
|
|
||||||
export const elementById = id => doc.getElementById(id);
|
doc = document,
|
||||||
|
|
||||||
export const Settings = rl.settings;
|
$htmlCL = doc.documentElement.classList,
|
||||||
export const SettingsGet = rl.settings.get;
|
|
||||||
|
|
||||||
export const dropdownVisibility = ko.observable(false).extend({ rateLimit: 0 });
|
elementById = id => doc.getElementById(id),
|
||||||
|
|
||||||
export const moveAction = ko.observable(false);
|
Settings = rl.settings,
|
||||||
export const leftPanelDisabled = ko.observable(false);
|
SettingsGet = Settings.get,
|
||||||
|
|
||||||
export const createElement = (name, attr) => {
|
dropdownVisibility = ko.observable(false).extend({ rateLimit: 0 }),
|
||||||
let el = doc.createElement(name);
|
|
||||||
attr && Object.entries(attr).forEach(([k,v]) => el.setAttribute(k,v));
|
|
||||||
return el;
|
|
||||||
};
|
|
||||||
|
|
||||||
leftPanelDisabled.subscribe(value => {
|
moveAction = ko.observable(false),
|
||||||
value && moveAction() && moveAction(false);
|
leftPanelDisabled = ko.observable(false),
|
||||||
$htmlCL.toggle('rl-left-panel-disabled', value);
|
|
||||||
});
|
|
||||||
|
|
||||||
moveAction.subscribe(value => value && leftPanelDisabled() && leftPanelDisabled(false));
|
createElement = (name, attr) => {
|
||||||
|
let el = doc.createElement(name);
|
||||||
|
attr && Object.entries(attr).forEach(([k,v]) => el.setAttribute(k,v));
|
||||||
|
return el;
|
||||||
|
},
|
||||||
|
|
||||||
// keys
|
// keys
|
||||||
export const keyScopeReal = ko.observable(Scope.All);
|
keyScopeReal = ko.observable(Scope.All),
|
||||||
|
keyScope = value => {
|
||||||
export const keyScope = (()=>{
|
|
||||||
let keyScopeFake = Scope.All;
|
|
||||||
dropdownVisibility.subscribe(value => {
|
|
||||||
if (value) {
|
|
||||||
keyScope(Scope.Menu);
|
|
||||||
} else if (Scope.Menu === shortcuts.getScope()) {
|
|
||||||
keyScope(keyScopeFake);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return value => {
|
|
||||||
if (value) {
|
if (value) {
|
||||||
if (Scope.Menu !== value) {
|
if (Scope.Menu !== value) {
|
||||||
keyScopeFake = value;
|
keyScopeFake = value;
|
||||||
|
|
@ -54,4 +41,18 @@ export const keyScope = (()=>{
|
||||||
return keyScopeFake;
|
return keyScopeFake;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
|
||||||
|
dropdownVisibility.subscribe(value => {
|
||||||
|
if (value) {
|
||||||
|
keyScope(Scope.Menu);
|
||||||
|
} else if (Scope.Menu === shortcuts.getScope()) {
|
||||||
|
keyScope(keyScopeFake);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
leftPanelDisabled.subscribe(value => {
|
||||||
|
value && moveAction() && moveAction(false);
|
||||||
|
$htmlCL.toggle('rl-left-panel-disabled', value);
|
||||||
|
});
|
||||||
|
|
||||||
|
moveAction.subscribe(value => value && leftPanelDisabled() && leftPanelDisabled(false));
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ export function encodeHtml(text) {
|
||||||
return (text && text.toString ? text.toString() : ''+text).replace(htmlre, m => htmlmap[m]);
|
return (text && text.toString ? text.toString() : ''+text).replace(htmlre, m => htmlmap[m]);
|
||||||
}
|
}
|
||||||
|
|
||||||
class HtmlEditor {
|
export class HtmlEditor {
|
||||||
/**
|
/**
|
||||||
* @param {Object} element
|
* @param {Object} element
|
||||||
* @param {Function=} onBlur
|
* @param {Function=} onBlur
|
||||||
|
|
@ -206,5 +206,3 @@ class HtmlEditor {
|
||||||
this.setHtml('');
|
this.setHtml('');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { HtmlEditor, HtmlEditor as default };
|
|
||||||
|
|
|
||||||
|
|
@ -8,174 +8,140 @@ const
|
||||||
VERSION = Settings.app('version'),
|
VERSION = Settings.app('version'),
|
||||||
VERSION_PREFIX = Settings.app('webVersionPath') || 'snappymail/v/' + VERSION + '/';
|
VERSION_PREFIX = Settings.app('webVersionPath') || 'snappymail/v/' + VERSION + '/';
|
||||||
|
|
||||||
/**
|
export const
|
||||||
* @returns {string}
|
SUB_QUERY_PREFIX = '&q[]=',
|
||||||
*/
|
|
||||||
export const SUB_QUERY_PREFIX = '&q[]=';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string=} startupUrl
|
* @param {string=} startupUrl
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function root(startupUrl = '') {
|
root = (startupUrl = '') => HASH_PREFIX + pString(startupUrl),
|
||||||
return HASH_PREFIX + pString(startupUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function logoutLink() {
|
logoutLink = () => (rl.adminArea() && !Settings.app('adminHostUse'))
|
||||||
return (rl.adminArea() && !Settings.app('adminHostUse'))
|
|
||||||
? SERVER_PREFIX + (Settings.app('adminPath') || 'admin')
|
? SERVER_PREFIX + (Settings.app('adminPath') || 'admin')
|
||||||
: ROOT;
|
: ROOT,
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} type
|
* @param {string} type
|
||||||
* @param {string} hash
|
* @param {string} hash
|
||||||
* @param {string=} customSpecSuffix
|
* @param {string=} customSpecSuffix
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function serverRequestRaw(type, hash, customSpecSuffix) {
|
serverRequestRaw = (type, hash, customSpecSuffix) =>
|
||||||
return SERVER_PREFIX + '/Raw/' + SUB_QUERY_PREFIX + '/'
|
SERVER_PREFIX + '/Raw/' + SUB_QUERY_PREFIX + '/'
|
||||||
+ (null == customSpecSuffix ? '0' : customSpecSuffix) + '/'
|
+ (null == customSpecSuffix ? '0' : customSpecSuffix) + '/'
|
||||||
+ (type
|
+ (type
|
||||||
? type + '/' + (hash ? SUB_QUERY_PREFIX + '/' + hash : '')
|
? type + '/' + (hash ? SUB_QUERY_PREFIX + '/' + hash : '')
|
||||||
: '')
|
: ''),
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} download
|
* @param {string} download
|
||||||
* @param {string=} customSpecSuffix
|
* @param {string=} customSpecSuffix
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function attachmentDownload(download, customSpecSuffix) {
|
attachmentDownload = (download, customSpecSuffix) =>
|
||||||
return serverRequestRaw('Download', download, customSpecSuffix);
|
serverRequestRaw('Download', download, customSpecSuffix),
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} type
|
* @param {string} type
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function serverRequest(type) {
|
serverRequest = type => SERVER_PREFIX + '/' + type + '/' + SUB_QUERY_PREFIX + '/0/',
|
||||||
return SERVER_PREFIX + '/' + type + '/' + SUB_QUERY_PREFIX + '/0/';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} email
|
* @param {string} email
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function change(email) {
|
change = email => serverRequest('Change') + encodeURIComponent(email) + '/',
|
||||||
return serverRequest('Change') + encodeURIComponent(email) + '/';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} lang
|
* @param {string} lang
|
||||||
* @param {boolean} isAdmin
|
* @param {boolean} isAdmin
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function langLink(lang, isAdmin) {
|
langLink = (lang, isAdmin) =>
|
||||||
return SERVER_PREFIX + '/Lang/0/' + (isAdmin ? 'Admin' : 'App') + '/' + encodeURI(lang) + '/' + VERSION + '/';
|
SERVER_PREFIX + '/Lang/0/' + (isAdmin ? 'Admin' : 'App') + '/' + encodeURI(lang) + '/' + VERSION + '/',
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} path
|
* @param {string} path
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function staticLink(path) {
|
staticLink = path => VERSION_PREFIX + 'static/' + path,
|
||||||
return VERSION_PREFIX + 'static/' + path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function openPgpJs() {
|
openPgpJs = () => staticLink('js/min/openpgp.min.js'),
|
||||||
return staticLink('js/min/openpgp.min.js');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function openPgpWorkerJs() {
|
openPgpWorkerJs = () => staticLink('js/min/openpgp.worker.min.js'),
|
||||||
return staticLink('js/min/openpgp.worker.min.js');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} theme
|
* @param {string} theme
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function themePreviewLink(theme) {
|
themePreviewLink = theme => {
|
||||||
let prefix = VERSION_PREFIX;
|
let prefix = VERSION_PREFIX;
|
||||||
if ('@custom' === theme.substr(-7)) {
|
if ('@custom' === theme.substr(-7)) {
|
||||||
theme = theme.substr(0, theme.length - 7).trim();
|
theme = theme.substr(0, theme.length - 7).trim();
|
||||||
prefix = Settings.app('webPath') || '';
|
prefix = Settings.app('webPath') || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
return prefix + 'themes/' + encodeURI(theme) + '/images/preview.png';
|
return prefix + 'themes/' + encodeURI(theme) + '/images/preview.png';
|
||||||
}
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} inboxFolderName = 'INBOX'
|
* @param {string} inboxFolderName = 'INBOX'
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function mailbox(inboxFolderName = 'INBOX') {
|
mailbox = (inboxFolderName = 'INBOX') => HASH_PREFIX + 'mailbox/' + inboxFolderName,
|
||||||
return HASH_PREFIX + 'mailbox/' + inboxFolderName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string=} screenName = ''
|
* @param {string=} screenName = ''
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function settings(screenName = '') {
|
settings = (screenName = '') => HASH_PREFIX + 'settings' + (screenName ? '/' + screenName : ''),
|
||||||
return HASH_PREFIX + 'settings' + (screenName ? '/' + screenName : '');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {string} screenName
|
* @param {string=} screenName
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function admin(screenName) {
|
admin = screenName => HASH_PREFIX + (
|
||||||
let result = HASH_PREFIX;
|
'AdminDomains' == screenName ? 'domains'
|
||||||
switch (screenName) {
|
: 'AdminSecurity' == screenName ? 'security'
|
||||||
case 'AdminDomains':
|
: ''
|
||||||
result += 'domains';
|
),
|
||||||
break;
|
|
||||||
case 'AdminSecurity':
|
|
||||||
result += 'security';
|
|
||||||
break;
|
|
||||||
// no default
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
/**
|
||||||
}
|
* @param {string} folder
|
||||||
|
* @param {number=} page = 1
|
||||||
|
* @param {string=} search = ''
|
||||||
|
* @param {string=} threadUid = ''
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
mailBox = (folder, page = 1, search = '', threadUid = '') => {
|
||||||
|
page = pInt(page, 1);
|
||||||
|
search = pString(search);
|
||||||
|
|
||||||
/**
|
let result = HASH_PREFIX + 'mailbox/';
|
||||||
* @param {string} folder
|
|
||||||
* @param {number=} page = 1
|
|
||||||
* @param {string=} search = ''
|
|
||||||
* @param {string=} threadUid = ''
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function mailBox(folder, page = 1, search = '', threadUid = '') {
|
|
||||||
page = pInt(page, 1);
|
|
||||||
search = pString(search);
|
|
||||||
|
|
||||||
let result = HASH_PREFIX + 'mailbox/';
|
if (folder) {
|
||||||
|
const resultThreadUid = pInt(threadUid);
|
||||||
|
result += encodeURI(folder) + (0 < resultThreadUid ? '~' + resultThreadUid : '');
|
||||||
|
}
|
||||||
|
|
||||||
if (folder) {
|
if (1 < page) {
|
||||||
const resultThreadUid = pInt(threadUid);
|
result = result.replace(/\/+$/, '') + '/p' + page;
|
||||||
result += encodeURI(folder) + (0 < resultThreadUid ? '~' + resultThreadUid : '');
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (1 < page) {
|
if (search) {
|
||||||
result = result.replace(/\/+$/, '') + '/p' + page;
|
result = result.replace(/\/+$/, '') + '/' + encodeURI(search);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (search) {
|
|
||||||
result = result.replace(/\/+$/, '') + '/' + encodeURI(search);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -5,49 +5,28 @@ import { doc, createElement } from 'Common/Globals';
|
||||||
|
|
||||||
let I18N_DATA = {};
|
let I18N_DATA = {};
|
||||||
|
|
||||||
export const trigger = ko.observable(false);
|
const
|
||||||
|
i18nToNode = element => {
|
||||||
/**
|
const key = element.dataset.i18n;
|
||||||
* @param {string} key
|
if (key) {
|
||||||
* @param {Object=} valueList
|
if ('[' === key.substr(0, 1)) {
|
||||||
* @param {string=} defaulValue
|
switch (key.substr(0, 6)) {
|
||||||
* @returns {string}
|
case '[html]':
|
||||||
*/
|
element.innerHTML = i18n(key.substr(6));
|
||||||
export function i18n(key, valueList, defaulValue) {
|
break;
|
||||||
let path = key.split('/');
|
case '[place':
|
||||||
if (!I18N_DATA[path[0]] || !path[1]) {
|
element.placeholder = i18n(key.substr(13));
|
||||||
return defaulValue || key;
|
break;
|
||||||
}
|
case '[title':
|
||||||
let result = I18N_DATA[path[0]][path[1]] || defaulValue || key;
|
element.title = i18n(key.substr(7));
|
||||||
if (valueList) {
|
break;
|
||||||
Object.entries(valueList).forEach(([key, value]) => {
|
// no default
|
||||||
result = result.replace('%' + key + '%', value);
|
}
|
||||||
});
|
} else {
|
||||||
}
|
element.textContent = i18n(key);
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const i18nToNode = element => {
|
|
||||||
const key = element.dataset.i18n;
|
|
||||||
if (key) {
|
|
||||||
if ('[' === key.substr(0, 1)) {
|
|
||||||
switch (key.substr(0, 6)) {
|
|
||||||
case '[html]':
|
|
||||||
element.innerHTML = i18n(key.substr(6));
|
|
||||||
break;
|
|
||||||
case '[place':
|
|
||||||
element.placeholder = i18n(key.substr(13));
|
|
||||||
break;
|
|
||||||
case '[title':
|
|
||||||
element.title = i18n(key.substr(7));
|
|
||||||
break;
|
|
||||||
// no default
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
element.textContent = i18n(key);
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
|
||||||
|
|
||||||
init = () => {
|
init = () => {
|
||||||
if (rl.I18N) {
|
if (rl.I18N) {
|
||||||
|
|
@ -60,109 +39,129 @@ const i18nToNode = element => {
|
||||||
|
|
||||||
i18nKey = key => key.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase(),
|
i18nKey = key => key.replace(/([a-z])([A-Z])/g, '$1_$2').toUpperCase(),
|
||||||
|
|
||||||
getKeyByValue = (o, v) => Object.keys(o).find(key => o[key] === v);
|
getKeyByValue = (o, v) => Object.keys(o).find(key => o[key] === v),
|
||||||
|
|
||||||
|
getNotificationMessage = code => {
|
||||||
|
let key = getKeyByValue(Notification, code);
|
||||||
|
if (key) {
|
||||||
|
key = i18nKey(key).replace('_NOTIFICATION', '_ERROR');
|
||||||
|
return I18N_DATA.NOTIFICATIONS[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const
|
||||||
|
trigger = ko.observable(false),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} key
|
||||||
|
* @param {Object=} valueList
|
||||||
|
* @param {string=} defaulValue
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
i18n = (key, valueList, defaulValue) => {
|
||||||
|
let path = key.split('/');
|
||||||
|
if (!I18N_DATA[path[0]] || !path[1]) {
|
||||||
|
return defaulValue || key;
|
||||||
|
}
|
||||||
|
let result = I18N_DATA[path[0]][path[1]] || defaulValue || key;
|
||||||
|
if (valueList) {
|
||||||
|
Object.entries(valueList).forEach(([key, value]) => {
|
||||||
|
result = result.replace('%' + key + '%', value);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} elements
|
||||||
|
* @param {boolean=} animate = false
|
||||||
|
*/
|
||||||
|
i18nToNodes = element =>
|
||||||
|
setTimeout(() =>
|
||||||
|
element.querySelectorAll('[data-i18n]').forEach(item => i18nToNode(item))
|
||||||
|
, 1),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} startCallback
|
||||||
|
* @param {Function=} langCallback = null
|
||||||
|
*/
|
||||||
|
initOnStartOrLangChange = (startCallback, langCallback = null) => {
|
||||||
|
startCallback && startCallback();
|
||||||
|
startCallback && trigger.subscribe(startCallback);
|
||||||
|
langCallback && trigger.subscribe(langCallback);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {number} code
|
||||||
|
* @param {*=} message = ''
|
||||||
|
* @param {*=} defCode = null
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getNotification = (code, message = '', defCode = 0) => {
|
||||||
|
code = parseInt(code, 10) || 0;
|
||||||
|
if (Notification.ClientViewError === code && message) {
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getNotificationMessage(code)
|
||||||
|
|| getNotificationMessage(parseInt(defCode, 10))
|
||||||
|
|| '';
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {*} code
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
getUploadErrorDescByCode = code => {
|
||||||
|
let result = 'UNKNOWN';
|
||||||
|
code = parseInt(code, 10) || 0;
|
||||||
|
switch (code) {
|
||||||
|
case UploadErrorCode.FileIsTooBig:
|
||||||
|
case UploadErrorCode.FilePartiallyUploaded:
|
||||||
|
case UploadErrorCode.NoFileUploaded:
|
||||||
|
case UploadErrorCode.MissingTempFolder:
|
||||||
|
case UploadErrorCode.OnSavingFile:
|
||||||
|
case UploadErrorCode.FileType:
|
||||||
|
result = i18nKey(getKeyByValue(UploadErrorCode, code));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return i18n('UPLOAD/ERROR_' + result);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {boolean} admin
|
||||||
|
* @param {string} language
|
||||||
|
*/
|
||||||
|
reload = (admin, language) =>
|
||||||
|
new Promise((resolve, reject) => {
|
||||||
|
const script = createElement('script');
|
||||||
|
script.onload = () => {
|
||||||
|
// reload the data
|
||||||
|
if (init()) {
|
||||||
|
i18nToNodes(doc);
|
||||||
|
admin || rl.app.reloadTime();
|
||||||
|
trigger(!trigger());
|
||||||
|
}
|
||||||
|
script.remove();
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
script.onerror = () => reject(new Error('Language '+language+' failed'));
|
||||||
|
script.src = langLink(language, admin);
|
||||||
|
// script.async = true;
|
||||||
|
doc.head.append(script);
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} language
|
||||||
|
* @param {boolean=} isEng = false
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
convertLangName = (language, isEng = false) =>
|
||||||
|
i18n(
|
||||||
|
'LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/' + language,
|
||||||
|
null,
|
||||||
|
language
|
||||||
|
);
|
||||||
|
|
||||||
init();
|
init();
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Object} elements
|
|
||||||
* @param {boolean=} animate = false
|
|
||||||
*/
|
|
||||||
export function i18nToNodes(element) {
|
|
||||||
setTimeout(() =>
|
|
||||||
element.querySelectorAll('[data-i18n]').forEach(item => i18nToNode(item))
|
|
||||||
, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Function} startCallback
|
|
||||||
* @param {Function=} langCallback = null
|
|
||||||
*/
|
|
||||||
export function initOnStartOrLangChange(startCallback, langCallback = null) {
|
|
||||||
startCallback && startCallback();
|
|
||||||
startCallback && trigger.subscribe(startCallback);
|
|
||||||
langCallback && trigger.subscribe(langCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getNotificationMessage(code) {
|
|
||||||
let key = getKeyByValue(Notification, code);
|
|
||||||
if (key) {
|
|
||||||
key = i18nKey(key).replace('_NOTIFICATION', '_ERROR');
|
|
||||||
return I18N_DATA.NOTIFICATIONS[key];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} code
|
|
||||||
* @param {*=} message = ''
|
|
||||||
* @param {*=} defCode = null
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function getNotification(code, message = '', defCode = 0) {
|
|
||||||
code = parseInt(code, 10) || 0;
|
|
||||||
if (Notification.ClientViewError === code && message) {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
|
|
||||||
return getNotificationMessage(code)
|
|
||||||
|| getNotificationMessage(parseInt(defCode, 10))
|
|
||||||
|| '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {*} code
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function getUploadErrorDescByCode(code) {
|
|
||||||
let result = 'UNKNOWN';
|
|
||||||
code = parseInt(code, 10) || 0;
|
|
||||||
switch (code) {
|
|
||||||
case UploadErrorCode.FileIsTooBig:
|
|
||||||
case UploadErrorCode.FilePartiallyUploaded:
|
|
||||||
case UploadErrorCode.NoFileUploaded:
|
|
||||||
case UploadErrorCode.MissingTempFolder:
|
|
||||||
case UploadErrorCode.OnSavingFile:
|
|
||||||
case UploadErrorCode.FileType:
|
|
||||||
result = i18nKey(getKeyByValue(UploadErrorCode, code));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return i18n('UPLOAD/ERROR_' + result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {boolean} admin
|
|
||||||
* @param {string} language
|
|
||||||
*/
|
|
||||||
export function reload(admin, language) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const script = createElement('script');
|
|
||||||
script.onload = () => {
|
|
||||||
// reload the data
|
|
||||||
if (init()) {
|
|
||||||
i18nToNodes(doc);
|
|
||||||
admin || rl.app.reloadTime();
|
|
||||||
trigger(!trigger());
|
|
||||||
}
|
|
||||||
script.remove();
|
|
||||||
resolve();
|
|
||||||
};
|
|
||||||
script.onerror = () => reject(new Error('Language '+language+' failed'));
|
|
||||||
script.src = langLink(language, admin);
|
|
||||||
// script.async = true;
|
|
||||||
doc.head.append(script);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param {string} language
|
|
||||||
* @param {boolean=} isEng = false
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function convertLangName(language, isEng = false) {
|
|
||||||
return i18n(
|
|
||||||
'LANGS_NAMES' + (true === isEng ? '_EN' : '') + '/' + language,
|
|
||||||
null,
|
|
||||||
language
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,141 +1,96 @@
|
||||||
import { SaveSettingsStep } from 'Common/Enums';
|
import { SaveSettingsStep } from 'Common/Enums';
|
||||||
import { doc, elementById } from 'Common/Globals';
|
import { doc, elementById } from 'Common/Globals';
|
||||||
|
|
||||||
export const
|
|
||||||
isArray = Array.isArray,
|
|
||||||
arrayLength = array => isArray(array) && array.length,
|
|
||||||
isFunction = v => typeof v === 'function';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {*} value
|
|
||||||
* @param {number=} defaultValue = 0
|
|
||||||
* @returns {number}
|
|
||||||
*/
|
|
||||||
export function pInt(value, defaultValue = 0) {
|
|
||||||
value = parseInt(value, 10);
|
|
||||||
return isNaN(value) || !isFinite(value) ? defaultValue : value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {*} value
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export function pString(value) {
|
|
||||||
return null != value ? '' + value : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function inFocus() {
|
|
||||||
try {
|
|
||||||
return doc.activeElement && doc.activeElement.matches(
|
|
||||||
'input,textarea,[contenteditable]'
|
|
||||||
);
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} theme
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
export const convertThemeName = theme => {
|
|
||||||
if ('@custom' === theme.substr(-7)) {
|
|
||||||
theme = theme.substr(0, theme.length - 7).trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
return theme
|
|
||||||
.replace(/([A-Z])/g, ' $1')
|
|
||||||
.replace(/[^a-zA-Z0-9]+/g, ' ')
|
|
||||||
.trim();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {object} domOption
|
|
||||||
* @param {object} item
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
export function defaultOptionsAfterRender(domItem, item) {
|
|
||||||
if (item && undefined !== item.disabled && domItem) {
|
|
||||||
domItem.classList.toggle('disabled', domItem.disabled = item.disabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {object} koTrigger
|
|
||||||
* @param {mixed} context
|
|
||||||
* @returns {mixed}
|
|
||||||
*/
|
|
||||||
export function settingsSaveHelperSimpleFunction(koTrigger, context) {
|
|
||||||
return iError => {
|
|
||||||
koTrigger.call(context, iError ? SaveSettingsStep.FalseResult : SaveSettingsStep.TrueResult);
|
|
||||||
setTimeout(() => koTrigger.call(context, SaveSettingsStep.Idle), 1000);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
let __themeTimer = 0,
|
let __themeTimer = 0,
|
||||||
__themeJson = null;
|
__themeJson = null;
|
||||||
|
|
||||||
/**
|
export const
|
||||||
* @param {string} value
|
isArray = Array.isArray,
|
||||||
* @param {function=} themeTrigger = noop
|
arrayLength = array => isArray(array) && array.length,
|
||||||
* @returns {void}
|
isFunction = v => typeof v === 'function',
|
||||||
*/
|
pString = value => null != value ? '' + value : '',
|
||||||
export function changeTheme(value, themeTrigger = ()=>0) {
|
|
||||||
const themeStyle = elementById('app-theme-style'),
|
|
||||||
clearTimer = () => {
|
|
||||||
__themeTimer = setTimeout(() => themeTrigger(SaveSettingsStep.Idle), 1000);
|
|
||||||
__themeJson = null;
|
|
||||||
};
|
|
||||||
|
|
||||||
let url = themeStyle.dataset.href;
|
pInt = (value, defaultValue = 0) => {
|
||||||
|
value = parseInt(value, 10);
|
||||||
|
return isNaN(value) || !isFinite(value) ? defaultValue : value;
|
||||||
|
},
|
||||||
|
|
||||||
if (url) {
|
convertThemeName = theme => theme
|
||||||
url = url.toString()
|
.replace(/@custom$/, '')
|
||||||
.replace(/\/-\/[^/]+\/-\//, '/-/' + value + '/-/')
|
.replace(/([A-Z])/g, ' $1')
|
||||||
.replace(/\/Css\/[^/]+\/User\//, '/Css/0/User/')
|
.replace(/[^a-zA-Z0-9]+/g, ' ')
|
||||||
.replace(/\/Hash\/[^/]+\//, '/Hash/-/');
|
.trim(),
|
||||||
|
|
||||||
if ('Json/' !== url.substr(-5)) {
|
defaultOptionsAfterRender = (domItem, item) =>
|
||||||
url += 'Json/';
|
domItem && item && undefined !== item.disabled
|
||||||
|
&& domItem.classList.toggle('disabled', domItem.disabled = item.disabled),
|
||||||
|
|
||||||
|
addObservablesTo = (target, observables) =>
|
||||||
|
Object.entries(observables).forEach(([key, value]) =>
|
||||||
|
target[key] = /*isArray(value) ? ko.observableArray(value) :*/ ko.observable(value) ),
|
||||||
|
|
||||||
|
addComputablesTo = (target, computables) =>
|
||||||
|
Object.entries(computables).forEach(([key, fn]) => target[key] = ko.computed(fn)),
|
||||||
|
|
||||||
|
addSubscribablesTo = (target, subscribables) =>
|
||||||
|
Object.entries(subscribables).forEach(([key, fn]) => target[key].subscribe(fn)),
|
||||||
|
|
||||||
|
inFocus = () => {
|
||||||
|
try {
|
||||||
|
return doc.activeElement && doc.activeElement.matches(
|
||||||
|
'input,textarea,[contenteditable]'
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
clearTimeout(__themeTimer);
|
settingsSaveHelperSimpleFunction = (koTrigger, context) =>
|
||||||
|
iError => {
|
||||||
|
koTrigger.call(context, iError ? SaveSettingsStep.FalseResult : SaveSettingsStep.TrueResult);
|
||||||
|
setTimeout(() => koTrigger.call(context, SaveSettingsStep.Idle), 1000);
|
||||||
|
},
|
||||||
|
|
||||||
themeTrigger(SaveSettingsStep.Animate);
|
changeTheme = (value, themeTrigger = ()=>0) => {
|
||||||
|
const themeStyle = elementById('app-theme-style'),
|
||||||
|
clearTimer = () => {
|
||||||
|
__themeTimer = setTimeout(() => themeTrigger(SaveSettingsStep.Idle), 1000);
|
||||||
|
__themeJson = null;
|
||||||
|
};
|
||||||
|
|
||||||
if (__themeJson) {
|
let url = themeStyle.dataset.href;
|
||||||
__themeJson.abort();
|
|
||||||
|
if (url) {
|
||||||
|
url = url.toString()
|
||||||
|
.replace(/\/-\/[^/]+\/-\//, '/-/' + value + '/-/')
|
||||||
|
.replace(/\/Css\/[^/]+\/User\//, '/Css/0/User/')
|
||||||
|
.replace(/\/Hash\/[^/]+\//, '/Hash/-/');
|
||||||
|
|
||||||
|
if ('Json/' !== url.substr(-5)) {
|
||||||
|
url += 'Json/';
|
||||||
|
}
|
||||||
|
|
||||||
|
clearTimeout(__themeTimer);
|
||||||
|
|
||||||
|
themeTrigger(SaveSettingsStep.Animate);
|
||||||
|
|
||||||
|
if (__themeJson) {
|
||||||
|
__themeJson.abort();
|
||||||
|
}
|
||||||
|
let init = {};
|
||||||
|
if (window.AbortController) {
|
||||||
|
__themeJson = new AbortController();
|
||||||
|
init.signal = __themeJson.signal;
|
||||||
|
}
|
||||||
|
rl.fetchJSON(url, init)
|
||||||
|
.then(data => {
|
||||||
|
if (2 === arrayLength(data)) {
|
||||||
|
themeStyle.textContent = data[1];
|
||||||
|
themeStyle.dataset.href = url;
|
||||||
|
themeStyle.dataset.theme = data[0];
|
||||||
|
themeTrigger(SaveSettingsStep.TrueResult);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(clearTimer, clearTimer);
|
||||||
}
|
}
|
||||||
let init = {};
|
};
|
||||||
if (window.AbortController) {
|
|
||||||
__themeJson = new AbortController();
|
|
||||||
init.signal = __themeJson.signal;
|
|
||||||
}
|
|
||||||
rl.fetchJSON(url, init)
|
|
||||||
.then(data => {
|
|
||||||
if (2 === arrayLength(data)) {
|
|
||||||
themeStyle.textContent = data[1];
|
|
||||||
themeStyle.dataset.href = url;
|
|
||||||
themeStyle.dataset.theme = data[0];
|
|
||||||
themeTrigger(SaveSettingsStep.TrueResult);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(clearTimer, clearTimer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addObservablesTo(target, observables) {
|
|
||||||
Object.entries(observables).forEach(([key, value]) =>
|
|
||||||
target[key] = /*isArray(value) ? ko.observableArray(value) :*/ ko.observable(value) );
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addComputablesTo(target, computables) {
|
|
||||||
Object.entries(computables).forEach(([key, fn]) => target[key] = ko.computed(fn));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addSubscribablesTo(target, subscribables) {
|
|
||||||
Object.entries(subscribables).forEach(([key, fn]) => target[key].subscribe(fn));
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -10,321 +10,318 @@ const SCREENS = {},
|
||||||
autofocus = dom => {
|
autofocus = dom => {
|
||||||
const af = dom.querySelector('[autofocus]');
|
const af = dom.querySelector('[autofocus]');
|
||||||
af && af.focus();
|
af && af.focus();
|
||||||
};
|
},
|
||||||
|
|
||||||
export const popupVisibilityNames = ko.observableArray([]);
|
/**
|
||||||
|
* @param {string} screenName
|
||||||
|
* @returns {?Object}
|
||||||
|
*/
|
||||||
|
screen = screenName => screenName && null != SCREENS[screenName] ? SCREENS[screenName] : null,
|
||||||
|
|
||||||
export const ViewType = {
|
/**
|
||||||
Popup: 'Popups',
|
* @param {Function} ViewModelClass
|
||||||
Left: 'Left',
|
* @param {Object=} vmScreen
|
||||||
Right: 'Right',
|
* @returns {*}
|
||||||
Content: 'Content'
|
*/
|
||||||
};
|
buildViewModel = (ViewModelClass, vmScreen) => {
|
||||||
|
if (ViewModelClass && !ViewModelClass.__builded) {
|
||||||
|
let vmDom = null;
|
||||||
|
const vm = new ViewModelClass(vmScreen),
|
||||||
|
position = vm.viewModelPosition || '',
|
||||||
|
vmPlace = position ? doc.getElementById('rl-' + position.toLowerCase()) : null;
|
||||||
|
|
||||||
/**
|
ViewModelClass.__builded = true;
|
||||||
* @param {Function} fExecute
|
ViewModelClass.__vm = vm;
|
||||||
* @param {(Function|boolean|null)=} fCanExecute = true
|
|
||||||
* @returns {Function}
|
|
||||||
*/
|
|
||||||
export function createCommand(fExecute, fCanExecute = true) {
|
|
||||||
let fResult = fExecute
|
|
||||||
? (...args) => {
|
|
||||||
if (fResult && fResult.canExecute && fResult.canExecute()) {
|
|
||||||
fExecute.apply(null, args);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
} : ()=>0;
|
|
||||||
fResult.enabled = ko.observable(true);
|
|
||||||
fResult.isCommand = true;
|
|
||||||
|
|
||||||
if (isFunction(fCanExecute)) {
|
if (vmPlace) {
|
||||||
fResult.canExecute = ko.computed(() => fResult && fResult.enabled() && fCanExecute.call(null));
|
vmDom = Element.fromHTML('<div class="rl-view-model RL-' + vm.viewModelTemplateID + '" hidden=""></div>');
|
||||||
} else {
|
vmPlace.append(vmDom);
|
||||||
fResult.canExecute = ko.computed(() => fResult && fResult.enabled() && !!fCanExecute);
|
|
||||||
}
|
|
||||||
|
|
||||||
return fResult;
|
vm.viewModelDom = vmDom;
|
||||||
}
|
ViewModelClass.__dom = vmDom;
|
||||||
|
|
||||||
/**
|
if (ViewType.Popup === position) {
|
||||||
* @param {string} screenName
|
vm.cancelCommand = vm.closeCommand = createCommand(() => {
|
||||||
* @returns {?Object}
|
hideScreenPopup(ViewModelClass);
|
||||||
*/
|
});
|
||||||
function screen(screenName) {
|
|
||||||
return screenName && null != SCREENS[screenName] ? SCREENS[screenName] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// show/hide popup/modal
|
||||||
* @param {Function} ViewModelClassToHide
|
const endShowHide = e => {
|
||||||
* @returns {void}
|
if (e.target === vmDom) {
|
||||||
*/
|
if (vmDom.classList.contains('show')) {
|
||||||
export function hideScreenPopup(ViewModelClassToHide) {
|
autofocus(vmDom);
|
||||||
if (ViewModelClassToHide && ViewModelClassToHide.__vm && ViewModelClassToHide.__dom) {
|
vm.onShowWithDelay && vm.onShowWithDelay();
|
||||||
ViewModelClassToHide.__vm.modalVisibility(false);
|
} else {
|
||||||
}
|
vmDom.hidden = true;
|
||||||
}
|
vm.onHideWithDelay && vm.onHideWithDelay();
|
||||||
|
}
|
||||||
/**
|
|
||||||
* @param {Function} ViewModelClass
|
|
||||||
* @param {Object=} vmScreen
|
|
||||||
* @returns {*}
|
|
||||||
*/
|
|
||||||
function buildViewModel(ViewModelClass, vmScreen) {
|
|
||||||
if (ViewModelClass && !ViewModelClass.__builded) {
|
|
||||||
let vmDom = null;
|
|
||||||
const vm = new ViewModelClass(vmScreen),
|
|
||||||
position = vm.viewModelPosition || '',
|
|
||||||
vmPlace = position ? doc.getElementById('rl-' + position.toLowerCase()) : null;
|
|
||||||
|
|
||||||
ViewModelClass.__builded = true;
|
|
||||||
ViewModelClass.__vm = vm;
|
|
||||||
|
|
||||||
if (vmPlace) {
|
|
||||||
vmDom = Element.fromHTML('<div class="rl-view-model RL-' + vm.viewModelTemplateID + '" hidden=""></div>');
|
|
||||||
vmPlace.append(vmDom);
|
|
||||||
|
|
||||||
vm.viewModelDom = vmDom;
|
|
||||||
ViewModelClass.__dom = vmDom;
|
|
||||||
|
|
||||||
if (ViewType.Popup === position) {
|
|
||||||
vm.cancelCommand = vm.closeCommand = createCommand(() => {
|
|
||||||
hideScreenPopup(ViewModelClass);
|
|
||||||
});
|
|
||||||
|
|
||||||
// show/hide popup/modal
|
|
||||||
const endShowHide = e => {
|
|
||||||
if (e.target === vmDom) {
|
|
||||||
if (vmDom.classList.contains('show')) {
|
|
||||||
autofocus(vmDom);
|
|
||||||
vm.onShowWithDelay && vm.onShowWithDelay();
|
|
||||||
} else {
|
|
||||||
vmDom.hidden = true;
|
|
||||||
vm.onHideWithDelay && vm.onHideWithDelay();
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
};
|
|
||||||
|
|
||||||
vm.modalVisibility.subscribe(value => {
|
vm.modalVisibility.subscribe(value => {
|
||||||
if (value) {
|
if (value) {
|
||||||
vmDom.style.zIndex = 3000 + popupVisibilityNames().length + 10;
|
vmDom.style.zIndex = 3000 + popupVisibilityNames().length + 10;
|
||||||
vmDom.hidden = false;
|
vmDom.hidden = false;
|
||||||
vm.storeAndSetScope();
|
vm.storeAndSetScope();
|
||||||
popupVisibilityNames.push(vm.viewModelName);
|
popupVisibilityNames.push(vm.viewModelName);
|
||||||
requestAnimationFrame(() => { // wait just before the next paint
|
requestAnimationFrame(() => { // wait just before the next paint
|
||||||
vmDom.offsetHeight; // force a reflow
|
vmDom.offsetHeight; // force a reflow
|
||||||
vmDom.classList.add('show'); // trigger the transitions
|
vmDom.classList.add('show'); // trigger the transitions
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
vm.onHide && vm.onHide();
|
||||||
|
vmDom.classList.remove('show');
|
||||||
|
vm.restoreScope();
|
||||||
|
popupVisibilityNames(popupVisibilityNames.filter(v=>v!==vm.viewModelName));
|
||||||
|
}
|
||||||
|
vmDom.setAttribute('aria-hidden', !value);
|
||||||
|
});
|
||||||
|
if ('ontransitionend' in vmDom) {
|
||||||
|
vmDom.addEventListener('transitionend', endShowHide);
|
||||||
} else {
|
} else {
|
||||||
vm.onHide && vm.onHide();
|
// For Edge < 79 and mobile browsers
|
||||||
vmDom.classList.remove('show');
|
vm.modalVisibility.subscribe(() => ()=>setTimeout(endShowHide({target:vmDom}), 500));
|
||||||
vm.restoreScope();
|
|
||||||
popupVisibilityNames(popupVisibilityNames.filter(v=>v!==vm.viewModelName));
|
|
||||||
}
|
}
|
||||||
vmDom.setAttribute('aria-hidden', !value);
|
|
||||||
});
|
|
||||||
if ('ontransitionend' in vmDom) {
|
|
||||||
vmDom.addEventListener('transitionend', endShowHide);
|
|
||||||
} else {
|
|
||||||
// For Edge < 79 and mobile browsers
|
|
||||||
vm.modalVisibility.subscribe(() => ()=>setTimeout(endShowHide({target:vmDom}), 500));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ko.applyBindingAccessorsToNode(
|
ko.applyBindingAccessorsToNode(
|
||||||
vmDom,
|
vmDom,
|
||||||
{
|
{
|
||||||
i18nInit: true,
|
i18nInit: true,
|
||||||
template: () => ({ name: vm.viewModelTemplateID })
|
template: () => ({ name: vm.viewModelTemplateID })
|
||||||
},
|
},
|
||||||
vm
|
vm
|
||||||
);
|
|
||||||
|
|
||||||
vm.onBuild && vm.onBuild(vmDom);
|
|
||||||
if (vm && ViewType.Popup === position) {
|
|
||||||
vm.registerPopupKeyDown();
|
|
||||||
}
|
|
||||||
|
|
||||||
dispatchEvent(new CustomEvent('rl-view-model', {detail:vm}));
|
|
||||||
} else {
|
|
||||||
console.log('Cannot find view model position: ' + position);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ViewModelClass && ViewModelClass.__vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getScreenPopupViewModel(ViewModelClassToShow) {
|
|
||||||
return (buildViewModel(ViewModelClassToShow) && ViewModelClassToShow.__dom) && ViewModelClassToShow.__vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Function} ViewModelClassToShow
|
|
||||||
* @param {Array=} params
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
export function showScreenPopup(ViewModelClassToShow, params = []) {
|
|
||||||
const vm = getScreenPopupViewModel(ViewModelClassToShow);
|
|
||||||
if (vm) {
|
|
||||||
params = params || [];
|
|
||||||
|
|
||||||
vm.onBeforeShow && vm.onBeforeShow(...params);
|
|
||||||
|
|
||||||
vm.modalVisibility(true);
|
|
||||||
|
|
||||||
vm.onShow && vm.onShow(...params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Function} ViewModelClassToShow
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
export function isPopupVisible(ViewModelClassToShow) {
|
|
||||||
return ViewModelClassToShow && ViewModelClassToShow.__vm && ViewModelClassToShow.__vm.modalVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} screenName
|
|
||||||
* @param {string} subPart
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
function screenOnRoute(screenName, subPart) {
|
|
||||||
let vmScreen = null,
|
|
||||||
isSameScreen = false;
|
|
||||||
|
|
||||||
if (null == screenName || '' == screenName) {
|
|
||||||
screenName = defaultScreenName;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (screenName) {
|
|
||||||
vmScreen = screen(screenName);
|
|
||||||
if (!vmScreen) {
|
|
||||||
vmScreen = screen(defaultScreenName);
|
|
||||||
if (vmScreen) {
|
|
||||||
subPart = screenName + '/' + subPart;
|
|
||||||
screenName = defaultScreenName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vmScreen && vmScreen.__started) {
|
|
||||||
isSameScreen = currentScreen && vmScreen === currentScreen;
|
|
||||||
|
|
||||||
if (!vmScreen.__builded) {
|
|
||||||
vmScreen.__builded = true;
|
|
||||||
|
|
||||||
vmScreen.viewModels.forEach(ViewModelClass =>
|
|
||||||
buildViewModel(ViewModelClass, vmScreen)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
vmScreen.onBuild && vmScreen.onBuild();
|
vm.onBuild && vm.onBuild(vmDom);
|
||||||
}
|
if (vm && ViewType.Popup === position) {
|
||||||
|
vm.registerPopupKeyDown();
|
||||||
setTimeout(() => {
|
|
||||||
// hide screen
|
|
||||||
if (currentScreen && !isSameScreen) {
|
|
||||||
currentScreen.onHide && currentScreen.onHide();
|
|
||||||
currentScreen.onHideWithDelay && setTimeout(()=>currentScreen.onHideWithDelay(), 500);
|
|
||||||
|
|
||||||
if (arrayLength(currentScreen.viewModels)) {
|
|
||||||
currentScreen.viewModels.forEach(ViewModelClass => {
|
|
||||||
if (
|
|
||||||
ViewModelClass.__vm &&
|
|
||||||
ViewModelClass.__dom &&
|
|
||||||
ViewType.Popup !== ViewModelClass.__vm.viewModelPosition
|
|
||||||
) {
|
|
||||||
ViewModelClass.__dom.hidden = true;
|
|
||||||
ViewModelClass.__vm.viewModelVisible = false;
|
|
||||||
|
|
||||||
ViewModelClass.__vm.onHide && ViewModelClass.__vm.onHide();
|
|
||||||
ViewModelClass.__vm.onHideWithDelay && setTimeout(()=>ViewModelClass.__vm.onHideWithDelay(), 500);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// --
|
|
||||||
|
|
||||||
currentScreen = vmScreen;
|
dispatchEvent(new CustomEvent('rl-view-model', {detail:vm}));
|
||||||
|
} else {
|
||||||
// show screen
|
console.log('Cannot find view model position: ' + position);
|
||||||
if (currentScreen && !isSameScreen) {
|
|
||||||
currentScreen.onShow && currentScreen.onShow();
|
|
||||||
|
|
||||||
if (arrayLength(currentScreen.viewModels)) {
|
|
||||||
currentScreen.viewModels.forEach(ViewModelClass => {
|
|
||||||
if (
|
|
||||||
ViewModelClass.__vm &&
|
|
||||||
ViewModelClass.__dom &&
|
|
||||||
ViewType.Popup !== ViewModelClass.__vm.viewModelPosition
|
|
||||||
) {
|
|
||||||
ViewModelClass.__vm.onBeforeShow && ViewModelClass.__vm.onBeforeShow();
|
|
||||||
|
|
||||||
ViewModelClass.__dom.hidden = false;
|
|
||||||
ViewModelClass.__vm.viewModelVisible = true;
|
|
||||||
|
|
||||||
ViewModelClass.__vm.onShow && ViewModelClass.__vm.onShow();
|
|
||||||
|
|
||||||
autofocus(ViewModelClass.__dom);
|
|
||||||
|
|
||||||
ViewModelClass.__vm.onShowWithDelay && setTimeout(()=>ViewModelClass.__vm.onShowWithDelay, 200);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// --
|
|
||||||
|
|
||||||
vmScreen && vmScreen.__cross && vmScreen.__cross.parse(subPart);
|
|
||||||
}, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Array} screensClasses
|
|
||||||
* @returns {void}
|
|
||||||
*/
|
|
||||||
export function startScreens(screensClasses) {
|
|
||||||
screensClasses.forEach(CScreen => {
|
|
||||||
if (CScreen) {
|
|
||||||
const vmScreen = new CScreen(),
|
|
||||||
screenName = vmScreen && vmScreen.screenName();
|
|
||||||
|
|
||||||
if (screenName) {
|
|
||||||
defaultScreenName || (defaultScreenName = screenName);
|
|
||||||
|
|
||||||
SCREENS[screenName] = vmScreen;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
Object.values(SCREENS).forEach(vmScreen =>
|
return ViewModelClass && ViewModelClass.__vm;
|
||||||
vmScreen && vmScreen.onStart && vmScreen.onStart()
|
},
|
||||||
);
|
|
||||||
|
|
||||||
const cross = new Crossroads();
|
/**
|
||||||
cross.addRoute(/^([a-zA-Z0-9-]*)\/?(.*)$/, screenOnRoute);
|
* @param {string} screenName
|
||||||
|
* @param {string} subPart
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
screenOnRoute = (screenName, subPart) => {
|
||||||
|
let vmScreen = null,
|
||||||
|
isSameScreen = false;
|
||||||
|
|
||||||
hasher.add(cross.parse.bind(cross));
|
if (null == screenName || '' == screenName) {
|
||||||
hasher.init();
|
screenName = defaultScreenName;
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(() => $htmlCL.remove('rl-started-trigger'), 100);
|
if (screenName) {
|
||||||
setTimeout(() => $htmlCL.add('rl-started-delay'), 200);
|
vmScreen = screen(screenName);
|
||||||
}
|
if (!vmScreen) {
|
||||||
|
vmScreen = screen(defaultScreenName);
|
||||||
|
if (vmScreen) {
|
||||||
|
subPart = screenName + '/' + subPart;
|
||||||
|
screenName = defaultScreenName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function decorateKoCommands(thisArg, commands) {
|
if (vmScreen && vmScreen.__started) {
|
||||||
Object.entries(commands).forEach(([key, canExecute]) => {
|
isSameScreen = currentScreen && vmScreen === currentScreen;
|
||||||
let command = thisArg[key],
|
|
||||||
fn = (...args) => fn.enabled() && fn.canExecute() && command.apply(thisArg, args);
|
|
||||||
|
|
||||||
// fn.__realCanExecute = canExecute;
|
if (!vmScreen.__builded) {
|
||||||
// fn.isCommand = true;
|
vmScreen.__builded = true;
|
||||||
|
|
||||||
fn.enabled = ko.observable(true);
|
vmScreen.viewModels.forEach(ViewModelClass =>
|
||||||
|
buildViewModel(ViewModelClass, vmScreen)
|
||||||
|
);
|
||||||
|
|
||||||
fn.canExecute = (typeof canExecute === 'function')
|
vmScreen.onBuild && vmScreen.onBuild();
|
||||||
? ko.computed(() => fn.enabled() && canExecute.call(thisArg, thisArg))
|
}
|
||||||
: ko.computed(() => fn.enabled());
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// hide screen
|
||||||
|
if (currentScreen && !isSameScreen) {
|
||||||
|
currentScreen.onHide && currentScreen.onHide();
|
||||||
|
currentScreen.onHideWithDelay && setTimeout(()=>currentScreen.onHideWithDelay(), 500);
|
||||||
|
|
||||||
|
if (arrayLength(currentScreen.viewModels)) {
|
||||||
|
currentScreen.viewModels.forEach(ViewModelClass => {
|
||||||
|
if (
|
||||||
|
ViewModelClass.__vm &&
|
||||||
|
ViewModelClass.__dom &&
|
||||||
|
ViewType.Popup !== ViewModelClass.__vm.viewModelPosition
|
||||||
|
) {
|
||||||
|
ViewModelClass.__dom.hidden = true;
|
||||||
|
ViewModelClass.__vm.viewModelVisible = false;
|
||||||
|
|
||||||
|
ViewModelClass.__vm.onHide && ViewModelClass.__vm.onHide();
|
||||||
|
ViewModelClass.__vm.onHideWithDelay && setTimeout(()=>ViewModelClass.__vm.onHideWithDelay(), 500);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --
|
||||||
|
|
||||||
|
currentScreen = vmScreen;
|
||||||
|
|
||||||
|
// show screen
|
||||||
|
if (currentScreen && !isSameScreen) {
|
||||||
|
currentScreen.onShow && currentScreen.onShow();
|
||||||
|
|
||||||
|
if (arrayLength(currentScreen.viewModels)) {
|
||||||
|
currentScreen.viewModels.forEach(ViewModelClass => {
|
||||||
|
if (
|
||||||
|
ViewModelClass.__vm &&
|
||||||
|
ViewModelClass.__dom &&
|
||||||
|
ViewType.Popup !== ViewModelClass.__vm.viewModelPosition
|
||||||
|
) {
|
||||||
|
ViewModelClass.__vm.onBeforeShow && ViewModelClass.__vm.onBeforeShow();
|
||||||
|
|
||||||
|
ViewModelClass.__dom.hidden = false;
|
||||||
|
ViewModelClass.__vm.viewModelVisible = true;
|
||||||
|
|
||||||
|
ViewModelClass.__vm.onShow && ViewModelClass.__vm.onShow();
|
||||||
|
|
||||||
|
autofocus(ViewModelClass.__dom);
|
||||||
|
|
||||||
|
ViewModelClass.__vm.onShowWithDelay && setTimeout(()=>ViewModelClass.__vm.onShowWithDelay, 200);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// --
|
||||||
|
|
||||||
|
vmScreen && vmScreen.__cross && vmScreen.__cross.parse(subPart);
|
||||||
|
}, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const
|
||||||
|
popupVisibilityNames = ko.observableArray([]),
|
||||||
|
|
||||||
|
ViewType = {
|
||||||
|
Popup: 'Popups',
|
||||||
|
Left: 'Left',
|
||||||
|
Right: 'Right',
|
||||||
|
Content: 'Content'
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} fExecute
|
||||||
|
* @param {(Function|boolean|null)=} fCanExecute = true
|
||||||
|
* @returns {Function}
|
||||||
|
*/
|
||||||
|
createCommand = (fExecute, fCanExecute = true) => {
|
||||||
|
let fResult = fExecute
|
||||||
|
? (...args) => {
|
||||||
|
if (fResult && fResult.canExecute && fResult.canExecute()) {
|
||||||
|
fExecute.apply(null, args);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} : ()=>0;
|
||||||
|
fResult.enabled = ko.observable(true);
|
||||||
|
fResult.isCommand = true;
|
||||||
|
|
||||||
|
if (isFunction(fCanExecute)) {
|
||||||
|
fResult.canExecute = ko.computed(() => fResult && fResult.enabled() && fCanExecute.call(null));
|
||||||
|
} else {
|
||||||
|
fResult.canExecute = ko.computed(() => fResult && fResult.enabled() && !!fCanExecute);
|
||||||
|
}
|
||||||
|
|
||||||
|
return fResult;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} ViewModelClassToHide
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
hideScreenPopup = ViewModelClassToHide => {
|
||||||
|
if (ViewModelClassToHide && ViewModelClassToHide.__vm && ViewModelClassToHide.__dom) {
|
||||||
|
ViewModelClassToHide.__vm.modalVisibility(false);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getScreenPopupViewModel = ViewModelClassToShow =>
|
||||||
|
(buildViewModel(ViewModelClassToShow) && ViewModelClassToShow.__dom) && ViewModelClassToShow.__vm,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} ViewModelClassToShow
|
||||||
|
* @param {Array=} params
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
showScreenPopup = (ViewModelClassToShow, params = []) => {
|
||||||
|
const vm = getScreenPopupViewModel(ViewModelClassToShow);
|
||||||
|
if (vm) {
|
||||||
|
params = params || [];
|
||||||
|
|
||||||
|
vm.onBeforeShow && vm.onBeforeShow(...params);
|
||||||
|
|
||||||
|
vm.modalVisibility(true);
|
||||||
|
|
||||||
|
vm.onShow && vm.onShow(...params);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Function} ViewModelClassToShow
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
isPopupVisible = ViewModelClassToShow =>
|
||||||
|
ViewModelClassToShow && ViewModelClassToShow.__vm && ViewModelClassToShow.__vm.modalVisibility(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array} screensClasses
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
startScreens = screensClasses => {
|
||||||
|
screensClasses.forEach(CScreen => {
|
||||||
|
if (CScreen) {
|
||||||
|
const vmScreen = new CScreen(),
|
||||||
|
screenName = vmScreen && vmScreen.screenName();
|
||||||
|
|
||||||
|
if (screenName) {
|
||||||
|
defaultScreenName || (defaultScreenName = screenName);
|
||||||
|
|
||||||
|
SCREENS[screenName] = vmScreen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.values(SCREENS).forEach(vmScreen =>
|
||||||
|
vmScreen && vmScreen.onStart && vmScreen.onStart()
|
||||||
|
);
|
||||||
|
|
||||||
|
const cross = new Crossroads();
|
||||||
|
cross.addRoute(/^([a-zA-Z0-9-]*)\/?(.*)$/, screenOnRoute);
|
||||||
|
|
||||||
|
hasher.add(cross.parse.bind(cross));
|
||||||
|
hasher.init();
|
||||||
|
|
||||||
|
setTimeout(() => $htmlCL.remove('rl-started-trigger'), 100);
|
||||||
|
setTimeout(() => $htmlCL.add('rl-started-delay'), 200);
|
||||||
|
},
|
||||||
|
|
||||||
|
decorateKoCommands = (thisArg, commands) =>
|
||||||
|
Object.entries(commands).forEach(([key, canExecute]) => {
|
||||||
|
let command = thisArg[key],
|
||||||
|
fn = (...args) => fn.enabled() && fn.canExecute() && command.apply(thisArg, args);
|
||||||
|
|
||||||
|
// fn.__realCanExecute = canExecute;
|
||||||
|
// fn.isCommand = true;
|
||||||
|
|
||||||
|
fn.enabled = ko.observable(true);
|
||||||
|
|
||||||
|
fn.canExecute = (typeof canExecute === 'function')
|
||||||
|
? ko.computed(() => fn.enabled() && canExecute.call(thisArg, thisArg))
|
||||||
|
: ko.computed(() => fn.enabled());
|
||||||
|
|
||||||
|
thisArg[key] = fn;
|
||||||
|
});
|
||||||
|
|
||||||
thisArg[key] = fn;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
ko.decorateCommands = decorateKoCommands;
|
ko.decorateCommands = decorateKoCommands;
|
||||||
|
|
|
||||||
|
|
@ -160,9 +160,9 @@ function getSystemFolderName(type, def)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case FolderType.Inbox:
|
case FolderType.Inbox:
|
||||||
return i18n('FOLDER_LIST/INBOX_NAME');
|
return i18n('FOLDER_LIST/INBOX_NAME');
|
||||||
case FolderType.SentItems:
|
case FolderType.Sent:
|
||||||
return i18n('FOLDER_LIST/SENT_NAME');
|
return i18n('FOLDER_LIST/SENT_NAME');
|
||||||
case FolderType.Draft:
|
case FolderType.Drafts:
|
||||||
return i18n('FOLDER_LIST/DRAFTS_NAME');
|
return i18n('FOLDER_LIST/DRAFTS_NAME');
|
||||||
case FolderType.Spam:
|
case FolderType.Spam:
|
||||||
return i18n('GLOBAL/SPAM');
|
return i18n('GLOBAL/SPAM');
|
||||||
|
|
@ -281,14 +281,14 @@ export class FolderModel extends AbstractModel {
|
||||||
type = folder.type();
|
type = folder.type();
|
||||||
|
|
||||||
if (count) {
|
if (count) {
|
||||||
if (FolderType.Draft === type) {
|
if (FolderType.Drafts === type) {
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
unread &&
|
unread &&
|
||||||
FolderType.Trash !== type &&
|
FolderType.Trash !== type &&
|
||||||
FolderType.Archive !== type &&
|
FolderType.Archive !== type &&
|
||||||
FolderType.SentItems !== type
|
FolderType.Sent !== type
|
||||||
) {
|
) {
|
||||||
return unread;
|
return unread;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,8 +127,8 @@ export const FolderUserStore = new class {
|
||||||
this.archiveFolder.subscribe(fRemoveSystemFolderType(this.archiveFolder), this, 'beforeChange');
|
this.archiveFolder.subscribe(fRemoveSystemFolderType(this.archiveFolder), this, 'beforeChange');
|
||||||
|
|
||||||
addSubscribablesTo(this, {
|
addSubscribablesTo(this, {
|
||||||
sentFolder: fSetSystemFolderType(FolderType.SentItems),
|
sentFolder: fSetSystemFolderType(FolderType.Sent),
|
||||||
draftFolder: fSetSystemFolderType(FolderType.Draft),
|
draftFolder: fSetSystemFolderType(FolderType.Drafts),
|
||||||
spamFolder: fSetSystemFolderType(FolderType.Spam),
|
spamFolder: fSetSystemFolderType(FolderType.Spam),
|
||||||
trashFolder: fSetSystemFolderType(FolderType.Trash),
|
trashFolder: fSetSystemFolderType(FolderType.Trash),
|
||||||
archiveFolder: fSetSystemFolderType(FolderType.Archive)
|
archiveFolder: fSetSystemFolderType(FolderType.Archive)
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,11 @@ class DomainPopupView extends AbstractViewPopup {
|
||||||
constructor() {
|
constructor() {
|
||||||
super('Domain');
|
super('Domain');
|
||||||
|
|
||||||
|
this.addObservables(this.getDefaults());
|
||||||
this.addObservables({
|
this.addObservables({
|
||||||
edit: false,
|
edit: false,
|
||||||
|
|
||||||
saving: false,
|
saving: false,
|
||||||
savingError: '',
|
|
||||||
page: 'main',
|
|
||||||
sieveSettings: false,
|
|
||||||
|
|
||||||
testing: false,
|
testing: false,
|
||||||
testingDone: false,
|
testingDone: false,
|
||||||
|
|
@ -31,28 +30,6 @@ class DomainPopupView extends AbstractViewPopup {
|
||||||
imapServerFocus: false,
|
imapServerFocus: false,
|
||||||
sieveServerFocus: false,
|
sieveServerFocus: false,
|
||||||
smtpServerFocus: false,
|
smtpServerFocus: false,
|
||||||
|
|
||||||
name: '',
|
|
||||||
|
|
||||||
imapServer: '',
|
|
||||||
imapPort: '143',
|
|
||||||
imapSecure: 0,
|
|
||||||
imapShortLogin: false,
|
|
||||||
useSieve: false,
|
|
||||||
sieveServer: '',
|
|
||||||
sievePort: '4190',
|
|
||||||
sieveSecure: 0,
|
|
||||||
smtpServer: '',
|
|
||||||
smtpPort: '25',
|
|
||||||
smtpSecure: 0,
|
|
||||||
smtpShortLogin: false,
|
|
||||||
smtpAuth: true,
|
|
||||||
smtpSetSender: false,
|
|
||||||
smtpPhpMail: false,
|
|
||||||
whiteList: '',
|
|
||||||
aliasName: '',
|
|
||||||
|
|
||||||
enableSmartPorts: false
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.addComputables({
|
this.addComputables({
|
||||||
|
|
@ -306,38 +283,42 @@ class DomainPopupView extends AbstractViewPopup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDefaults() {
|
||||||
|
return {
|
||||||
|
savingError: '',
|
||||||
|
page: 'main',
|
||||||
|
sieveSettings: false,
|
||||||
|
|
||||||
|
name: '',
|
||||||
|
|
||||||
|
imapServer: '',
|
||||||
|
imapPort: '143',
|
||||||
|
imapSecure: 0,
|
||||||
|
imapShortLogin: false,
|
||||||
|
|
||||||
|
useSieve: false,
|
||||||
|
sieveServer: '',
|
||||||
|
sievePort: '4190',
|
||||||
|
sieveSecure: 0,
|
||||||
|
|
||||||
|
smtpServer: '',
|
||||||
|
smtpPort: '25',
|
||||||
|
smtpSecure: 0,
|
||||||
|
smtpShortLogin: false,
|
||||||
|
smtpAuth: true,
|
||||||
|
smtpSetSender: false,
|
||||||
|
smtpPhpMail: false,
|
||||||
|
|
||||||
|
whiteList: '',
|
||||||
|
aliasName: '',
|
||||||
|
|
||||||
|
enableSmartPorts: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
clearForm() {
|
clearForm() {
|
||||||
this.edit(false);
|
this.edit(false);
|
||||||
|
Object.entries(this.getDefaults()).forEach(([key, value]) => this[key](value));
|
||||||
this.page('main');
|
|
||||||
this.sieveSettings(false);
|
|
||||||
|
|
||||||
this.enableSmartPorts(false);
|
|
||||||
|
|
||||||
this.savingError('');
|
|
||||||
|
|
||||||
this.name('');
|
|
||||||
|
|
||||||
this.imapServer('');
|
|
||||||
this.imapPort('143');
|
|
||||||
this.imapSecure(0);
|
|
||||||
this.imapShortLogin(false);
|
|
||||||
|
|
||||||
this.useSieve(false);
|
|
||||||
this.sieveServer('');
|
|
||||||
this.sievePort('4190');
|
|
||||||
this.sieveSecure(0);
|
|
||||||
|
|
||||||
this.smtpServer('');
|
|
||||||
this.smtpPort('25');
|
|
||||||
this.smtpSecure(0);
|
|
||||||
this.smtpShortLogin(false);
|
|
||||||
this.smtpAuth(true);
|
|
||||||
this.smtpSetSender(true);
|
|
||||||
this.smtpPhpMail(false);
|
|
||||||
|
|
||||||
this.whiteList('');
|
|
||||||
this.aliasName('');
|
|
||||||
this.enableSmartPorts(true);
|
this.enableSmartPorts(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
9
dev/bootstrap.js
vendored
9
dev/bootstrap.js
vendored
|
|
@ -45,16 +45,11 @@ export default App => {
|
||||||
*/
|
*/
|
||||||
setHash: (hash, silence = false, replace = false) => {
|
setHash: (hash, silence = false, replace = false) => {
|
||||||
hash = hash.replace(/^[#/]+/, '');
|
hash = hash.replace(/^[#/]+/, '');
|
||||||
|
hasher.active = !silence;
|
||||||
const cmd = replace ? 'replaceHash' : 'setHash';
|
hasher[replace ? 'replaceHash' : 'setHash'](hash);
|
||||||
|
|
||||||
if (silence) {
|
if (silence) {
|
||||||
hasher.active = false;
|
|
||||||
hasher[cmd](hash);
|
|
||||||
hasher.active = true;
|
hasher.active = true;
|
||||||
} else {
|
} else {
|
||||||
hasher.active = true;
|
|
||||||
hasher[cmd](hash);
|
|
||||||
hasher.setHash(hash);
|
hasher.setHash(hash);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue