diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c2cda24724..b712239f10 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ 1. Install node.js - `https://nodejs.org/download/` 2. Install yarn - `https://yarnpkg.com/en/docs/install` 3. Install gulp - `npm install gulp -g` -4. Fork snappymail - `https://github.com/the-djmaze/snappymail/issues/new#fork-destination-box` +4. Fork snappymail from https://github.com/the-djmaze/snappymail 5. Clone snappymail - `git clone git@github.com:USERNAME/snappymail.git snappymail` 6. `cd snappymail` 7. Install install all dependencies - `yarn install` diff --git a/dev/App/User.js b/dev/App/User.js index 82f319fa22..2d0802b088 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -38,7 +38,6 @@ import { } from 'Common/Cache'; import { - userBackground, mailBox, root, openPgpWorkerJs, @@ -81,6 +80,8 @@ import { ComposePopupView } from 'View/Popup/Compose'; import { FolderSystemPopupView } from 'View/Popup/FolderSystem'; import { AskPopupView } from 'View/Popup/Ask'; +import { timeToNode } from 'Common/Momentor'; + // Every 5 minutes const refreshFolders = 300000; @@ -110,16 +111,6 @@ class AppUser extends AbstractApp { lastTime = currentTime; }, interval); - if (SettingsGet('UserBackgroundHash')) { - setTimeout(() => { - const img = userBackground(SettingsGet('UserBackgroundHash')); - if (img) { - $htmlCL.add('UserBackground'); - doc.body.style.backgroundImage = "url("+img+")"; - } - }, 1000); - } - const fn = (ev=>$htmlCL.toggle('rl-ctrl-key-pressed', ev.ctrlKey)).debounce(500); ['keydown','keyup'].forEach(t => doc.addEventListener(t, fn)); @@ -1020,7 +1011,14 @@ class AppUser extends AbstractApp { this.hideLoading(); } - setInterval(() => dispatchEvent(new CustomEvent('reload-time')), 60000); + setInterval(this.reloadTime(), 60000); + } + + reloadTime() + { + setTimeout(() => + doc.querySelectorAll('[data-bind*="moment:"]').forEach(element => timeToNode(element)) + , 1) } showMessageComposer(params = []) diff --git a/dev/Common/Links.js b/dev/Common/Links.js index dc726351f4..b5edfa99f9 100644 --- a/dev/Common/Links.js +++ b/dev/Common/Links.js @@ -70,14 +70,6 @@ export function change(email) { return serverRequest('Change') + encodeURIComponent(email) + '/'; } -/** - * @param {string} hash - * @returns {string} - */ -export function userBackground(hash) { - return serverRequestRaw('UserBackground', hash); -} - /** * @param {string} lang * @param {boolean} isAdmin diff --git a/dev/Common/Momentor.js b/dev/Common/Momentor.js index 6da0a88cea..aa6efed35a 100644 --- a/dev/Common/Momentor.js +++ b/dev/Common/Momentor.js @@ -1,4 +1,3 @@ -import { doc } from 'Common/Globals'; import { i18n } from 'Common/Translator'; export function timestampToString(timeStampInUTC, formatStr) { @@ -53,8 +52,3 @@ export function timeToNode(element, time) { console.error(e); } } - -addEventListener('reload-time', () => setTimeout(() => - doc.querySelectorAll('[data-bind*="moment:"]').forEach(element => timeToNode(element)) - , 1) -); diff --git a/dev/Common/Selector.js b/dev/Common/Selector.js index 109b301359..bd01d203ad 100644 --- a/dev/Common/Selector.js +++ b/dev/Common/Selector.js @@ -1,6 +1,15 @@ import ko from 'ko'; import { isArray } from 'Common/Utils'; +/* + oCallbacks: + ItemSelect + MiddleClick + AutoSelect + ItemGetUid + UpOrDown +*/ + export class Selector { /** * @param {koProperty} koList @@ -209,11 +218,9 @@ export class Selector { itemSelected(item) { if (this.isListChecked()) { - if (!item) { - (this.oCallbacks.onItemSelect || (()=>{}))(item || null); - } + item || (this.oCallbacks.ItemSelect || (()=>{}))(null); } else if (item) { - (this.oCallbacks.onItemSelect || (()=>{}))(item); + (this.oCallbacks.ItemSelect || (()=>{}))(item); } } @@ -226,20 +233,32 @@ export class Selector { this.oContentScrollable = contentScrollable; if (contentScrollable) { + let getItem = selector => { + let el = event.target.closestWithin(selector, contentScrollable); + return el ? ko.dataFor(el) : null; + }; + contentScrollable.addEventListener('click', event => { let el = event.target.closestWithin(this.sItemSelector, contentScrollable); el && this.actionClick(ko.dataFor(el), event); - el = event.target.closestWithin(this.sItemCheckedSelector, contentScrollable); - if (el) { - const item = ko.dataFor(el); + const item = getItem(this.sItemCheckedSelector); + if (item) { + if (event.shiftKey) { + this.actionClick(item, event); + } else { + this.focusedItem(item); + item.checked(!item.checked()); + } + } + }); + + contentScrollable.addEventListener('auxclick', event => { + if (1 == event.button) { + const item = getItem(this.sItemSelector); if (item) { - if (event.shiftKey) { - this.actionClick(item, event); - } else { - this.focusedItem(item); - item.checked(!item.checked()); - } + this.focusedItem(item); + (this.oCallbacks.MiddleClick || (()=>{}))(item); } } }); @@ -271,7 +290,7 @@ export class Selector { * @returns {boolean} */ autoSelect() { - return !!(this.oCallbacks.onAutoSelect || (()=>true))(); + return !!(this.oCallbacks.AutoSelect || (()=>true))(); } /** @@ -281,7 +300,7 @@ export class Selector { getItemUid(item) { let uid = ''; - const getItemUidCallback = this.oCallbacks.onItemGetUid || null; + const getItemUidCallback = this.oCallbacks.ItemGetUid || null; if (getItemUidCallback && item) { uid = getItemUidCallback(item); } @@ -312,7 +331,7 @@ export class Selector { } else if (++i < listLen) { result = list[i]; } - result || (this.oCallbacks.onUpUpOrDownDown || (()=>true))('ArrowUp' === sEventKey); + result || (this.oCallbacks.UpOrDown || (()=>true))('ArrowUp' === sEventKey); } else if ('Home' === sEventKey) { result = list[0]; } else if ('End' === sEventKey) { diff --git a/dev/Common/Translator.js b/dev/Common/Translator.js index ba97282760..dd2d81bb6f 100644 --- a/dev/Common/Translator.js +++ b/dev/Common/Translator.js @@ -140,7 +140,7 @@ export function reload(admin, language) { // reload the data if (init()) { i18nToNodes(doc); - dispatchEvent(new CustomEvent('reload-time')); + admin || rl.app.reloadTime(); trigger(!trigger()); } script.remove(); diff --git a/dev/Model/Message.js b/dev/Model/Message.js index a5b4b0dd13..9e31a25157 100644 --- a/dev/Model/Message.js +++ b/dev/Model/Message.js @@ -524,13 +524,6 @@ export class MessageModel extends AbstractModel { } } - storeDataInDom() { - if (this.body) { - this.body.rlIsHtml = !!this.isHtml(); - this.body.rlHasImages = !!this.hasImages(); - } - } - fetchDataFromDom() { if (this.body) { this.isHtml(!!this.body.rlIsHtml); diff --git a/dev/Settings/User/Themes.js b/dev/Settings/User/Themes.js index bc5d9ee69c..2a0b825311 100644 --- a/dev/Settings/User/Themes.js +++ b/dev/Settings/User/Themes.js @@ -2,9 +2,9 @@ import ko from 'ko'; import { SaveSettingsStep, UploadErrorCode, Capa } from 'Common/Enums'; import { changeTheme, convertThemeName } from 'Common/Utils'; -import { userBackground, themePreviewLink, serverRequest } from 'Common/Links'; +import { themePreviewLink, serverRequest } from 'Common/Links'; import { i18n } from 'Common/Translator'; -import { doc, $htmlCL, Settings } from 'Common/Globals'; +import { Settings } from 'Common/Globals'; import { ThemeStore } from 'Stores/Theme'; @@ -38,16 +38,6 @@ export class ThemesUserSettings { Theme: value }); }); - - this.background.hash.subscribe((value) => { - if (!value) { - $htmlCL.remove('UserBackground'); - doc.body.removeAttribute('style'); - } else { - $htmlCL.add('UserBackground'); - doc.body.style.backgroundImage = "url("+userBackground(value)+")"; - } - }); } onBuild() { diff --git a/dev/Stores/Theme.js b/dev/Stores/Theme.js index 3a11d63c9a..95f17f13a5 100644 --- a/dev/Stores/Theme.js +++ b/dev/Stores/Theme.js @@ -1,6 +1,7 @@ import ko from 'ko'; -import { $htmlCL, leftPanelDisabled, Settings, SettingsGet } from 'Common/Globals'; +import { doc, $htmlCL, leftPanelDisabled, Settings, SettingsGet } from 'Common/Globals'; import { isArray } from 'Common/Utils'; +import { serverRequestRaw } from 'Common/Links'; export const ThemeStore = { themes: ko.observableArray(), @@ -25,3 +26,13 @@ export const ThemeStore = { ThemeStore.theme = ko.observable('').extend({ limitedList: ThemeStore.themes }); ThemeStore.isMobile.subscribe(value => $htmlCL.toggle('rl-mobile', value)); + +ThemeStore.userBackgroundHash.subscribe(value => { + if (value) { + $htmlCL.add('UserBackground'); + doc.body.style.backgroundImage = "url("+serverRequestRaw('UserBackground', value)+")"; + } else { + $htmlCL.remove('UserBackground'); + doc.body.removeAttribute('style'); + } +}); diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js index 1a570831e7..f36fe51d61 100644 --- a/dev/Stores/User/Message.js +++ b/dev/Stores/User/Message.js @@ -2,7 +2,7 @@ import ko from 'ko'; import { Scope, Notification } from 'Common/Enums'; import { MessageSetAction } from 'Common/EnumsUser'; -import { doc, createElement, elementById } from 'Common/Globals'; +import { doc, $htmlCL, createElement, elementById } from 'Common/Globals'; import { isNonEmptyArray, pInt, pString, addObservablesTo, addSubscribablesTo } from 'Common/Utils'; import { plainToHtml } from 'Common/UtilsUser'; @@ -186,6 +186,8 @@ export const MessageUserStore = new class { } }, + listLoadingAnimation: value => $htmlCL.toggle('list-loading', value), + listLoading: value => this.listCompleteLoading(value || this.listIsNotCompleted()), @@ -220,7 +222,7 @@ export const MessageUserStore = new class { } }); - this.purgeMessageBodyCacheThrottle = this.purgeMessageBodyCache.throttle(30000); + this.purgeMessageBodyCache = this.purgeMessageBodyCache.throttle(30000); } purgeMessageBodyCache() { @@ -428,16 +430,12 @@ export const MessageUserStore = new class { ); } - setMessage(data, cached) { + setMessage(data, cached, oMessage) { let isNew = false, - body = null, json = data && data.Result, - id = '', - plain = '', - resultHtml = '', messagesDom = this.messagesBodiesDom(), selectedMessage = this.selectorMessageSelected(), - message = this.message(); + message = oMessage || this.message(); if ( json && @@ -447,7 +445,7 @@ export const MessageUserStore = new class { ) { const threads = message.threads(); if (message.uid !== json.Uid && 1 < threads.length && threads.includes(json.Uid)) { - message = MessageModel.reviveFromJson(json); + message = oMessage ? null : MessageModel.reviveFromJson(json); if (message) { message.threads(threads); MessageFlagsCache.initMessage(message); @@ -460,7 +458,7 @@ export const MessageUserStore = new class { } if (message && message.uid === json.Uid) { - this.messageError(''); + oMessage || this.messageError(''); if (cached) { delete json.IsSeen; @@ -475,7 +473,8 @@ export const MessageUserStore = new class { addRequestedMessage(message.folder, message.uid); if (messagesDom) { - id = 'rl-mgs-' + message.hash.replace(/[^a-zA-Z0-9]/g, ''); + let body = null, + id = 'rl-mgs-' + message.hash.replace(/[^a-zA-Z0-9]/g, ''); const textBody = elementById(id); if (textBody) { @@ -483,7 +482,9 @@ export const MessageUserStore = new class { message.fetchDataFromDom(); messagesDom.append(textBody); } else { - let isHtml = !!json.Html; + let isHtml = !!json.Html, + plain = '', + resultHtml = '
';
 						if (isHtml) {
 							resultHtml = json.Html.toString();
 							if (SettingsUserStore.removeColors()) {
@@ -508,8 +509,6 @@ export const MessageUserStore = new class {
 							} else {
 								resultHtml = '
' + resultHtml + '
'; } - } else { - resultHtml = '
' + resultHtml + '
'; } body = Element.fromHTML('