Bugfix boostrap alerts.less was accidentally removed

Bugfix Date.fromNow('past'/'future') reversed
Replace Events[pub/sub]('interval.*') with setInterval()
Events[pub/sub] to native
Cleanup knockout extensions
Replaced momentToNode with proper HTML5 <time>
Cleanup Momentor
This commit is contained in:
djmaze 2020-08-14 20:35:39 +02:00
parent 6541a1de7c
commit 9f1ea1a0fd
44 changed files with 539 additions and 1126 deletions

View file

@ -59,7 +59,7 @@ This fork uses downsized/simplified versions of scripts and has no support for I
The result is faster and smaller download code (good for mobile networks). The result is faster and smaller download code (good for mobile networks).
Things might work in Edge 15-18, Firefox 47-62 and Chrome 54-68 due to one polyfill for array.flat(). Things might work in Edge 16-18, Firefox 50-62 and Chrome 54-68 due to one polyfill for array.flat().
* Replaced jQuery with jQuery.slim * Replaced jQuery with jQuery.slim
* Replaced ProgressJS with simple native dropin * Replaced ProgressJS with simple native dropin
@ -75,32 +75,33 @@ Things might work in Edge 15-18, Firefox 47-62 and Chrome 54-68 due to one polyf
* Removed opentip (use CSS) * Removed opentip (use CSS)
* Replaced Autolinker with simple https/email detection * Replaced Autolinker with simple https/email detection
* Replaced ifvisible.js with simple drop-in replacement * Replaced ifvisible.js with simple drop-in replacement
* Replaced momentToNode with proper HTML5 <time>
|js/* |1.14.0 |native |gzip 1.14 |gzip | |js/* |1.14.0 |native |
|----------- |--------: |--------: |--------: |--------: | |----------- |--------: |--------: |
|admin.js |2.130.942 |1.119.128 | 485.481 | 271.258 | |admin.js |2.130.942 |1.090.923 |
|app.js |4.184.455 |2.829.541 | 932.725 | 659.696 | |app.js |4.184.455 |2.775.561 |
|boot.js | 671.522 | 44.029 | 169.502 | 15.460 | |boot.js | 671.522 | 44.029 |
|libs.js | 647.614 | 316.107 | 194.728 | 98.214 | |libs.js | 647.614 | 316.107 |
|polyfills.js | 325.834 | 0 | 71.825 | 0 | |polyfills.js | 325.834 | 0 |
|TOTAL js |7.960.367 |4.308.805 |1.854.261 |1.044.628 | |TOTAL |7.960.367 |4.226.620 |
|js/min/* |1.14.0 |native |gzip 1.14 |gzip | |js/min/* |1.14.0 |native |gzip 1.14 |gzip |
|--------------- |--------: |--------: |--------: |--------: | |--------------- |--------: |--------: |--------: |--------: |
|admin.min.js | 252.147 | 151.632 | 73.657 | 43.313 | |admin.min.js | 252.147 | 148.293 | 73.657 | 42.376 |
|app.min.js | 511.202 | 377.163 |140.462 | 99.062 | |app.min.js | 511.202 | 371.757 |140.462 | 97.432 |
|boot.min.js | 66.007 | 5.589 | 22.567 | 2.333 | |boot.min.js | 66.007 | 5.589 | 22.567 | 2.332 |
|libs.min.js | 572.545 | 300.211 |176.720 | 92.698 | |libs.min.js | 572.545 | 300.211 |176.720 | 92.699 |
|polyfills.min.js | 32.452 | 0 | 11.312 | 0 | |polyfills.min.js | 32.452 | 0 | 11.312 | 0 |
|TOTAL js/min |1.434.353 | 834.595 |424.718 |237.406 | |TOTAL |1.434.353 | 825.850 |424.718 |234.839 |
599.758 bytes (187.312 gzip) is not much, but it feels faster. 604.051 bytes (188.978 gzip) is not much, but it feels faster.
|css/* |1.14.0 |native | |css/* |1.14.0 |native |
|-------------- |--------: |--------: | |-------------- |--------: |--------: |
|app.css | 340.334 | 267.507 | |app.css | 340.334 | 266.796 |
|app.min.css | 274.791 | 212.244 | |app.min.css | 274.791 | 211.638 |
### PHP73 branch ### PHP73 branch

View file

@ -13,7 +13,6 @@ import { isNormal, pString, detectDropdownVisibility, windowResizeCallback } fro
import { KeyState } from 'Common/Enums'; import { KeyState } from 'Common/Enums';
import { root, rootAdmin, rootUser, populateAuthSuffix } from 'Common/Links'; import { root, rootAdmin, rootUser, populateAuthSuffix } from 'Common/Links';
import { initOnStartOrLangChange, initNotificationLanguage } from 'Common/Translator'; import { initOnStartOrLangChange, initNotificationLanguage } from 'Common/Translator';
import * as Events from 'Common/Events';
import * as Settings from 'Storage/Settings'; import * as Settings from 'Storage/Settings';
import LanguageStore from 'Stores/Language'; import LanguageStore from 'Stores/Language';
@ -32,11 +31,9 @@ class AbstractApp extends AbstractBoot {
this.isLocalAutocomplete = true; this.isLocalAutocomplete = true;
this.lastErrorTime = 0; this.lastErrorTime = 0;
addEventListener('resize', () => Events.pub('window.resize'));
var t; var t;
Events.sub( addEventListener(
'window.resize', 'resize',
()=>{ ()=>{
// throttle // throttle
if (!t) { if (!t) {
@ -47,8 +44,7 @@ class AbstractApp extends AbstractBoot {
if ($win.__sizes[0] !== iH || $win.__sizes[1] !== iW) { if ($win.__sizes[0] !== iH || $win.__sizes[1] !== iW) {
$win.__sizes[0] = iH; $win.__sizes[0] = iH;
$win.__sizes[1] = iW; $win.__sizes[1] = iW;
dispatchEvent(new CustomEvent('resize.real'));
Events.pub('window.resize.real');
} }
t = 0; t = 0;
}, 50); }, 50);
@ -56,16 +52,6 @@ class AbstractApp extends AbstractBoot {
} }
); );
// DEBUG
// Events.sub({
// 'window.resize': function() {
// console.log('window.resize');
// },
// 'window.resize.real': function() {
// console.log('window.resize.real');
// }
// });
const $doc = document; const $doc = document;
$doc.addEventListener('keydown', (event) => { $doc.addEventListener('keydown', (event) => {
if (event && event.ctrlKey) { if (event && event.ctrlKey) {
@ -81,8 +67,8 @@ class AbstractApp extends AbstractBoot {
var d; var d;
const fn = ()=>{ const fn = ()=>{
// debounce // debounce
d && clearTimeout(d); clearTimeout(d);
d = setTimeout(()=>Events.pub('rl.auto-logout-refresh'), 5000); d = setTimeout(()=>dispatchEvent(new CustomEvent('rl.auto-logout-refresh')), 5000);
} }
$doc.addEventListener('mousemove', fn); $doc.addEventListener('mousemove', fn);
@ -211,8 +197,6 @@ class AbstractApp extends AbstractBoot {
} }
bootstart() { bootstart() {
Events.pub('rl.bootstart');
const mobile = Settings.appSettingsGet('mobile'); const mobile = Settings.appSettingsGet('mobile');
ko.components.register('SaveTrigger', require('Component/SaveTrigger').default); ko.components.register('SaveTrigger', require('Component/SaveTrigger').default);
@ -239,10 +223,6 @@ class AbstractApp extends AbstractBoot {
setTimeout(windowResizeCallback, 1000); setTimeout(windowResizeCallback, 1000);
Events.sub('ssm.mobile-enter', () => leftPanelDisabled(true));
Events.sub('ssm.mobile-leave', () => leftPanelDisabled(false));
if (!mobile) { if (!mobile) {
$htmlCL.add('rl-desktop'); $htmlCL.add('rl-desktop');
@ -251,11 +231,11 @@ class AbstractApp extends AbstractBoot {
query: '(max-width: 767px)', query: '(max-width: 767px)',
onEnter: () => { onEnter: () => {
$htmlCL.add('ssm-state-mobile'); $htmlCL.add('ssm-state-mobile');
Events.pub('ssm.mobile-enter'); leftPanelDisabled(true);
}, },
onLeave: () => { onLeave: () => {
$htmlCL.remove('ssm-state-mobile'); $htmlCL.remove('ssm-state-mobile');
Events.pub('ssm.mobile-leave'); leftPanelDisabled(false);
} }
}); });
@ -281,7 +261,7 @@ class AbstractApp extends AbstractBoot {
}); });
} else { } else {
$htmlCL.add('ssm-state-mobile', 'rl-mobile'); $htmlCL.add('ssm-state-mobile', 'rl-mobile');
Events.pub('ssm.mobile-enter'); leftPanelDisabled(true);
} }
leftPanelDisabled.subscribe((bValue) => { leftPanelDisabled.subscribe((bValue) => {

View file

@ -23,7 +23,7 @@ import { $htmlCL, leftPanelDisabled, bMobileDevice } from 'Common/Globals';
import { UNUSED_OPTION_VALUE } from 'Common/Consts'; import { UNUSED_OPTION_VALUE } from 'Common/Consts';
import { runHook } from 'Common/Plugins'; import { runHook } from 'Common/Plugins';
import { momentNowUnix, reload as momentReload } from 'Common/Momentor'; import { reload as momentReload } from 'Common/Momentor';
import { import {
initMessageFlagsFromCache, initMessageFlagsFromCache,
@ -44,8 +44,6 @@ import {
openPgpJs openPgpJs
} from 'Common/Links'; } from 'Common/Links';
import * as Events from 'Common/Events';
import { getNotification, i18n } from 'Common/Translator'; import { getNotification, i18n } from 'Common/Translator';
import AppStore from 'Stores/User/App'; import AppStore from 'Stores/User/App';
@ -85,22 +83,19 @@ import { AbstractApp } from 'App/Abstract';
const doc = document; const doc = document;
if (!window.ResizeObserver) { if (!window.ResizeObserver) {
let rot;
window.ResizeObserver = class { window.ResizeObserver = class {
constructor(callback) { constructor(callback) {
this.observer = new MutationObserver(mutations => { this.observer = new MutationObserver(mutations => {
let entries = []; let i = mutations.length;
mutations.forEach(mutation => { while (i--) {
if ('style' == mutation.attributeName) { if ('style' == mutations[i].attributeName) {
entries.push({ // debounce
contentRect: { clearTimeout(rot);
width: mutation.target.offsetWidth, rot = setTimeout(callback, 250);
height: mutation.target.offsetHeight break;
},
target: mutation.target
});
} }
}); }
callback(entries);
}); });
} }
@ -123,25 +118,12 @@ class AppUser extends AbstractApp {
let qd, o = this; let qd, o = this;
this.quotaDebounce = ()=>{ this.quotaDebounce = ()=>{
// debounce // debounce
qd && clearTimeout(qd); clearTimeout(qd);
qd = setTimeout(o.quota, 30000); qd = setTimeout(o.quota, 30000);
}; };
this.moveOrDeleteResponseHelper = this.moveOrDeleteResponseHelper.bind(this); this.moveOrDeleteResponseHelper = this.moveOrDeleteResponseHelper.bind(this);
setInterval(() => Events.pub('interval.30s'), 30000);
setInterval(() => Events.pub('interval.1m'), 60000);
setInterval(() => Events.pub('interval.2m'), 120000);
setInterval(() => Events.pub('interval.3m'), 180000);
setInterval(() => Events.pub('interval.5m'), 300000);
setInterval(() => Events.pub('interval.10m'), 600000);
setInterval(() => Events.pub('interval.15m'), 900000);
setInterval(() => Events.pub('interval.20m'), 1200000);
setTimeout(() => setInterval(() => Events.pub('interval.2m-after5m'), 120000), 300000);
setTimeout(() => setInterval(() => Events.pub('interval.5m-after5m'), 300000), 300000);
setTimeout(() => setInterval(() => Events.pub('interval.10m-after5m'), 600000), 300000);
// wakeUp // wakeUp
const interval = 3600000; // 60m const interval = 3600000; // 60m
var lastTime = (new Date()).getTime(); var lastTime = (new Date()).getTime();
@ -284,7 +266,7 @@ class AppUser extends AbstractApp {
messagesMoveTrigger() { messagesMoveTrigger() {
// debounce // debounce
const o = this; const o = this;
o.mt && clearTimeout(o.mt); clearTimeout(o.mt);
o.mt = setTimeout(()=>{ o.mt = setTimeout(()=>{
const sTrashFolder = FolderStore.trashFolder(), const sTrashFolder = FolderStore.trashFolder(),
sSpamFolder = FolderStore.spamFolder(); sSpamFolder = FolderStore.spamFolder();
@ -537,37 +519,7 @@ class AppUser extends AbstractApp {
} }
} }
accountsCounts() { accountsAndIdentities() {
return false;
// AccountStore.accounts.loading(true);
//
// Remote.accountsCounts((sResult, oData) => {
//
// AccountStore.accounts.loading(false);
//
// if (StorageResultType.Success === sResult && oData.Result && oData.Result['Counts'])
// {
// var
// sEmail = AccountStore.email(),
// aAcounts = AccountStore.accounts()
// ;
//
// oData.Result['Counts'].find(oItem => {
//
// var oAccount = aAcounts.find(oAccount => {
// return oAccount && oItem[0] === oAccount.email && sEmail !== oAccount.email;
// });
//
// if (oAccount)
// {
// oAccount.count(pInt(oItem[1]));
// }
// });
// }
// });
}
accountsAndIdentities(bBoot) {
AccountStore.accounts.loading(true); AccountStore.accounts.loading(true);
IdentityStore.identities.loading(true); IdentityStore.identities.loading(true);
@ -594,11 +546,6 @@ class AppUser extends AbstractApp {
); );
} }
if (undefined === bBoot ? false : !!bBoot) {
setTimeout(() => this.accountsCounts(), 1000 * 5);
Events.sub('interval.10m-after5m', () => this.accountsCounts());
}
if (Array.isArray(oData.Result.Identities)) { if (Array.isArray(oData.Result.Identities)) {
delegateRunOnDestroy(IdentityStore.identities()); delegateRunOnDestroy(IdentityStore.identities());
@ -673,7 +620,7 @@ class AppUser extends AbstractApp {
const folderFromCache = getFolderFromCacheList(data.Result.Folder); const folderFromCache = getFolderFromCacheList(data.Result.Folder);
if (folderFromCache) { if (folderFromCache) {
folderFromCache.interval = momentNowUnix(); folderFromCache.interval = Date.now() / 1000;
if (data.Result.Hash) { if (data.Result.Hash) {
setFolderHash(data.Result.Folder, data.Result.Hash); setFolderHash(data.Result.Folder, data.Result.Hash);
@ -748,7 +695,7 @@ class AppUser extends AbstractApp {
Remote.folderInformationMultiply((sResult, oData) => { Remote.folderInformationMultiply((sResult, oData) => {
if (StorageResultType.Success === sResult) { if (StorageResultType.Success === sResult) {
if (oData && oData.Result && oData.Result.List && isNonEmptyArray(oData.Result.List)) { if (oData && oData.Result && oData.Result.List && isNonEmptyArray(oData.Result.List)) {
const utc = momentNowUnix(); const utc = Date.now() / 1000;
oData.Result.List.forEach(item => { oData.Result.List.forEach(item => {
const hash = getFolderHash(item.Folder), const hash = getFolderHash(item.Folder),
folder = getFolderFromCacheList(item.Folder); folder = getFolderFromCacheList(item.Folder);
@ -974,7 +921,7 @@ class AppUser extends AbstractApp {
}; };
if (top && bottom) { if (top && bottom) {
fDisable(false); fDisable(false);
Events.sub('layout', layout => fDisable(Layout.BottomPreview !== layout)); addEventListener('rl-layout', e => fDisable(Layout.BottomPreview !== e.detail));
} }
} }
@ -986,8 +933,7 @@ class AppUser extends AbstractApp {
}; };
if (left && right) { if (left && right) {
fDisable(false); fDisable(false);
Events.sub('left-panel.off', () => fDisable(true)); leftPanelDisabled.subscribe(value => fDisable(value));
Events.sub('left-panel.on', () => fDisable(false));
} }
} }
@ -1018,7 +964,6 @@ class AppUser extends AbstractApp {
startScreens([LoginUserScreen]); startScreens([LoginUserScreen]);
runHook('rl-start-login-screens'); runHook('rl-start-login-screens');
Events.pub('rl.bootstart-login-screens');
} else { } else {
routeOff(); routeOff();
setHash(root(), true); setHash(root(), true);
@ -1054,10 +999,6 @@ class AppUser extends AbstractApp {
progressJs.set(90); progressJs.set(90);
} }
leftPanelDisabled.subscribe((value) => {
Events.pub('left-panel.' + (value ? 'off' : 'on'));
});
this.setWindowTitle(''); this.setWindowTitle('');
if (Settings.settingsGet('Auth')) { if (Settings.settingsGet('Auth')) {
$htmlCL.add('rl-user-auth'); $htmlCL.add('rl-user-auth');
@ -1102,8 +1043,6 @@ class AppUser extends AbstractApp {
PgpStore.openpgpKeyring = new openpgp.Keyring(); PgpStore.openpgpKeyring = new openpgp.Keyring();
PgpStore.capaOpenPGP(true); PgpStore.capaOpenPGP(true);
Events.pub('openpgp.init');
this.reloadOpenPgpKeys(); this.reloadOpenPgpKeys();
return true; return true;
@ -1126,25 +1065,25 @@ class AppUser extends AbstractApp {
// false ? AboutUserScreen : null // false ? AboutUserScreen : null
]); ]);
Events.sub('interval.2m', () => this.folderInformation(getFolderInboxName())); setInterval(() => this.folderInformation(getFolderInboxName()), 120000);
Events.sub('interval.3m', () => { setInterval(() => {
const sF = FolderStore.currentFolderFullNameRaw(); const sF = FolderStore.currentFolderFullNameRaw();
if (getFolderInboxName() !== sF) { if (getFolderInboxName() !== sF) {
this.folderInformation(sF); this.folderInformation(sF);
} }
}); }, 180000);
Events.sub('interval.2m-after5m', () => this.folderInformationMultiply()); setTimeout(() => setInterval(this.folderInformationMultiply, 120000), 300000);
Events.sub('interval.15m', () => this.quota()); setInterval(this.quota, 900000);
Events.sub('interval.20m', () => this.foldersReload()); setInterval(this.foldersReload, 1200000);
contactsSyncInterval = 5 <= contactsSyncInterval ? contactsSyncInterval : 20; contactsSyncInterval = 5 <= contactsSyncInterval ? contactsSyncInterval : 20;
contactsSyncInterval = 320 >= contactsSyncInterval ? contactsSyncInterval : 320; contactsSyncInterval = 320 >= contactsSyncInterval ? contactsSyncInterval : 320;
setTimeout(() => this.contactsSync(), 10000); setTimeout(this.contactsSync, 10000);
setTimeout(() => this.folderInformationMultiply(true), 2000); setTimeout(() => this.folderInformationMultiply(true), 2000);
setInterval(() => this.contactsSync(), contactsSyncInterval * 60000 + 5000); setInterval(this.contactsSync, contactsSyncInterval * 60000 + 5000);
this.accountsAndIdentities(true); this.accountsAndIdentities(true);
@ -1155,13 +1094,12 @@ class AppUser extends AbstractApp {
} }
}, 1000); }, 1000);
setTimeout(() => this.quota(), 5000); setTimeout(this.quota, 5000);
setTimeout(() => Remote.appDelayStart(()=>{}), 35000); setTimeout(() => Remote.appDelayStart(()=>{}), 35000);
Events.sub('rl.auto-logout', () => this.logout()); addEventListener('rl.auto-logout', () => this.logout());
runHook('rl-start-user-screens'); runHook('rl-start-user-screens');
Events.pub('rl.bootstart-user-screens');
if (Settings.settingsGet('WelcomePageUrl')) { if (Settings.settingsGet('WelcomePageUrl')) {
setTimeout(() => this.bootstartWelcomePopup(Settings.settingsGet('WelcomePageUrl')), 1000); setTimeout(() => this.bootstartWelcomePopup(Settings.settingsGet('WelcomePageUrl')), 1000);
@ -1203,10 +1141,9 @@ class AppUser extends AbstractApp {
this.bootstartLoginScreen(); this.bootstartLoginScreen();
} }
Events.sub('interval.1m', () => momentReload()); setInterval(momentReload, 60000);
runHook('rl-start-screens'); runHook('rl-start-screens');
Events.pub('rl.bootstart-end');
} }
} }

View file

@ -1,5 +1,4 @@
import * as Links from 'Common/Links'; import * as Links from 'Common/Links';
import * as Events from 'Common/Events';
class Audio { class Audio {
notificator = null; notificator = null;
@ -37,7 +36,7 @@ class Audio {
this.player.addEventListener('ended', stopFn); this.player.addEventListener('ended', stopFn);
this.player.addEventListener('error', stopFn); this.player.addEventListener('error', stopFn);
Events.sub('audio.api.stop', stopFn); addEventListener('audio.api.stop', stopFn);
} }
} }
@ -66,7 +65,7 @@ class Audio {
this.player.pause(); this.player.pause();
} }
Events.pub('audio.stop'); dispatchEvent(new CustomEvent('audio.stop'));
} }
pause() { pause() {
@ -87,7 +86,7 @@ class Audio {
this.player.src = url; this.player.src = url;
this.player.play(); this.player.play();
Events.pub('audio.start', [this.clearName(name, 'mp3'), 'mp3']); dispatchEvent(new CustomEvent('audio.start', {detail:this.clearName(name, 'mp3')}));
} }
} }
@ -99,7 +98,7 @@ class Audio {
name = this.clearName(name, 'oga'); name = this.clearName(name, 'oga');
name = this.clearName(name, 'ogg'); name = this.clearName(name, 'ogg');
Events.pub('audio.start', [name, 'ogg']); dispatchEvent(new CustomEvent('audio.start', {detail:name}));
} }
} }
@ -108,7 +107,7 @@ class Audio {
this.player.src = url; this.player.src = url;
this.player.play(); this.player.play();
Events.pub('audio.start', [this.clearName(name, 'wav'), 'wav']); dispatchEvent(new CustomEvent('audio.start', {detail:this.clearName(name, 'wav')}));
} }
} }

View file

@ -4,21 +4,21 @@
* @enum {string} * @enum {string}
*/ */
export const FileType = { export const FileType = {
'Unknown': 'unknown', Unknown: 'unknown',
'Text': 'text', Text: 'text',
'Html': 'html', Html: 'html',
'Code': 'code', Code: 'code',
'Eml': 'eml', Eml: 'eml',
'WordText': 'word-text', WordText: 'word-text',
'Pdf': 'pdf', Pdf: 'pdf',
'Image': 'image', Image: 'image',
'Audio': 'audio', Audio: 'audio',
'Video': 'video', Video: 'video',
'Sheet': 'sheet', Sheet: 'sheet',
'Presentation': 'presentation', Presentation: 'presentation',
'Certificate': 'certificate', Certificate: 'certificate',
'CertificateBin': 'certificate-bin', CertificateBin: 'certificate-bin',
'Archive': 'archive', Archive: 'archive',
getIconClass: function(type) { getIconClass: function(type) {
let result = ['icon-file', '']; let result = ['icon-file', ''];
@ -67,483 +67,483 @@ export const FileType = {
* @enum {string} * @enum {string}
*/ */
export const StorageResultType = { export const StorageResultType = {
'Success': 'success', Success: 'success',
'Abort': 'abort', Abort: 'abort',
'Error': 'error', Error: 'error',
'Unload': 'unload' Unload: 'unload'
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const Focused = { export const Focused = {
'None': 'none', None: 'none',
'MessageList': 'message-list', MessageList: 'message-list',
'MessageView': 'message-view', MessageView: 'message-view',
'FolderList': 'folder-list' FolderList: 'folder-list'
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const State = { export const State = {
'Empty': 10, Empty: 10,
'Login': 20, Login: 20,
'Auth': 30 Auth: 30
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const StateType = { export const StateType = {
'Webmail': 0, Webmail: 0,
'Admin': 1 Admin: 1
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const Capa = { export const Capa = {
'TwoFactor': 'TWO_FACTOR', TwoFactor: 'TWO_FACTOR',
'TwoFactorForce': 'TWO_FACTOR_FORCE', TwoFactorForce: 'TWO_FACTOR_FORCE',
'OpenPGP': 'OPEN_PGP', OpenPGP: 'OPEN_PGP',
'Prefetch': 'PREFETCH', Prefetch: 'PREFETCH',
'Gravatar': 'GRAVATAR', Gravatar: 'GRAVATAR',
'Folders': 'FOLDERS', Folders: 'FOLDERS',
'Composer': 'COMPOSER', Composer: 'COMPOSER',
'Contacts': 'CONTACTS', Contacts: 'CONTACTS',
'Reload': 'RELOAD', Reload: 'RELOAD',
'Search': 'SEARCH', Search: 'SEARCH',
'SearchAdv': 'SEARCH_ADV', SearchAdv: 'SEARCH_ADV',
'MessageActions': 'MESSAGE_ACTIONS', MessageActions: 'MESSAGE_ACTIONS',
'MessageListActions': 'MESSAGELIST_ACTIONS', MessageListActions: 'MESSAGELIST_ACTIONS',
'AttachmentsActions': 'ATTACHMENTS_ACTIONS', AttachmentsActions: 'ATTACHMENTS_ACTIONS',
'DangerousActions': 'DANGEROUS_ACTIONS', DangerousActions: 'DANGEROUS_ACTIONS',
'Settings': 'SETTINGS', Settings: 'SETTINGS',
'Help': 'HELP', Help: 'HELP',
'Themes': 'THEMES', Themes: 'THEMES',
'UserBackground': 'USER_BACKGROUND', UserBackground: 'USER_BACKGROUND',
'Sieve': 'SIEVE', Sieve: 'SIEVE',
'Filters': 'FILTERS', Filters: 'FILTERS',
'AttachmentThumbnails': 'ATTACHMENT_THUMBNAILS', AttachmentThumbnails: 'ATTACHMENT_THUMBNAILS',
'Templates': 'TEMPLATES', Templates: 'TEMPLATES',
'AutoLogout': 'AUTOLOGOUT', AutoLogout: 'AUTOLOGOUT',
'AdditionalAccounts': 'ADDITIONAL_ACCOUNTS', AdditionalAccounts: 'ADDITIONAL_ACCOUNTS',
'Identities': 'IDENTITIES' Identities: 'IDENTITIES'
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const KeyState = { export const KeyState = {
'All': 'all', All: 'all',
'None': 'none', None: 'none',
'ContactList': 'contact-list', ContactList: 'contact-list',
'MessageList': 'message-list', MessageList: 'message-list',
'FolderList': 'folder-list', FolderList: 'folder-list',
'MessageView': 'message-view', MessageView: 'message-view',
'Compose': 'compose', Compose: 'compose',
'Settings': 'settings', Settings: 'settings',
'Menu': 'menu', Menu: 'menu',
'PopupComposeOpenPGP': 'compose-open-pgp', PopupComposeOpenPGP: 'compose-open-pgp',
'PopupMessageOpenPGP': 'message-open-pgp', PopupMessageOpenPGP: 'message-open-pgp',
'PopupViewOpenPGP': 'view-open-pgp', PopupViewOpenPGP: 'view-open-pgp',
'PopupKeyboardShortcutsHelp': 'popup-keyboard-shortcuts-help', PopupKeyboardShortcutsHelp: 'popup-keyboard-shortcuts-help',
'PopupAsk': 'popup-ask' PopupAsk: 'popup-ask'
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const FolderType = { export const FolderType = {
'Inbox': 10, Inbox: 10,
'SentItems': 11, SentItems: 11,
'Draft': 12, Draft: 12,
'Trash': 13, Trash: 13,
'Spam': 14, Spam: 14,
'Archive': 15, Archive: 15,
'NotSpam': 80, NotSpam: 80,
'User': 99 User: 99
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const ServerFolderType = { export const ServerFolderType = {
'USER': 0, USER: 0,
'INBOX': 1, INBOX: 1,
'SENT': 2, SENT: 2,
'DRAFTS': 3, DRAFTS: 3,
'JUNK': 4, JUNK: 4,
'TRASH': 5, TRASH: 5,
'IMPORTANT': 10, IMPORTANT: 10,
'FLAGGED': 11, FLAGGED: 11,
'ALL': 12 ALL: 12
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const LoginSignMeTypeAsString = { export const LoginSignMeTypeAsString = {
'DefaultOff': 'defaultoff', DefaultOff: 'defaultoff',
'DefaultOn': 'defaulton', DefaultOn: 'defaulton',
'Unused': 'unused' Unused: 'unused'
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const LoginSignMeType = { export const LoginSignMeType = {
'DefaultOff': 0, DefaultOff: 0,
'DefaultOn': 1, DefaultOn: 1,
'Unused': 2 Unused: 2
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const ComposeType = { export const ComposeType = {
'Empty': 'empty', Empty: 'empty',
'Reply': 'reply', Reply: 'reply',
'ReplyAll': 'replyall', ReplyAll: 'replyall',
'Forward': 'forward', Forward: 'forward',
'ForwardAsAttachment': 'forward-as-attachment', ForwardAsAttachment: 'forward-as-attachment',
'Draft': 'draft', Draft: 'draft',
'EditAsNew': 'editasnew' EditAsNew: 'editasnew'
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const UploadErrorCode = { export const UploadErrorCode = {
'Normal': 0, Normal: 0,
'FileIsTooBig': 1, FileIsTooBig: 1,
'FilePartiallyUploaded': 2, FilePartiallyUploaded: 2,
'FileNoUploaded': 3, FileNoUploaded: 3,
'MissingTempFolder': 4, MissingTempFolder: 4,
'FileOnSaveingError': 5, FileOnSaveingError: 5,
'FileType': 98, FileType: 98,
'Unknown': 99 Unknown: 99
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const SetSystemFoldersNotification = { export const SetSystemFoldersNotification = {
'None': 0, None: 0,
'Sent': 1, Sent: 1,
'Draft': 2, Draft: 2,
'Spam': 3, Spam: 3,
'Trash': 4, Trash: 4,
'Archive': 5 Archive: 5
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const ClientSideKeyName = { export const ClientSideKeyName = {
'FoldersLashHash': 0, FoldersLashHash: 0,
'MessagesInboxLastHash': 1, MessagesInboxLastHash: 1,
'MailBoxListSize': 2, MailBoxListSize: 2,
'ExpandedFolders': 3, ExpandedFolders: 3,
'FolderListSize': 4, FolderListSize: 4,
'MessageListSize': 5, MessageListSize: 5,
'LastReplyAction': 6, LastReplyAction: 6,
'LastSignMe': 7, LastSignMe: 7,
'ComposeLastIdentityID': 8, ComposeLastIdentityID: 8,
'MessageHeaderFullInfo': 9, MessageHeaderFullInfo: 9,
'MessageAttachmnetControls': 10 MessageAttachmnetControls: 10
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const EventKeyCode = { export const EventKeyCode = {
'Backspace': 8, Backspace: 8,
'Tab': 9, Tab: 9,
'Enter': 13, Enter: 13,
'Esc': 27, Esc: 27,
'PageUp': 33, PageUp: 33,
'PageDown': 34, PageDown: 34,
'Left': 37, Left: 37,
'Right': 39, Right: 39,
'Up': 38, Up: 38,
'Down': 40, Down: 40,
'End': 35, End: 35,
'Home': 36, Home: 36,
'Space': 32, Space: 32,
'Insert': 45, Insert: 45,
'Delete': 46, Delete: 46,
'A': 65, A: 65,
'S': 83 S: 83
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const MessageSetAction = { export const MessageSetAction = {
'SetSeen': 0, SetSeen: 0,
'UnsetSeen': 1, UnsetSeen: 1,
'SetFlag': 2, SetFlag: 2,
'UnsetFlag': 3 UnsetFlag: 3
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const MessageSelectAction = { export const MessageSelectAction = {
'All': 0, All: 0,
'None': 1, None: 1,
'Invert': 2, Invert: 2,
'Unseen': 3, Unseen: 3,
'Seen': 4, Seen: 4,
'Flagged': 5, Flagged: 5,
'Unflagged': 6 Unflagged: 6
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const DesktopNotification = { export const DesktopNotification = {
'Allowed': 0, Allowed: 0,
'NotAllowed': 1, NotAllowed: 1,
'Denied': 2, Denied: 2,
'NotSupported': 9 NotSupported: 9
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const MessagePriority = { export const MessagePriority = {
'Low': 5, Low: 5,
'Normal': 3, Normal: 3,
'High': 1 High: 1
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const EditorDefaultType = { export const EditorDefaultType = {
'Html': 'Html', Html: 'Html',
'Plain': 'Plain', Plain: 'Plain',
'HtmlForced': 'HtmlForced', HtmlForced: 'HtmlForced',
'PlainForced': 'PlainForced' PlainForced: 'PlainForced'
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const ServerSecure = { export const ServerSecure = {
'None': 0, None: 0,
'SSL': 1, SSL: 1,
'TLS': 2 TLS: 2
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const SearchDateType = { export const SearchDateType = {
'All': -1, All: -1,
'Days3': 3, Days3: 3,
'Days7': 7, Days7: 7,
'Month': 30 Month: 30
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const SaveSettingsStep = { export const SaveSettingsStep = {
'Animate': -2, Animate: -2,
'Idle': -1, Idle: -1,
'TrueResult': 1, TrueResult: 1,
'FalseResult': 0 FalseResult: 0
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const Layout = { export const Layout = {
'NoPreview': 0, NoPreview: 0,
'SidePreview': 1, SidePreview: 1,
'BottomPreview': 2 BottomPreview: 2
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const FilterConditionField = { export const FilterConditionField = {
'From': 'From', From: 'From',
'Recipient': 'Recipient', Recipient: 'Recipient',
'Subject': 'Subject', Subject: 'Subject',
'Header': 'Header', Header: 'Header',
'Size': 'Size' Size: 'Size'
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const FilterConditionType = { export const FilterConditionType = {
'Contains': 'Contains', Contains: 'Contains',
'NotContains': 'NotContains', NotContains: 'NotContains',
'EqualTo': 'EqualTo', EqualTo: 'EqualTo',
'NotEqualTo': 'NotEqualTo', NotEqualTo: 'NotEqualTo',
'Regex': 'Regex', Regex: 'Regex',
'Over': 'Over', Over: 'Over',
'Under': 'Under' Under: 'Under'
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const FiltersAction = { export const FiltersAction = {
'None': 'None', None: 'None',
'MoveTo': 'MoveTo', MoveTo: 'MoveTo',
'Discard': 'Discard', Discard: 'Discard',
'Vacation': 'Vacation', Vacation: 'Vacation',
'Reject': 'Reject', Reject: 'Reject',
'Forward': 'Forward' Forward: 'Forward'
}; };
/** /**
* @enum {string} * @enum {string}
*/ */
export const FilterRulesType = { export const FilterRulesType = {
'All': 'All', All: 'All',
'Any': 'Any' Any: 'Any'
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const SignedVerifyStatus = { export const SignedVerifyStatus = {
'UnknownPublicKeys': -4, UnknownPublicKeys: -4,
'UnknownPrivateKey': -3, UnknownPrivateKey: -3,
'Unverified': -2, Unverified: -2,
'Error': -1, Error: -1,
'None': 0, None: 0,
'Success': 1 Success: 1
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const ContactPropertyType = { export const ContactPropertyType = {
'Unknown': 0, Unknown: 0,
'FullName': 10, FullName: 10,
'FirstName': 15, FirstName: 15,
'LastName': 16, LastName: 16,
'MiddleName': 16, MiddleName: 16,
'Nick': 18, Nick: 18,
'NamePrefix': 20, NamePrefix: 20,
'NameSuffix': 21, NameSuffix: 21,
'Email': 30, Email: 30,
'Phone': 31, Phone: 31,
'Web': 32, Web: 32,
'Birthday': 40, Birthday: 40,
'Facebook': 90, Facebook: 90,
'Skype': 91, Skype: 91,
'GitHub': 92, GitHub: 92,
'Note': 110, Note: 110,
'Custom': 250 Custom: 250
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const Ports = { export const Ports = {
'Imap': 143, Imap: 143,
'ImapSsl': 993, ImapSsl: 993,
'Smtp': 25, Smtp: 25,
'SmtpSsl': 465, SmtpSsl: 465,
'SmtpStartTls': 587 SmtpStartTls: 587
}; };
/** /**
* @enum {number} * @enum {number}
*/ */
export const Notification = { export const Notification = {
'InvalidToken': 101, InvalidToken: 101,
'AuthError': 102, AuthError: 102,
'AccessError': 103, AccessError: 103,
'ConnectionError': 104, ConnectionError: 104,
'CaptchaError': 105, CaptchaError: 105,
'SocialFacebookLoginAccessDisable': 106, SocialFacebookLoginAccessDisable: 106,
'SocialTwitterLoginAccessDisable': 107, SocialTwitterLoginAccessDisable: 107,
'SocialGoogleLoginAccessDisable': 108, SocialGoogleLoginAccessDisable: 108,
'DomainNotAllowed': 109, DomainNotAllowed: 109,
'AccountNotAllowed': 110, AccountNotAllowed: 110,
'AccountTwoFactorAuthRequired': 120, AccountTwoFactorAuthRequired: 120,
'AccountTwoFactorAuthError': 121, AccountTwoFactorAuthError: 121,
'CouldNotSaveNewPassword': 130, CouldNotSaveNewPassword: 130,
'CurrentPasswordIncorrect': 131, CurrentPasswordIncorrect: 131,
'NewPasswordShort': 132, NewPasswordShort: 132,
'NewPasswordWeak': 133, NewPasswordWeak: 133,
'NewPasswordForbidden': 134, NewPasswordForbidden: 134,
'ContactsSyncError': 140, ContactsSyncError: 140,
'CantGetMessageList': 201, CantGetMessageList: 201,
'CantGetMessage': 202, CantGetMessage: 202,
'CantDeleteMessage': 203, CantDeleteMessage: 203,
'CantMoveMessage': 204, CantMoveMessage: 204,
'CantCopyMessage': 205, CantCopyMessage: 205,
'CantSaveMessage': 301, CantSaveMessage: 301,
'CantSendMessage': 302, CantSendMessage: 302,
'InvalidRecipients': 303, InvalidRecipients: 303,
'CantSaveFilters': 351, CantSaveFilters: 351,
'CantGetFilters': 352, CantGetFilters: 352,
'FiltersAreNotCorrect': 355, FiltersAreNotCorrect: 355,
'CantCreateFolder': 400, CantCreateFolder: 400,
'CantRenameFolder': 401, CantRenameFolder: 401,
'CantDeleteFolder': 402, CantDeleteFolder: 402,
'CantSubscribeFolder': 403, CantSubscribeFolder: 403,
'CantUnsubscribeFolder': 404, CantUnsubscribeFolder: 404,
'CantDeleteNonEmptyFolder': 405, CantDeleteNonEmptyFolder: 405,
'CantSaveSettings': 501, CantSaveSettings: 501,
'CantSavePluginSettings': 502, CantSavePluginSettings: 502,
'DomainAlreadyExists': 601, DomainAlreadyExists: 601,
'CantInstallPackage': 701, CantInstallPackage: 701,
'CantDeletePackage': 702, CantDeletePackage: 702,
'InvalidPluginPackage': 703, InvalidPluginPackage: 703,
'UnsupportedPluginPackage': 704, UnsupportedPluginPackage: 704,
'LicensingServerIsUnavailable': 710, LicensingServerIsUnavailable: 710,
'LicensingExpired': 711, LicensingExpired: 711,
'LicensingBanned': 712, LicensingBanned: 712,
'DemoSendMessageError': 750, DemoSendMessageError: 750,
'DemoAccountError': 751, DemoAccountError: 751,
'AccountAlreadyExists': 801, AccountAlreadyExists: 801,
'AccountDoesNotExist': 802, AccountDoesNotExist: 802,
'MailServerError': 901, MailServerError: 901,
'ClientViewError': 902, ClientViewError: 902,
'InvalidInputArgument': 903, InvalidInputArgument: 903,
'AjaxFalse': 950, AjaxFalse: 950,
'AjaxAbort': 951, AjaxAbort: 951,
'AjaxParse': 952, AjaxParse: 952,
'AjaxTimeout': 953, AjaxTimeout: 953,
'UnknownNotification': 999, UnknownNotification: 999,
'UnknownError': 999 UnknownError: 999
,getKeyByValue: function(v) { return Object.keys(this).find(key => this[key] === v); } ,getKeyByValue: function(v) { return Object.keys(this).find(key => this[key] === v); }
}; };

View file

@ -1,41 +0,0 @@
import * as Plugins from 'Common/Plugins';
const SUBS = {};
/**
* @param {string|Object} name
* @param {Function} func
* @param {Object=} context
*/
export function sub(name, func, context) {
if (typeof name === 'object') {
context = func || null;
func = null;
Object.entries(name).forEach(([subFunc, subName]) => {
sub(subName, subFunc, context);
});
} else {
if (undefined === SUBS[name]) {
SUBS[name] = [];
}
SUBS[name].push([func, context]);
}
}
/**
* @param {string} name
* @param {Array=} args
*/
export function pub(name, args) {
Plugins.runHook('rl-pub', [name, args]);
if (undefined !== SUBS[name]) {
SUBS[name].forEach(items => {
if (items[0]) {
items[0].apply(items[1] || null, args || []);
}
});
}
}

View file

@ -1,114 +1,65 @@
import { i18n } from 'Common/Translator'; import { i18n } from 'Common/Translator';
let _moment = null; let d,
let d; _moment = null,
momentNow = () => {
/** if (!d) {
* @returns {moment} d = setTimeout(()=>d=0, 500);
*/ _moment = new Date();
function momentNow() {
if (!d) {
d = setTimeout(()=>d=0, 500);
_moment = new Date();
}
return _moment;
}
/**
* @returns {number}
*/
export function momentNowUnix() {
return momentNow().getTime() / 1000;
}
/**
* @param {Object} m
* @returns {string}
*/
function formatCustomShortDate(m) {
const now = momentNow();
if (m && now) {
switch (true) {
case 4 >= (now.getTime() - m.getTime()) / 3600000:
return m.fromNow();
case now.format('L') === m.format('L'):
return i18n('MESSAGE_LIST/TODAY_AT', {
TIME: m.format('LT')
});
case new Date(now.getTime() - 86400000) // subtract 1 day
.format('L') === m.format('L'):
return i18n('MESSAGE_LIST/YESTERDAY_AT', {
TIME: m.format('LT')
});
case now.getFullYear() === m.getFullYear():
return m.format('d M.');
// no default
} }
} return _moment;
};
return m ? m.format('LL') : '';
}
/**
* @param {number} timeStampInUTC
* @param {string} formatStr
* @returns {string}
*/
export function format(timeStampInUTC, formatStr) { export function format(timeStampInUTC, formatStr) {
let m = null, const now = Date.now() / 1000;
result = '';
const now = momentNowUnix(); timeStampInUTC = 0 < timeStampInUTC ? Math.min(now, timeStampInUTC) : (0 === timeStampInUTC ? now : 0);
timeStampInUTC = 0 < timeStampInUTC ? timeStampInUTC : 0 === timeStampInUTC ? now : 0; if (31536000 < timeStampInUTC) {
timeStampInUTC = now < timeStampInUTC ? now : timeStampInUTC; const m = new Date(timeStampInUTC * 1000);
m = 0 < timeStampInUTC ? new Date(timeStampInUTC * 1000) : null;
if (m && 1970 === m.getFullYear()) {
m = null;
}
if (m) {
switch (formatStr) { switch (formatStr) {
case 'FROMNOW': case 'FROMNOW':
result = m.fromNow(); return m.fromNow();
break;
case 'SHORT': case 'SHORT':
result = formatCustomShortDate(m); if (4 >= (now - timeStampInUTC) / 3600)
break; return m.fromNow();
if (momentNow().format('Ymd') === m.format('Ymd'))
return i18n('MESSAGE_LIST/TODAY_AT', {TIME: m.format('LT')});
if (new Date((now - 86400) * 1000).format('Ymd') === m.format('Ymd'))
return i18n('MESSAGE_LIST/YESTERDAY_AT', {TIME: m.format('LT')});
if (momentNow().getFullYear() === m.getFullYear())
return m.format('d M.');
return m.format('LL');
case 'FULL': case 'FULL':
result = m.format('LLL'); return m.format('LLL');
break;
default: default:
result = m.format(formatStr); return m.format(formatStr);
break;
} }
} }
return result; return '';
} }
/** export function timeToNode(element, time) {
* @param {Object} element try {
* @returns {void} time = time || (Date.parse(element.dateTime) / 1000);
*/ if (time) {
export function momentToNode(element) { let key, m = new Date(time * 1000);
let key = '', element.dateTime = m.format('Y-m-d\\TH:i:s');
time = 0;
const $el = jQuery(element);
time = $el.data('moment-time'); key = element.dataset.momentFormat;
if (time) { if (key) {
key = $el.data('moment-format'); element.textContent = format(time, key);
if (key) { }
$el.text(format(time, key));
}
key = $el.data('moment-format-title'); key = element.dataset.momentFormatTitle;
if (key) { if (key) {
$el.attr('title', format(time, key)); element.title = format(time, key);
}
} }
} catch (e) {
// prevent knockout crashes
console.error(e);
} }
} }
@ -117,8 +68,6 @@ export function momentToNode(element) {
*/ */
export function reload() { export function reload() {
setTimeout(() => setTimeout(() =>
jQuery('.moment', document).each((index, item) => { document.querySelectorAll('[data-bind*="moment:"]').forEach(element => timeToNode(element))
momentToNode(item);
})
, 1); , 1);
} }

View file

@ -55,7 +55,7 @@ class Selector {
var d, o = this; var d, o = this;
this.itemSelectedThrottle = (item)=>{ this.itemSelectedThrottle = (item)=>{
// debounce // debounce
d && clearTimeout(d); clearTimeout(d);
d = setTimeout(()=>o.itemSelected(item), 300); d = setTimeout(()=>o.itemSelected(item), 300);
}; };

View file

@ -845,7 +845,7 @@ export function selectElement(element) {
var dv; var dv;
export const detectDropdownVisibility = ()=>{ export const detectDropdownVisibility = ()=>{
// leading debounce // leading debounce
dv && clearTimeout(dv); clearTimeout(dv);
dv = setTimeout(()=> dv = setTimeout(()=>
dropdownVisibility(!!GlobalsData.aBootstrapDropdowns.find(item => item.hasClass('open'))) dropdownVisibility(!!GlobalsData.aBootstrapDropdowns.find(item => item.hasClass('open')))
, 50); , 50);
@ -1223,7 +1223,7 @@ export function mailToHelper(mailToUrl, PopupComposeViewModel) {
var wr; var wr;
export const windowResize = timeout => { export const windowResize = timeout => {
wr && clearTimeout(wr); clearTimeout(wr);
if (undefined === timeout || null === timeout) { if (undefined === timeout || null === timeout) {
$win.trigger('resize'); $win.trigger('resize');
} else { } else {

323
dev/External/ko.js vendored
View file

@ -12,16 +12,8 @@ ko.bindingHandlers.editor = {
const fValue = fValueAccessor(), const fValue = fValueAccessor(),
HtmlEditor = require('Common/HtmlEditor').default, HtmlEditor = require('Common/HtmlEditor').default,
fUpdateEditorValue = () => { fUpdateEditorValue = () => fValue && fValue.__editor && fValue.__editor.setHtmlOrPlain(fValue()),
if (fValue && fValue.__editor) { fUpdateKoValue = () => fValue && fValue.__editor && fValue(fValue.__editor.getDataWithHtmlMark()),
fValue.__editor.setHtmlOrPlain(fValue());
}
},
fUpdateKoValue = () => {
if (fValue && fValue.__editor) {
fValue(fValue.__editor.getDataWithHtmlMark());
}
},
fOnReady = () => { fOnReady = () => {
fValue.__editor = editor; fValue.__editor = editor;
fUpdateEditorValue(); fUpdateEditorValue();
@ -40,66 +32,9 @@ ko.bindingHandlers.editor = {
} }
}; };
ko.bindingHandlers.json = {
init: (element, fValueAccessor) => {
$(element).text(JSON.stringify(ko.unwrap(fValueAccessor())));
},
update: (element, fValueAccessor) => {
$(element).text(JSON.stringify(ko.unwrap(fValueAccessor())));
}
};
ko.bindingHandlers.scrollerShadows = {
init: (element) => {
var t;
const limit = 8,
$el = $(element),
cont = $el.find('[data-scroller-shadows-content]')[0] || null,
// throttle
fFunc = ()=>{
if (!t) {
t = setTimeout(()=>{
$el
.toggleClass('scroller-shadow-top', limit < cont.scrollTop)
.toggleClass('scroller-shadow-bottom', cont.scrollTop + limit < cont.scrollHeight - cont.clientHeight);
t = 0;
}, 100);
}
};
if (cont) {
$(cont).on('scroll resize', fFunc);
addEventListener('resize', fFunc);
ko.utils.domNodeDisposal.addDisposeCallback(cont, () => {
$(cont).off();
removeEventListener('resize', fFunc);
});
}
}
};
ko.bindingHandlers.visibleAnimated = { ko.bindingHandlers.visibleAnimated = {
init: (element, fValueAccessor) => { init: (element, fValueAccessor) => element.hidden = !ko.unwrap(fValueAccessor()),
const $el = $(element); update: (element, fValueAccessor) => element.hidden = !ko.unwrap(fValueAccessor())
$el.addClass('rl-animated-inited');
if (ko.unwrap(fValueAccessor())) {
$el.show();
} else {
$el.hide();
}
},
update: (element, fValueAccessor) => {
const $el = $(element);
if (ko.unwrap(fValueAccessor())) {
$el.addClass('rl-animated-hidden').show();
setTimeout(() => {
$el.removeClass('rl-animated-hidden');
}, 10);
} else {
$el.hide().removeClass('rl-animated-hidden');
}
}
}; };
ko.bindingHandlers.tooltip = { ko.bindingHandlers.tooltip = {
@ -139,13 +74,9 @@ ko.bindingHandlers.tooltip = {
}; };
ko.bindingHandlers.tooltipErrorTip = { ko.bindingHandlers.tooltipErrorTip = {
init: function(element) { init: element => {
$(document).on('click', () => { document.addEventListener('click', () => element.removeAttribute('data-rainloopErrorTip'));
element.removeAttribute('data-rainloopErrorTip') ko.utils.domNodeDisposal.addDisposeCallback(element, () => element.removeAttribute('data-rainloopErrorTip'));
});
ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
element.removeAttribute('data-rainloopErrorTip')
});
}, },
update: (element, fValueAccessor) => { update: (element, fValueAccessor) => {
const fValue = fValueAccessor(), const fValue = fValueAccessor(),
@ -164,13 +95,7 @@ ko.bindingHandlers.registrateBootstrapDropdown = {
const Globals = require('Common/Globals'); const Globals = require('Common/Globals');
if (Globals && Globals.data.aBootstrapDropdowns) { if (Globals && Globals.data.aBootstrapDropdowns) {
Globals.data.aBootstrapDropdowns.push($(element)); Globals.data.aBootstrapDropdowns.push($(element));
element.addEventListener('click', () => require('Common/Utils').detectDropdownVisibility());
$(element).click(() => {
require('Common/Utils').detectDropdownVisibility();
});
// ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
// });
} }
} }
}; };
@ -178,12 +103,12 @@ ko.bindingHandlers.registrateBootstrapDropdown = {
ko.bindingHandlers.openDropdownTrigger = { ko.bindingHandlers.openDropdownTrigger = {
update: (element, fValueAccessor) => { update: (element, fValueAccessor) => {
if (ko.unwrap(fValueAccessor())) { if (ko.unwrap(fValueAccessor())) {
const $el = $(element); const $el = $(element), t = $el.find('.dropdown-toggle');
if (!$el.hasClass('open')) { if (!$el.hasClass('open')) {
$el.find('.dropdown-toggle').dropdown('toggle'); t.dropdown('toggle');
} }
$el.find('.dropdown-toggle').focus(); t.focus();
require('Common/Utils').detectDropdownVisibility(); require('Common/Utils').detectDropdownVisibility();
fValueAccessor()(false); fValueAccessor()(false);
@ -192,17 +117,15 @@ ko.bindingHandlers.openDropdownTrigger = {
}; };
ko.bindingHandlers.dropdownCloser = { ko.bindingHandlers.dropdownCloser = {
init: (element) => { init: element => $(element)
$(element) .closest('.dropdown')
.closest('.dropdown') .on('click', '.e-item', () => {
.on('click', '.e-item', () => { $(element).dropdown('toggle');
$(element).dropdown('toggle'); })
});
}
}; };
ko.bindingHandlers.popover = { ko.bindingHandlers.popover = {
init: function(element, fValueAccessor) { init: (element, fValueAccessor) => {
console.log('TODO: $(element).popover removed', element, fValueAccessor); console.log('TODO: $(element).popover removed', element, fValueAccessor);
/* /*
$(element).popover(ko.unwrap(fValueAccessor())); $(element).popover(ko.unwrap(fValueAccessor()));
@ -213,22 +136,6 @@ ko.bindingHandlers.popover = {
} }
}; };
ko.bindingHandlers.onKeyDown = {
init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
$(element).on('keydown.koOnKeyDown', (event) => {
if (event) {
return fValueAccessor().call(viewModel, event);
}
return true;
});
ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
$(element).off('keydown.koOnKeyDown');
});
}
};
ko.bindingHandlers.onEnter = { ko.bindingHandlers.onEnter = {
init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => { init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
$(element).on('keypress.koOnEnter', (event) => { $(element).on('keypress.koOnEnter', (event) => {
@ -258,21 +165,6 @@ ko.bindingHandlers.onSpace = {
} }
}; };
ko.bindingHandlers.onTab = {
init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
$(element).on('keydown.koOnTab', (event) => {
if (event && 9 === parseInt(event.keyCode, 10)) {
return fValueAccessor().call(viewModel, !!event.shiftKey);
}
return true;
});
ko.utils.domNodeDisposal.addDisposeCallback(element, () => {
$(element).off('keydown.koOnTab');
});
}
};
ko.bindingHandlers.onEsc = { ko.bindingHandlers.onEsc = {
init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => { init: (element, fValueAccessor, fAllBindingsAccessor, viewModel) => {
$(element).on('keyup.koOnEsc', (event) => { $(element).on('keyup.koOnEsc', (event) => {
@ -288,14 +180,6 @@ ko.bindingHandlers.onEsc = {
} }
}; };
ko.bindingHandlers.clickOnTrue = {
update: (element, fValueAccessor) => {
if (ko.unwrap(fValueAccessor())) {
$(element).click();
}
}
};
ko.bindingHandlers.modal = { ko.bindingHandlers.modal = {
init: (element, fValueAccessor) => { init: (element, fValueAccessor) => {
const Globals = require('Common/Globals'), const Globals = require('Common/Globals'),
@ -327,117 +211,52 @@ ko.bindingHandlers.modal = {
if (Globals.$htmlCL.contains('rl-anim')) { if (Globals.$htmlCL.contains('rl-anim')) {
Globals.$htmlCL.add('rl-modal-animation'); Globals.$htmlCL.add('rl-modal-animation');
setTimeout(() => { setTimeout(() => Globals.$htmlCL.remove('rl-modal-animation'), 500);
Globals.$htmlCL.remove('rl-modal-animation');
}, 500);
} }
} }
}; };
let ttn = (element, fValueAccessor) => require('Common/Momentor').timeToNode(element, ko.unwrap(fValueAccessor()));
ko.bindingHandlers.moment = { ko.bindingHandlers.moment = {
init: (element, fValueAccessor) => { init: ttn,
require('Common/Momentor').momentToNode( update: ttn
$(element)
.addClass('moment')
.data('moment-time', ko.unwrap(fValueAccessor()))
);
},
update: (element, fValueAccessor) => {
require('Common/Momentor').momentToNode($(element).data('moment-time', ko.unwrap(fValueAccessor())));
}
}; };
ko.bindingHandlers.i18nInit = { ko.bindingHandlers.i18nInit = {
init: (element) => { init: element => Translator().i18nToNodes(element)
require('Common/Translator').i18nToNodes(element);
}
};
ko.bindingHandlers.translatorInit = {
init: (element) => {
require('Common/Translator').i18nToNodes(element);
}
}; };
ko.bindingHandlers.i18nUpdate = { ko.bindingHandlers.i18nUpdate = {
update: (element, fValueAccessor) => { update: (element, fValueAccessor) => {
ko.unwrap(fValueAccessor()); ko.unwrap(fValueAccessor());
require('Common/Translator').i18nToNodes(element); Translator().i18nToNodes(element);
} }
}; };
ko.bindingHandlers.link = { ko.bindingHandlers.link = {
update: function(element, fValueAccessor) { update: (element, fValueAccessor) => element.setAttribute('href', ko.unwrap(fValueAccessor()))
$(element).attr('href', ko.unwrap(fValueAccessor()));
}
}; };
ko.bindingHandlers.title = { ko.bindingHandlers.title = {
update: function(element, fValueAccessor) { update: (element, fValueAccessor) => element.setAttribute('title', ko.unwrap(fValueAccessor()))
$(element).attr('title', ko.unwrap(fValueAccessor()));
}
};
ko.bindingHandlers.textF = {
init: function(element, fValueAccessor) {
$(element).text(ko.unwrap(fValueAccessor()));
}
}; };
ko.bindingHandlers.initDom = { ko.bindingHandlers.initDom = {
init: function(element, fValueAccessor) { init: (element, fValueAccessor) => fValueAccessor()(element)
fValueAccessor()(element);
}
};
ko.bindingHandlers.initFixedTrigger = {
init: (element, fValueAccessor) => {
const values = ko.unwrap(fValueAccessor()),
$el = $(element),
top = values[1] || 0;
let $container = $(values[0] || null);
$container = $container[0] ? $container : null;
if ($container) {
addEventListener('resize', () => {
const offset = $container ? $container.offset() : null;
if (offset && offset.top) {
$el.css('top', offset.top + top);
}
});
}
}
}; };
ko.bindingHandlers.initResizeTrigger = { ko.bindingHandlers.initResizeTrigger = {
init: (element, fValueAccessor) => { init: (element, fValueAccessor) =>
element.style.height = element.style.minHeight = ko.unwrap(fValueAccessor())[1] + 'px',
update: (element, fValueAccessor) => {
const values = ko.unwrap(fValueAccessor()); const values = ko.unwrap(fValueAccessor());
$(element).css({ let offset = element.getBoundingClientRect().top + pageYOffset;
'height': values[1],
'min-height': values[1]
});
},
update: (oElement, fValueAccessor) => {
const Utils = require('Common/Utils'),
Globals = require('Common/Globals'),
values = ko.unwrap(fValueAccessor());
let value = Utils.pInt(values[1]),
size = 0,
offset = $(oElement).offset().top;
if (0 < offset) { if (0 < offset) {
offset += Utils.pInt(values[2]); offset += parseInt(values[2], 10) || 0;
size = Globals.$win.height() - offset; element.style.height = element.style.minHeight = Math.max(
parseInt(values[1], 10) || 0,
if (value < size) { window.innerHeight - offset
value = size; ) + 'px';
}
$(oElement).css({
'height': value,
'min-height': value
});
} }
} }
}; };
@ -720,8 +539,7 @@ ko.bindingHandlers.emailsTags = {
ko.bindingHandlers.command = { ko.bindingHandlers.command = {
init: (element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext) => { init: (element, fValueAccessor, fAllBindingsAccessor, viewModel, bindingContext) => {
const jqElement = $(element), const command = fValueAccessor();
command = fValueAccessor();
if (!command || !command.isCommand) { if (!command || !command.isCommand) {
throw new Error('Value should be a command'); throw new Error('Value should be a command');
@ -740,8 +558,8 @@ ko.bindingHandlers.command = {
} }
} }
jqElement.addClass('command'); element.classList.add('command');
ko.bindingHandlers[jqElement.is('form') ? 'submit' : 'click'].init( ko.bindingHandlers[element.tagName.match(/FORM/i) ? 'submit' : 'click'].init(
element, element,
fValueAccessor, fValueAccessor,
fAllBindingsAccessor, fAllBindingsAccessor,
@ -750,40 +568,29 @@ ko.bindingHandlers.command = {
); );
}, },
update: (element, fValueAccessor) => { update: (element, fValueAccessor) => {
const jqElement = $(element), const cl = element.classList,
command = fValueAccessor(); command = fValueAccessor();
let result = command.enabled(); let result = command.enabled();
jqElement.toggleClass('command-not-enabled', !result); cl.toggle('command-not-enabled', !result);
if (result) { if (result) {
result = command.canExecute(); result = command.canExecute();
jqElement.toggleClass('command-can-not-be-execute', !result); cl.toggle('command-can-not-be-execute', !result);
} }
jqElement.toggleClass('command-disabled disable disabled', !result).toggleClass('no-disabled', !!result); ['command-disabled','disable','disabled'].forEach(s=>cl.toggle(s, !result));
cl.toggle('no-disabled', !!result);
if (jqElement.is('input') || jqElement.is('button')) { if (element.tagName.match(/INPUT|TEXTAREA|BUTTON/i)) {
jqElement.prop('disabled', !result); element.disabled = !result;
} }
} }
}; };
// extenders // extenders
ko.extenders.trimmer = (target) => {
const result = ko.computed({
read: target,
write: (newValue) => {
target(newValue.toString().trim());
}
});
result(target());
return result;
};
ko.extenders.posInterer = (target, defaultVal) => { ko.extenders.posInterer = (target, defaultVal) => {
const Utils = require('Common/Utils'), const Utils = require('Common/Utils'),
result = ko.computed({ result = ko.computed({
@ -834,9 +641,7 @@ ko.extenders.limitedList = (target, limitedList) => {
result(target()); result(target());
if (!result.valueHasMutated) { if (!result.valueHasMutated) {
result.valueHasMutated = () => { result.valueHasMutated = () => target.valueHasMutated();
target.valueHasMutated();
};
} }
return result; return result;
@ -845,13 +650,9 @@ ko.extenders.limitedList = (target, limitedList) => {
ko.extenders.reversible = (target) => { ko.extenders.reversible = (target) => {
let value = target(); let value = target();
target.commit = () => { target.commit = () => value = target();
value = target();
};
target.reverse = () => { target.reverse = () => target(value);
target(value);
};
target.commitedValue = () => value; target.commitedValue = () => value;
return target; return target;
@ -867,20 +668,12 @@ ko.extenders.toggleSubscribeProperty = (target, options) => {
const prop = options[1]; const prop = options[1];
if (prop) { if (prop) {
target.subscribe( target.subscribe(
(prev) => { prev => prev && prev[prop] && prev[prop](false),
if (prev && prev[prop]) {
prev[prop](false);
}
},
options[0], options[0],
'beforeChange' 'beforeChange'
); );
target.subscribe((next) => { target.subscribe(next => next && next[prop] && next[prop](true), options[0]);
if (next && next[prop]) {
next[prop](true);
}
}, options[0]);
} }
return target; return target;
@ -888,13 +681,13 @@ ko.extenders.toggleSubscribeProperty = (target, options) => {
ko.extenders.falseTimeout = (target, option) => { ko.extenders.falseTimeout = (target, option) => {
target.iFalseTimeoutTimeout = 0; target.iFalseTimeoutTimeout = 0;
target.subscribe((value) => { target.subscribe(value => {
if (value) { if (value) {
clearTimeout(target.iFalseTimeoutTimeout); clearTimeout(target.iFalseTimeoutTimeout);
target.iFalseTimeoutTimeout = setTimeout(() => { target.iFalseTimeoutTimeout = setTimeout(() => {
target(false); target(false);
target.iFalseTimeoutTimeout = 0; target.iFalseTimeoutTimeout = 0;
}, require('Common/Utils').pInt(option)); }, parseInt(option, 10) || 0);
} }
}); });
@ -949,9 +742,7 @@ ko.observable.fn.validateNone = function() {
ko.observable.fn.validateEmail = function() { ko.observable.fn.validateEmail = function() {
this.hasError = ko.observable(false); this.hasError = ko.observable(false);
this.subscribe((value) => { this.subscribe(value => this.hasError(value && !/^[^@\s]+@[^@\s]+$/.test(value)));
this.hasError(value && !/^[^@\s]+@[^@\s]+$/.test(value));
});
this.valueHasMutated(); this.valueHasMutated();
return this; return this;
@ -960,9 +751,7 @@ ko.observable.fn.validateEmail = function() {
ko.observable.fn.validateSimpleEmail = function() { ko.observable.fn.validateSimpleEmail = function() {
this.hasError = ko.observable(false); this.hasError = ko.observable(false);
this.subscribe((value) => { this.subscribe(value => this.hasError(value && !/^.+@.+$/.test(value)));
this.hasError(value && !/^.+@.+$/.test(value));
});
this.valueHasMutated(); this.valueHasMutated();
return this; return this;
@ -977,9 +766,7 @@ ko.observable.fn.validateFunc = function(fFunc) {
this.hasFuncError = ko.observable(false); this.hasFuncError = ko.observable(false);
if (isFunction(fFunc)) { if (isFunction(fFunc)) {
this.subscribe((value) => { this.subscribe(value => this.hasFuncError(!fFunc(value)));
this.hasFuncError(!fFunc(value));
});
this.valueHasMutated(); this.valueHasMutated();
} }

View file

@ -207,7 +207,7 @@ export function buildViewModel(ViewModelClass, vmScreen) {
ko.applyBindingAccessorsToNode( ko.applyBindingAccessorsToNode(
vmDom[0], vmDom[0],
{ {
translatorInit: true, i18nInit: true,
template: () => ({ name: vm.viewModelTemplateID }) template: () => ({ name: vm.viewModelTemplateID })
}, },
vm vm

View file

@ -4,7 +4,6 @@ import { FolderType } from 'Common/Enums';
import { isPosNumeric } from 'Common/Utils'; import { isPosNumeric } from 'Common/Utils';
import { i18n, trigger as translatorTrigger } from 'Common/Translator'; import { i18n, trigger as translatorTrigger } from 'Common/Translator';
import { getFolderInboxName } from 'Common/Cache'; import { getFolderInboxName } from 'Common/Cache';
import * as Events from 'Common/Events';
import { AbstractModel } from 'Knoin/AbstractModel'; import { AbstractModel } from 'Knoin/AbstractModel';
@ -234,19 +233,13 @@ class FolderModel extends AbstractModel {
); );
// subscribe // subscribe
this.name.subscribe((value) => { this.name.subscribe(value => this.nameForEdit(value));
this.nameForEdit(value);
});
this.edited.subscribe((value) => { this.edited.subscribe(value => value && this.nameForEdit(this.name()));
if (value) {
this.nameForEdit(this.name());
}
});
this.messageCountUnread.subscribe((unread) => { this.messageCountUnread.subscribe((unread) => {
if (FolderType.Inbox === this.type()) { if (FolderType.Inbox === this.type()) {
Events.pub('mailbox.inbox-unread-count', [unread]); dispatchEvent(new CustomEvent('mailbox.inbox-unread-count', {detail:unread}));
} }
}); });

View file

@ -228,13 +228,6 @@ class RemoteUserAjax extends AbstractAjaxRemote {
this.defaultRequest(fCallback, 'AccountsAndIdentities'); this.defaultRequest(fCallback, 'AccountsAndIdentities');
} }
/**
* @param {?Function} fCallback
*/
accountsCounts(fCallback) {
this.defaultRequest(fCallback, 'AccountsCounts');
}
/** /**
* @param {?Function} fCallback * @param {?Function} fCallback
* @param {Array} filters * @param {Array} filters

View file

@ -88,7 +88,7 @@ class AbstractSettingsScreen extends AbstractScreen {
ko.applyBindingAccessorsToNode( ko.applyBindingAccessorsToNode(
viewModelDom[0], viewModelDom[0],
{ {
translatorInit: true, i18nInit: true,
template: () => tmpl template: () => tmpl
}, },
settingsScreen settingsScreen

View file

@ -4,7 +4,6 @@ import { pString, pInt, windowResizeCallback } from 'Common/Utils';
import { getFolderFromCacheList, getFolderFullNameRaw, getFolderInboxName } from 'Common/Cache'; import { getFolderFromCacheList, getFolderFullNameRaw, getFolderInboxName } from 'Common/Cache';
import { i18n } from 'Common/Translator'; import { i18n } from 'Common/Translator';
import * as Events from 'Common/Events';
import * as Settings from 'Storage/Settings'; import * as Settings from 'Storage/Settings';
import AppStore from 'Stores/User/App'; import AppStore from 'Stores/User/App';
@ -110,13 +109,13 @@ class MailBoxUserScreen extends AbstractScreen {
setTimeout(() => SettingsStore.layout.valueHasMutated(), 50); setTimeout(() => SettingsStore.layout.valueHasMutated(), 50);
setTimeout(() => warmUpScreenPopup(require('View/Popup/Compose')), 500); setTimeout(() => warmUpScreenPopup(require('View/Popup/Compose')), 500);
Events.sub('mailbox.inbox-unread-count', (count) => { addEventListener('mailbox.inbox-unread-count', e => {
FolderStore.foldersInboxUnreadCount(count); FolderStore.foldersInboxUnreadCount(e.detail);
const email = AccountStore.email(); const email = AccountStore.email();
AccountStore.accounts().forEach(item => { AccountStore.accounts().forEach(item => {
if (item && email === item.email) { if (item && email === item.email) {
item.count(count); item.count(e.detail);
} }
}); });

View file

@ -7,8 +7,6 @@ import { UNUSED_OPTION_VALUE } from 'Common/Consts';
import { folderListOptionsBuilder } from 'Common/Utils'; import { folderListOptionsBuilder } from 'Common/Utils';
import { getFolderInboxName, getFolderFromCacheList } from 'Common/Cache'; import { getFolderInboxName, getFolderFromCacheList } from 'Common/Cache';
import { momentNowUnix } from 'Common/Momentor';
class FolderUserStore { class FolderUserStore {
constructor() { constructor() {
this.displaySpecSetting = ko.observable(true); this.displaySpecSetting = ko.observable(true);
@ -157,7 +155,7 @@ class FolderUserStore {
getNextFolderNames() { getNextFolderNames() {
const result = [], const result = [],
limit = 5, limit = 5,
utc = momentNowUnix(), utc = Date.now() / 1000,
timeout = utc - 60 * 5, timeout = utc - 60 * 5,
timeouts = [], timeouts = [],
inboxFolderName = getFolderInboxName(), inboxFolderName = getFolderInboxName(),
@ -182,15 +180,7 @@ class FolderUserStore {
fSearchFunction(this.folderList()); fSearchFunction(this.folderList());
timeouts.sort((a, b) => { timeouts.sort((a, b) => (a[0] < b[0]) ? -1 : (a[0] > b[0] ? 1 : 0));
if (a[0] < b[0]) {
return -1;
} else if (a[0] > b[0]) {
return 1;
}
return 0;
});
timeouts.find(aItem => { timeouts.find(aItem => {
const folder = getFolderFromCacheList(aItem[1]); const folder = getFolderFromCacheList(aItem[1]);

View file

@ -29,7 +29,6 @@ import { MESSAGE_BODY_CACHE_LIMIT } from 'Common/Consts';
import { data as GlobalsData } from 'Common/Globals'; import { data as GlobalsData } from 'Common/Globals';
import { mailBox, notificationMailIcon } from 'Common/Links'; import { mailBox, notificationMailIcon } from 'Common/Links';
import { i18n, getNotification } from 'Common/Translator'; import { i18n, getNotification } from 'Common/Translator';
import { momentNowUnix } from 'Common/Momentor';
import * as MessageHelper from 'Helper/Message'; import * as MessageHelper from 'Helper/Message';
import { MessageModel } from 'Model/Message'; import { MessageModel } from 'Model/Message';
@ -209,7 +208,7 @@ class MessageUserStore {
this.messageList.subscribe( this.messageList.subscribe(
(list)=>{ (list)=>{
// debounce // debounce
d && clearTimeout(d); clearTimeout(d);
d = setTimeout(()=>list.forEach(item => { d = setTimeout(()=>list.forEach(item => {
if (item && item.newForAnimation()) { if (item && item.newForAnimation()) {
item.newForAnimation(false); item.newForAnimation(false);
@ -750,7 +749,7 @@ class MessageUserStore {
const folder = getFolderFromCacheList(isNormal(data.Result.Folder) ? data.Result.Folder : ''); const folder = getFolderFromCacheList(isNormal(data.Result.Folder) ? data.Result.Folder : '');
if (folder && !cached) { if (folder && !cached) {
folder.interval = momentNowUnix(); folder.interval = Date.now() / 1000;
setFolderHash(data.Result.Folder, data.Result.FolderHash); setFolderHash(data.Result.Folder, data.Result.FolderHash);

View file

@ -1,7 +1,6 @@
import ko from 'ko'; import ko from 'ko';
import { DesktopNotification } from 'Common/Enums'; import { DesktopNotification } from 'Common/Enums';
import * as Events from 'Common/Events';
import Audio from 'Common/Audio'; import Audio from 'Common/Audio';
import * as Settings from 'Storage/Settings'; import * as Settings from 'Storage/Settings';
@ -118,7 +117,7 @@ class NotificationUserStore {
} }
} }
displayDesktopNotification(imageSrc, title, text, nessageData) { displayDesktopNotification(imageSrc, title, text, messageData) {
if (this.enableDesktopNotification()) { if (this.enableDesktopNotification()) {
const NotificationClass = this.notificationClass(), const NotificationClass = this.notificationClass(),
notification = NotificationClass notification = NotificationClass
@ -133,12 +132,12 @@ class NotificationUserStore {
notification.show(); notification.show();
} }
if (nessageData) { if (messageData) {
notification.onclick = () => { notification.onclick = () => {
focus(); focus();
if (nessageData.Folder && nessageData.Uid) { if (messageData.Folder && messageData.Uid) {
Events.pub('mailbox.message.show', [nessageData.Folder, nessageData.Uid]); dispatchEvent(new CustomEvent('mailbox.message.show', {detail:messageData}));
} }
}; };
} }

View file

@ -4,7 +4,6 @@ import { MESSAGES_PER_PAGE, MESSAGES_PER_PAGE_VALUES } from 'Common/Consts';
import { Layout, EditorDefaultType } from 'Common/Enums'; import { Layout, EditorDefaultType } from 'Common/Enums';
import { $htmlCL } from 'Common/Globals'; import { $htmlCL } from 'Common/Globals';
import { pInt } from 'Common/Utils'; import { pInt } from 'Common/Utils';
import * as Events from 'Common/Events';
import * as Settings from 'Storage/Settings'; import * as Settings from 'Storage/Settings';
@ -48,7 +47,7 @@ class SettingsUserStore {
$htmlCL.toggle('rl-no-preview-pane', Layout.NoPreview === value); $htmlCL.toggle('rl-no-preview-pane', Layout.NoPreview === value);
$htmlCL.toggle('rl-side-preview-pane', Layout.SidePreview === value); $htmlCL.toggle('rl-side-preview-pane', Layout.SidePreview === value);
$htmlCL.toggle('rl-bottom-preview-pane', Layout.BottomPreview === value); $htmlCL.toggle('rl-bottom-preview-pane', Layout.BottomPreview === value);
Events.pub('layout', [value]); dispatchEvent(new CustomEvent('rl-layout', {detail:value}));
}); });
} }
@ -65,16 +64,16 @@ class SettingsUserStore {
this.useThreads(!!Settings.settingsGet('UseThreads')); this.useThreads(!!Settings.settingsGet('UseThreads'));
this.replySameFolder(!!Settings.settingsGet('ReplySameFolder')); this.replySameFolder(!!Settings.settingsGet('ReplySameFolder'));
Events.sub('rl.auto-logout-refresh', () => { const refresh = () => {
clearTimeout(this.iAutoLogoutTimer); clearTimeout(this.iAutoLogoutTimer);
if (0 < this.autoLogout() && !Settings.settingsGet('AccountSignMe')) { if (0 < this.autoLogout() && !Settings.settingsGet('AccountSignMe')) {
this.iAutoLogoutTimer = setTimeout(() => { this.iAutoLogoutTimer = setTimeout(() =>
Events.pub('rl.auto-logout'); dispatchEvent(new CustomEvent('rl.auto-logout'))
}, this.autoLogout() * 60000); , this.autoLogout() * 60000);
} }
}); };
addEventListener('rl.auto-logout-refresh', refresh);
Events.pub('rl.auto-logout-refresh'); refresh();
} }
} }

View file

@ -19,6 +19,7 @@
@import "../../vendors/bootstrap/less/buttons.less"; @import "../../vendors/bootstrap/less/buttons.less";
@import "../../vendors/bootstrap/less/button-groups.less"; @import "../../vendors/bootstrap/less/button-groups.less";
@import "../../vendors/bootstrap/less/alerts.less";
@import "../../vendors/bootstrap/less/navs.less"; @import "../../vendors/bootstrap/less/navs.less";
@ -80,7 +81,5 @@
@import "SettingsThemes.less"; @import "SettingsThemes.less";
@import "SettingsFilters.less"; @import "SettingsFilters.less";
@import "Cmd.less";
@import "Animations.less"; @import "Animations.less";
@import "_End.less"; @import "_End.less";

View file

@ -73,11 +73,13 @@ html {
html.rl-anim { html.rl-anim {
.rl-animated-inited { .b-login-content {
opacity: 1; .alertError {
.transition(opacity 0.5s linear); display: block;
opacity: 1;
&.rl-animated-hidden { .transition(opacity 0.5s linear);
}
.alertError[hidden] {
opacity: 0; opacity: 0;
} }
} }

View file

@ -1,82 +0,0 @@
.rl-cmd {
position: absolute;
bottom: 0;
left: 0;
right: 0;
top: auto;
height: 0;
z-index: 10000;
background: rgba(0, 0, 0, .85);
border-top: 1px solid #000;
overflow: hidden;
font-family: monospace;
.transition(height 0.1s ease-out);
&.opened {
height: 250px;
}
.rl-cmd-clr-error {
color: #CD3131;
}
.rl-cmd-clr-info {
color: #BFBF00;
}
.rl-cmd-clr-success {
color: #31FF40;
}
.rl-cmd-wrp {
position: relative;
height: 100%;
}
.rl-cmd-input-helper {
color: #666;
}
.rl-cmd-input-prefix {
color: #31FF40;
display: inline-block;
}
.rl-cmd-input-wrp {
position: absolute;
bottom: 0;
left: 10px;
right: 10px;
}
.rl-cmd-input {
background: none;
border: none;
color: white;
display: inline-block;
width: calc(~'100% - 30px');
font-family: monospace;
&:focus{
background: none;
border: none;
}
}
.rl-cmd-history {
color: white;
font-family: monospace;
position: absolute;
top: 10px;
bottom: 60px;
left: 10px;
right: -30px;
overflow: hidden;
overflow-x: hidden;
overflow-y: auto;
}
}

View file

@ -649,20 +649,12 @@ html .messageItem {
.buttonUp, .buttonUp { .buttonUp, .buttonUp {
display: none !important; display: none !important;
} }
&.scroller-shadow-top .buttonUp {
display: inline-block !important;
}
} }
html.rl-desktop .messageItem { html.rl-desktop .messageItem {
.buttonUp, .buttonFull { .buttonUp, .buttonFull {
display: none !important; display: none !important;
} }
&:hover {
&.scroller-shadow-top .buttonUp, .buttonFull {
display: inline-block !important;
}
}
} }
html.rl-message-fullscreen .messageItem { html.rl-message-fullscreen .messageItem {
@ -675,7 +667,4 @@ html.rl-message-fullscreen .messageItem {
.buttonUp { .buttonUp {
display: none !important; display: none !important;
} }
&.scroller-shadow-top .buttonUp {
display: inline-block !important;
}
} }

View file

@ -43,7 +43,6 @@ import MessageStore from 'Stores/User/Message';
import Remote from 'Remote/User/Ajax'; import Remote from 'Remote/User/Ajax';
import * as Settings from 'Storage/Settings'; import * as Settings from 'Storage/Settings';
import * as Events from 'Common/Events';
import { ComposeAttachmentModel } from 'Model/ComposeAttachment'; import { ComposeAttachmentModel } from 'Model/ComposeAttachment';
@ -164,7 +163,9 @@ class ComposePopupView extends AbstractViewNext {
this.savedTime = ko.observable(0); this.savedTime = ko.observable(0);
this.savedTimeText = ko.computed(() => this.savedTimeText = ko.computed(() =>
0 < this.savedTime() ? i18n('COMPOSE/SAVED_TIME', { 'TIME': momentorFormat(this.savedTime() - 1, 'LT') }) : '' this.savedTime()
? i18n('COMPOSE/SAVED_TIME', { 'TIME': this.savedTime().format('LT') })
: ''
); );
this.emptyToError = ko.observable(false); this.emptyToError = ko.observable(false);
@ -300,7 +301,7 @@ class ComposePopupView extends AbstractViewNext {
this.sendMessageResponse = this.sendMessageResponse.bind(this); this.sendMessageResponse = this.sendMessageResponse.bind(this);
this.saveMessageResponse = this.saveMessageResponse.bind(this); this.saveMessageResponse = this.saveMessageResponse.bind(this);
Events.sub('interval.2m', () => { setInterval(() => {
if ( if (
this.modalVisibility() && this.modalVisibility() &&
!FolderStore.draftFolderNotEnabled() && !FolderStore.draftFolderNotEnabled() &&
@ -312,7 +313,7 @@ class ComposePopupView extends AbstractViewNext {
) { ) {
this.saveCommand(); this.saveCommand();
} }
}); }, 120000);
this.showCc.subscribe(this.resizerTrigger); this.showCc.subscribe(this.resizerTrigger);
this.showBcc.subscribe(this.resizerTrigger); this.showBcc.subscribe(this.resizerTrigger);
@ -326,7 +327,7 @@ class ComposePopupView extends AbstractViewNext {
// debounce // debounce
var d, fn = this.tryToClosePopup.bind(this); var d, fn = this.tryToClosePopup.bind(this);
this.tryToClosePopup = ()=>{ this.tryToClosePopup = ()=>{
d && clearTimeout(d); clearTimeout(d);
d = setTimeout(fn, 200); d = setTimeout(fn, 200);
}; };
@ -667,7 +668,7 @@ class ComposePopupView extends AbstractViewNext {
this.draftFolder(oData.Result.NewFolder); this.draftFolder(oData.Result.NewFolder);
this.draftUid(oData.Result.NewUid); this.draftUid(oData.Result.NewUid);
this.savedTime(Math.round(new Date().getTime() / 1000)); this.savedTime(new Date);
if (this.bFromDraft) { if (this.bFromDraft) {
setFolderHash(this.draftFolder(), ''); setFolderHash(this.draftFolder(), '');
@ -722,15 +723,9 @@ class ComposePopupView extends AbstractViewNext {
} }
converSignature(signature) { converSignature(signature) {
let limit = 10,
fromLine = '';
const moments = [],
momentRegx = /{{MOMENT:([^}]+)}}/g;
signature = signature.replace(/[\r]/g, ''); signature = signature.replace(/[\r]/g, '');
fromLine = this.oLastMessage ? this.emailArrayToStringLineHelper(this.oLastMessage.from, true) : ''; let fromLine = this.oLastMessage ? this.emailArrayToStringLineHelper(this.oLastMessage.from, true) : '';
if (fromLine) { if (fromLine) {
signature = signature.replace(/{{FROM-FULL}}/g, fromLine); signature = signature.replace(/{{FROM-FULL}}/g, fromLine);
@ -748,36 +743,14 @@ class ComposePopupView extends AbstractViewNext {
signature = signature.replace(/{{FROM-FULL}}/g, ''); signature = signature.replace(/{{FROM-FULL}}/g, '');
if (signature.includes('{{DATE}}')) { if (signature.includes('{{DATE}}')) {
signature = signature.replace(/{{DATE}}/g, momentorFormat(0, 'llll')); signature = signature.replace(/{{DATE}}/g, new Date().format('LLLL'));
} }
if (signature.includes('{{TIME}}')) { if (signature.includes('{{TIME}}')) {
signature = signature.replace(/{{TIME}}/g, momentorFormat(0, 'LT')); signature = signature.replace(/{{TIME}}/g, new Date().format('LT'));
} }
if (signature.includes('{{MOMENT:')) {
try {
let match = null;
while (null !== (match = momentRegx.exec(signature))) {
// eslint-disable-line no-cond-assign
if (match && match[0] && match[1]) {
moments.push([match[0], match[1]]);
}
limit -= 1; signature = signature.replace(/{{MOMENT:[^}]+}}/g, '');
if (0 === limit) {
break;
}
}
if (moments) {
moments.forEach(data => {
signature = signature.replace(data[0], momentorFormat(0, data[1]));
});
}
signature = signature.replace(/{{MOMENT:[^}]+}}/g, '');
} catch (e) {} // eslint-disable-line no-empty
}
return signature; return signature;
} }
@ -1244,11 +1217,10 @@ class ComposePopupView extends AbstractViewNext {
return false; return false;
}); });
Events.sub('window.resize.real', this.resizerTrigger);
var d, o = this; var d, o = this;
Events.sub('window.resize.real', ()=>{ addEventListener('resize.real', ()=>{
// debounce // debounce
d && clearTimeout(d); clearTimeout(d);
d = setTimeout(o.resizerTrigger, 50); d = setTimeout(o.resizerTrigger, 50);
}); });

View file

@ -65,7 +65,7 @@ class FolderSystemPopupView extends AbstractViewNext {
}, },
fSaveSystemFolders = ()=>{ fSaveSystemFolders = ()=>{
// debounce // debounce
d && clearTimeout(d); clearTimeout(d);
d = setTimeout(()=>{ d = setTimeout(()=>{
fSetSystemFolders(); fSetSystemFolders();
Remote.saveSystemFolders(()=>{}, { Remote.saveSystemFolders(()=>{}, {

View file

@ -44,7 +44,7 @@ class PluginPopupView extends AbstractViewNext {
var d, fn = this.tryToClosePopup.bind(this); var d, fn = this.tryToClosePopup.bind(this);
this.tryToClosePopup = ()=>{ this.tryToClosePopup = ()=>{
// debounce // debounce
d && clearTimeout(d); clearTimeout(d);
d = setTimeout(fn, 200); d = setTimeout(fn, 200);
}; };
} }

View file

@ -7,7 +7,6 @@ import MessageStore from 'Stores/User/Message';
import { Capa, KeyState } from 'Common/Enums'; import { Capa, KeyState } from 'Common/Enums';
import { settings } from 'Common/Links'; import { settings } from 'Common/Links';
import * as Events from 'Common/Events';
import * as Settings from 'Storage/Settings'; import * as Settings from 'Storage/Settings';
import { getApp } from 'Helper/Apps/User'; import { getApp } from 'Helper/Apps/User';
@ -40,12 +39,12 @@ class AbstractSystemDropDownUserView extends AbstractViewNext {
this.addAccountClick = this.addAccountClick.bind(this); this.addAccountClick = this.addAccountClick.bind(this);
Events.sub('audio.stop', () => AppStore.currentAudio('')); addEventListener('audio.stop', () => AppStore.currentAudio(''));
Events.sub('audio.start', (name) => AppStore.currentAudio(name)); addEventListener('audio.start', e => AppStore.currentAudio(e.detail));
} }
stopPlay() { stopPlay() {
Events.pub('audio.api.stop'); dispatchEvent(new CustomEvent('audio.api.stop'));
} }
accountClick(account, event) { accountClick(account, event) {

View file

@ -19,7 +19,6 @@ import { computedPagenatorHelper, draggablePlace, friendlySize } from 'Common/Ut
import { mailBox, append } from 'Common/Links'; import { mailBox, append } from 'Common/Links';
import { Selector } from 'Common/Selector'; import { Selector } from 'Common/Selector';
import * as Events from 'Common/Events';
import { i18n, initOnStartOrLangChange } from 'Common/Translator'; import { i18n, initOnStartOrLangChange } from 'Common/Translator';
@ -238,15 +237,17 @@ class MessageListMailBoxUserView extends AbstractViewNext {
this.goToUpUpOrDownDown(v); this.goToUpUpOrDownDown(v);
}); });
Events.sub('mailbox.message-list.selector.go-down', (select) => { addEventListener('mailbox.message-list.selector.go-down', e => {
this.selector.goDown(select); this.selector.goDown(e.detail);
}); });
Events.sub('mailbox.message-list.selector.go-up', (select) => { addEventListener('mailbox.message-list.selector.go-up', e => {
this.selector.goUp(select); this.selector.goUp(e.detail);
}); });
Events.sub('mailbox.message.show', (sFolder, sUid) => { addEventListener('mailbox.message.show', e => {
const sFolder = e.detail.Folder, sUid = e.detail.Uid;
const message = this.messageList().find( const message = this.messageList().find(
item => item && sFolder === item.folderFullNameRaw && sUid === item.uid item => item && sFolder === item.folderFullNameRaw && sUid === item.uid
); );
@ -781,7 +782,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
initShortcuts() { initShortcuts() {
key('enter', KeyState.MessageList, () => { key('enter', KeyState.MessageList, () => {
if (this.message() && this.useAutoSelect()) { if (this.message() && this.useAutoSelect()) {
Events.pub('mailbox.message-view.toggle-full-screen'); dispatchEvent(new CustomEvent('mailbox.message-view.toggle-full-screen'));
return false; return false;
} }

View file

@ -27,7 +27,6 @@ import {
} from 'Common/Utils'; } from 'Common/Utils';
import Audio from 'Common/Audio'; import Audio from 'Common/Audio';
import * as Events from 'Common/Events';
import { i18n } from 'Common/Translator'; import { i18n } from 'Common/Translator';
import { attachmentDownload } from 'Common/Links'; import { attachmentDownload } from 'Common/Links';
@ -328,7 +327,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
() => MessageStore.messageListCompleteLoadingThrottle() || MessageStore.messageLoadingThrottle() () => MessageStore.messageListCompleteLoadingThrottle() || MessageStore.messageLoadingThrottle()
); );
Events.sub('mailbox.message-view.toggle-full-screen', () => { addEventListener('mailbox.message-view.toggle-full-screen', () => {
this.toggleFullScreen(); this.toggleFullScreen();
}); });
@ -350,12 +349,16 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
@command((self) => !self.messageListAndMessageViewLoading()) @command((self) => !self.messageListAndMessageViewLoading())
goUpCommand() { goUpCommand() {
Events.pub('mailbox.message-list.selector.go-up', [Layout.NoPreview === this.layout() ? !!this.message() : true]); dispatchEvent(new CustomEvent('mailbox.message-list.selector.go-up',
{detail:Layout.NoPreview === this.layout() ? !!this.message() : true}
));
} }
@command((self) => !self.messageListAndMessageViewLoading()) @command((self) => !self.messageListAndMessageViewLoading())
goDownCommand() { goDownCommand() {
Events.pub('mailbox.message-list.selector.go-down', [Layout.NoPreview === this.layout() ? !!this.message() : true]); dispatchEvent(new CustomEvent('mailbox.message-list.selector.go-up',
{detail:Layout.NoPreview === this.layout() ? !!this.message() : true}
));
} }
detectDomBackgroundColor(dom) { detectDomBackgroundColor(dom) {
@ -537,8 +540,8 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
this.message.subscribe(fCheckHeaderHeight); this.message.subscribe(fCheckHeaderHeight);
var t; var t;
Events.sub( addEventListener(
'window.resize', 'resize',
()=>{ ()=>{
// throttle // throttle
if (!t) { if (!t) {

View file

@ -168,7 +168,7 @@
Date.prototype.fromNow = function() { Date.prototype.fromNow = function() {
let format, let format,
seconds = ((new Date()).getTime() - this.getTime()) / 1000, seconds = ((new Date()).getTime() - this.getTime()) / 1000,
str = locale.relativeTime[0 < seconds ? 'future' : 'past']; str = locale.relativeTime[0 < seconds ? 'past' : 'future'];
seconds = Math.abs(seconds); seconds = Math.abs(seconds);
if (60 > seconds) { if (60 > seconds) {
format = 's'; format = 's';

View file

@ -2844,49 +2844,6 @@ NewThemeLink IncludeCss LoadingDescriptionEsc TemplatesLink LangLink IncludeBack
return $iResult; return $iResult;
} }
/**
* @throws \MailSo\Base\Exceptions\Exception
*/
public function DoAccountsCounts() : array
{
$oAccount = $this->getAccountFromToken();
$bComplete = true;
$aCounts = array();
if ($this->GetCapa(false, false, Enumerations\Capa::ADDITIONAL_ACCOUNTS, $oAccount))
{
$iLimit = 7;
$aAccounts = $this->GetAccounts($oAccount);
if ($aAccounts)
{
if ($iLimit > \count($aAccounts))
{
$aAccounts = \array_slice($aAccounts, 0, $iLimit);
}
else
{
$bComplete = false;
}
foreach ($aAccounts as $sEmail => $sHash)
{
$aCounts[] = array(\MailSo\Base\Utils::IdnToUtf8($sEmail),
$oAccount->Email() === $sEmail ? 0 : $this->getAccountUnreadCountFromHash($sHash));
}
}
}
else
{
$aCounts[] = array(\MailSo\Base\Utils::IdnToUtf8($oAccount->Email()), 0);
}
return $this->DefaultResponse(__FUNCTION__, array(
'Complete' => $bComplete,
'Counts' => $aCounts
));
}
public function ClearSignMeData(Model\Account $oAccount) : void public function ClearSignMeData(Model\Account $oAccount) : void
{ {
if ($oAccount) if ($oAccount)

View file

@ -235,7 +235,7 @@ nl_NL:
ATTACHMENTS_ERROR_DESC: "Waarschuwing! Nog niet alle bijlagen zijn klaar met uploaden" ATTACHMENTS_ERROR_DESC: "Waarschuwing! Nog niet alle bijlagen zijn klaar met uploaden"
ATTACHMENTS_UPLOAD_ERROR_DESC: "Toevoegen van bijlage(n) is nog niet gereed" ATTACHMENTS_UPLOAD_ERROR_DESC: "Toevoegen van bijlage(n) is nog niet gereed"
BUTTON_REQUEST_READ_RECEIPT: "Leesbevestiging vragen" BUTTON_REQUEST_READ_RECEIPT: "Leesbevestiging vragen"
BUTTON_MARK_AS_IMPORTANT: "Marker als belangrijk" BUTTON_MARK_AS_IMPORTANT: "Markeer als belangrijk"
BUTTON_OPEN_PGP: "OpenPGP (allen bij Platte Tekst)" BUTTON_OPEN_PGP: "OpenPGP (allen bij Platte Tekst)"
BUTTON_REQUEST_DSN: "Ontvangstbevestiging vragen" BUTTON_REQUEST_DSN: "Ontvangstbevestiging vragen"
POPUPS_WELCOME_PAGE: POPUPS_WELCOME_PAGE:

View file

@ -18,11 +18,11 @@
</div> </div>
</div> </div>
</div> </div>
<div class="b-content" data-bind="nano: true, scrollerShadows: true"> <div class="b-content">
<div class="content g-scrollbox" data-scroller-shadows-content> <div class="content g-scrollbox">
<div class="content-wrapper"> <div class="content-wrapper">
<div id="rl-settings-subscreen" class="b-settings-content" style="position: relative; z-index: 2"></div> <div id="rl-settings-subscreen" class="b-settings-content" style="position: relative; z-index: 2"></div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -1,10 +0,0 @@
<div class="rl-cmd" data-bind="css: {opened: opened}, click: function() { focused(true) }">
<div class="rl-cmd-wrp">
<div class="rl-cmd-history"><div class="rl-cmd-history-data"></div></div>
<div class="rl-cmd-input-wrp">
<div class="rl-cmd-input-helper" data-bind="text: cmdHelper"></div>
<div class="rl-cmd-input-prefix">#</div>
<input type="text" class="rl-cmd-input" data-bind="textInput: cmd, hasFocus: focused, onEnter: onEnter, onKeyDown: onKeyDown, onEsc: onEsc, onTab: onTab" />
</div>
</div>
</div>

View file

@ -12,7 +12,7 @@
<span class="desc" data-bind="text: loginDescription"></span> <span class="desc" data-bind="text: loginDescription"></span>
</div> </div>
{{INCLUDE/AfterLogo/PLACE}} {{INCLUDE/AfterLogo/PLACE}}
<div class="alert alertError" data-bind="visibleAnimated: '' !== submitError()"> <div class="alert alertError" data-bind="visibleAnimated: '' !== submitError()" hidden="">
<button type="button" class="close" data-bind="click: function () { submitError('') }">&times;</button> <button type="button" class="close" data-bind="click: function () { submitError('') }">&times;</button>
<span data-bind="text: submitError"></span> <span data-bind="text: submitError"></span>
<div data-bind="visible: '' !== submitErrorAddidional()"> <div data-bind="visible: '' !== submitErrorAddidional()">

View file

@ -10,8 +10,8 @@
<i class="icon-address-book"></i> <i class="icon-address-book"></i>
</a> </a>
</div> </div>
<div class="b-content opacity-on-panel-disabled" data-bind="visible: allowFolders, nano: true, scrollerShadows: true, css: {'inbox-is-starred': isInboxStarred}"> <div class="b-content opacity-on-panel-disabled" data-bind="visible: allowFolders, css: {'inbox-is-starred': isInboxStarred}">
<div class="content g-scrollbox" data-scroller-shadows-content> <div class="content g-scrollbox">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="b-folders-system" data-bind="template: { name: 'MailFolderListSystemItem', foreach: folderListSystem }"></div> <div class="b-folders-system" data-bind="template: { name: 'MailFolderListSystemItem', foreach: folderListSystem }"></div>
<hr class="b-list-delimiter" /> <hr class="b-list-delimiter" />
@ -36,4 +36,4 @@
</a> </a>
</div> </div>
</div> </div>
</div> </div>

View file

@ -166,8 +166,8 @@
</div> </div>
<div class="line-loading e-strip-animation" data-bind="visible: messageListCompleteLoadingThrottle"></div> <div class="line-loading e-strip-animation" data-bind="visible: messageListCompleteLoadingThrottle"></div>
<div class="mainDelimiter toolbarDelimiter"></div> <div class="mainDelimiter toolbarDelimiter"></div>
<div class="b-content" data-bind="nano: true, scrollerShadows: true, initDom: dragOverBodyArea"> <div class="b-content" data-bind="initDom: dragOverBodyArea">
<div class="content g-scrollbox" data-scroller-shadows-content> <div class="content g-scrollbox">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="listThreadUidDesc" data-bind="visible: '' !== messageListEndThreadUid(), click: cancelThreadUid"> <div class="listThreadUidDesc" data-bind="visible: '' !== messageListEndThreadUid(), click: cancelThreadUid">
<i class="icon-left" data-bind="click: cancelThreadUid"></i> <i class="icon-left" data-bind="click: cancelThreadUid"></i>
@ -215,4 +215,4 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>

View file

@ -16,7 +16,7 @@
</span> </span>
</div> </div>
<div class="dateParent actionHandle dragHandle"> <div class="dateParent actionHandle dragHandle">
<span class="date" data-moment-format="SHORT" data-moment-format-title="FULL" data-bind="moment: dateTimeStampInUTC"></span> <time class="date" data-moment-format="SHORT" data-moment-format-title="FULL" data-bind="moment: dateTimeStampInUTC"></time>
</div> </div>
<div class="threadsParent" data-bind="visible: 1 < threadsLen()"> <div class="threadsParent" data-bind="visible: 1 < threadsLen()">
<span class="threads-len"> <span class="threads-len">
@ -46,4 +46,4 @@
<span class="subject-prefix" data-bind="text: subjectPrefix"></span><span class="subject-suffix" data-bind="text: subjectSuffix"></span> <span class="subject-prefix" data-bind="text: subjectPrefix"></span><span class="subject-suffix" data-bind="text: subjectSuffix"></span>
</div> </div>
</div> </div>
</div> </div>

View file

@ -5,7 +5,7 @@
<div class="delimiter"></div> <div class="delimiter"></div>
<div class="wrapper"> <div class="wrapper">
<div class="dateParent actionHandle dragHandle"> <div class="dateParent actionHandle dragHandle">
<span class="date" data-moment-format="SHORT" data-moment-format-title="FULL" data-bind="moment: dateTimeStampInUTC"></span> <time class="date" data-moment-format="SHORT" data-moment-format-title="FULL" data-bind="moment: dateTimeStampInUTC"></time>
</div> </div>
<div class="threadsParent" data-bind="visible: 1 < threadsLen()"> <div class="threadsParent" data-bind="visible: 1 < threadsLen()">
<span class="threads-len"> <span class="threads-len">
@ -47,4 +47,4 @@
</div> </div>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</div> </div>

View file

@ -247,7 +247,7 @@
</span> </span>
</span> </span>
<span data-bind="visible: 0 < viewTimeStamp()"> <span data-bind="visible: 0 < viewTimeStamp()">
(<span class="date" data-moment-format="FULL" data-bind="moment: viewTimeStamp"></span>) (<time class="date" data-moment-format="FULL" data-bind="moment: viewTimeStamp"></time>)
</span> </span>
</div> </div>
<div class="informationShortWrp"> <div class="informationShortWrp">
@ -296,17 +296,17 @@
<tr data-bind="visible: 0 < viewTimeStamp()"> <tr data-bind="visible: 0 < viewTimeStamp()">
<td><span class="i18n uiLabel" data-i18n="MESSAGE/LABEL_DATE"></span></td> <td><span class="i18n uiLabel" data-i18n="MESSAGE/LABEL_DATE"></span></td>
<td> <td>
<span class="date uiLabelValue" data-moment-format="FULL" data-bind="moment: viewTimeStamp"></span> <time class="date uiLabelValue" data-moment-format="FULL" data-bind="moment: viewTimeStamp"></time>
&nbsp; &nbsp;
(<span class="date uiLabelValue" data-moment-format="FROMNOW" data-bind="moment: viewTimeStamp"></span>) (<time class="date uiLabelValue" data-moment-format="FROMNOW" data-bind="moment: viewTimeStamp"></time>)
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
</div> </div>
</div> </div>
<div class="messageItem fixIndex" data-bind="css: viewLineAsCss(), nano: true, scrollerShadows: true, attr: {'style': 'top:' + viewBodyTopValue() + 'px' }"> <div class="messageItem fixIndex" data-bind="css: viewLineAsCss(), attr: {'style': 'top:' + viewBodyTopValue() + 'px' }">
<div class="content g-scrollbox" tabindex="0" data-scroller-shadows-content data-bind="hasfocus: messageDomFocused, css: { 'focused': messageDomFocused }, <div class="content g-scrollbox" tabindex="0" data-bind="hasfocus: messageDomFocused, css: { 'focused': messageDomFocused },
style: {'background-color': messageLoadingThrottle() ? '' : bodyBackgroundColor()}"> style: {'background-color': messageLoadingThrottle() ? '' : bodyBackgroundColor()}">
<div class="content-wrapper"> <div class="content-wrapper">

View file

@ -185,8 +185,8 @@
</div> </div>
</div> </div>
<div class="attachmentAreaParent b-content" style="height: 200px; min-height: 200px" data-bind="nano: true, scrollerShadows: true, visible: attachmentsPlace, initResizeTrigger: [resizer(), 200, 57]"> <div class="attachmentAreaParent b-content" style="height: 200px; min-height: 200px" data-bind="visible: attachmentsPlace, initResizeTrigger: [resizer(), 200, 57]">
<div class="content g-scrollbox" data-scroller-shadows-content> <div class="content g-scrollbox">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="b-attachment-place" data-bind="visible: addAttachmentEnabled() && dragAndDropEnabled() && dragAndDropVisible(), initDom: composeUploaderDropPlace, css: {'dragAndDropOver': dragAndDropOver}"> <div class="b-attachment-place" data-bind="visible: addAttachmentEnabled() && dragAndDropEnabled() && dragAndDropVisible(), initDom: composeUploaderDropPlace, css: {'dragAndDropOver': dragAndDropOver}">
<span class="i18n" data-i18n="COMPOSE/ATTACH_DROP_FILES_DESC"></span> <span class="i18n" data-i18n="COMPOSE/ATTACH_DROP_FILES_DESC"></span>

View file

@ -71,8 +71,8 @@
<div class="b-list-toolbar"> <div class="b-list-toolbar">
<input type="text" class="i18n span3 e-search" placeholder="Search" autocorrect="off" autocapitalize="off" data-i18n="[placeholder]CONTACTS/SEARCH_INPUT_PLACEHOLDER" data-bind="value: search" /> <input type="text" class="i18n span3 e-search" placeholder="Search" autocorrect="off" autocapitalize="off" data-i18n="[placeholder]CONTACTS/SEARCH_INPUT_PLACEHOLDER" data-bind="value: search" />
</div> </div>
<div class="b-list-content g-ui-user-select-none" data-bind="nano: true, scrollerShadows: true, css: {'hideContactListCheckbox': !useCheckboxesInList()}"> <div class="b-list-content g-ui-user-select-none" data-bind="css: {'hideContactListCheckbox': !useCheckboxesInList()}">
<div class="content g-scrollbox" data-scroller-shadows-content> <div class="content g-scrollbox">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="listClear" data-bind="visible: viewClearSearch() && '' !== search()"> <div class="listClear" data-bind="visible: viewClearSearch() && '' !== search()">
<span class="g-ui-link i18n" data-i18n="CONTACTS/CLEAR_SEARCH" data-bind="command: clearCommand"></span> <span class="g-ui-link i18n" data-i18n="CONTACTS/CLEAR_SEARCH" data-bind="command: clearCommand"></span>
@ -167,8 +167,8 @@
</button> </button>
</div> </div>
</div> </div>
<div class="b-view-content" data-bind="nano: true, scrollerShadows: true, css: {'read-only': viewReadOnly}"> <div class="b-view-content" data-bind="css: {'read-only': viewReadOnly}">
<div class="content g-scrollbox" data-scroller-shadows-content> <div class="content g-scrollbox">
<div class="content-wrapper"> <div class="content-wrapper">
<div class="b-contact-view-desc" data-bind="visible: emptySelection"> <div class="b-contact-view-desc" data-bind="visible: emptySelection">
<span class="i18n" data-i18n="CONTACTS/CONTACT_VIEW_DESC"></span> <span class="i18n" data-i18n="CONTACTS/CONTACT_VIEW_DESC"></span>

View file

@ -30,7 +30,6 @@
</span> </span>
</div> </div>
</div> </div>
<!--<div data-bind="json: $data"></div>-->
</div> </div>
</div> </div>
<div class="control-group"> <div class="control-group">

View file

@ -18,11 +18,11 @@
</a> </a>
</div> </div>
</div> </div>
<div class="b-content" data-bind="nano: true, scrollerShadows: true"> <div class="b-content">
<div class="content g-scrollbox" data-scroller-shadows-content> <div class="content g-scrollbox">
<div class="content-wrapper"> <div class="content-wrapper">
<div id="rl-settings-subscreen" class="b-settings-content" style="position: relative; z-index: 2"></div> <div id="rl-settings-subscreen" class="b-settings-content" style="position: relative; z-index: 2"></div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>