diff --git a/README.md b/README.md index e41b730ed..b3bf97bc9 100644 --- a/README.md +++ b/README.md @@ -81,29 +81,29 @@ Things might work in Edge 18, Firefox 50-62 and Chrome 54-68 due to one polyfill |js/* |1.14.0 |native | |----------- |--------: |--------: | -|admin.js |2.130.942 |1.007.370 | -|app.js |4.184.455 |2.676.306 | -|boot.js | 671.522 | 43.856 | -|libs.js | 647.614 | 316.969 | +|admin.js |2.130.942 | 973.239 | +|app.js |4.184.455 |2.640.205 | +|boot.js | 671.522 | 43.824 | +|libs.js | 647.614 | 316.970 | |polyfills.js | 325.834 | 0 | -|TOTAL |7.960.367 |4.044.501 | +|TOTAL |7.960.367 |3.974.238 | |js/min/* |1.14.0 |native |gzip 1.14 |gzip |brotli | |--------------- |--------: |--------: |--------: |--------: |--------: | -|admin.min.js | 252.147 | 138.101 | 73.657 | 40.104 | 34.210 | -|app.min.js | 511.202 | 360.198 |140.462 | 95.043 | 76.240 | -|boot.min.js | 66.007 | 5.575 | 22.567 | 2.340 | 2.000 | +|admin.min.js | 252.147 | 132.156 | 73.657 | 38.184 | 32.740 | +|app.min.js | 511.202 | 356.109 |140.462 | 93.738 | 75.150 | +|boot.min.js | 66.007 | 5.560 | 22.567 | 2.341 | 2.004 | |libs.min.js | 572.545 | 300.691 |176.720 | 92.925 | 82.046 | |polyfills.min.js | 32.452 | 0 | 11.312 | 0 | 0 | -|TOTAL |1.434.353 | 804.565 |424.718 |230.412 |194.496 | +|TOTAL |1.434.353 | 794.516 |424.718 |227.188 |191.940 | -629.788 bytes (194.306 gzip) is not much, but it feels faster. +639.837 bytes (197.530 gzip) is not much, but it feels faster. |css/* |1.14.0 |native | |-------------- |--------: |--------: | -|app.css | 340.334 | 266.769 | -|app.min.css | 274.791 | 211.601 | +|app.css | 340.334 | 266.739 | +|app.min.css | 274.791 | 211.574 | ### PHP73 branch diff --git a/dev/App/Abstract.js b/dev/App/Abstract.js index 512e44f76..da744495f 100644 --- a/dev/App/Abstract.js +++ b/dev/App/Abstract.js @@ -72,7 +72,7 @@ class AbstractApp extends AbstractBoot { } else { const oLink = document.createElement('a'); oLink.href = link; - document.body.appendChild(oLink).click(); + document.body.append(oLink).click(); oLink.remove(); // open(link, '_self'); } @@ -165,11 +165,7 @@ class AbstractApp extends AbstractBoot { ko.components.register('SaveTrigger', require('Component/SaveTrigger').default); ko.components.register('Input', require('Component/Input').default); ko.components.register('Select', require('Component/Select').default); - ko.components.register('Radio', require('Component/Radio').default); ko.components.register('TextArea', require('Component/TextArea').default); - ko.components.register('Date', require('Component/Date').default); - - ko.components.register('x-script', require('Component/Script').default); if (Settings.appSettingsGet('materialDesign') && !bMobileDevice) { ko.components.register('Checkbox', require('Component/MaterialDesign/Checkbox').default); diff --git a/dev/App/User.js b/dev/App/User.js index 3c7b277c2..d3d21eaac 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -819,7 +819,7 @@ class AppUser extends AbstractApp { const resizer = doc.createElement('div'), cssint = s => parseFloat(getComputedStyle(source, null).getPropertyValue(s).replace('px', '')); resizer.className = 'resizer'; - source.appendChild(resizer); + source.append(resizer); resizer.addEventListener('mousedown', { source: source, mode: mode, @@ -995,7 +995,7 @@ class AppUser extends AbstractApp { script.onload = openpgpCallback; script.onerror = () => console.error(script.src); script.src = openPgpJs(); - doc.head.appendChild(script); + doc.head.append(script); } } else { PgpStore.capaOpenPGP(false); diff --git a/dev/Common/Booter.js b/dev/Common/Booter.js index 6fe02aa74..e8f0b1196 100644 --- a/dev/Common/Booter.js +++ b/dev/Common/Booter.js @@ -45,8 +45,8 @@ function writeCSS(css) { const style = doc.createElement('style'); style.type = 'text/css'; style.textContent = css; -// style.appendChild(doc.createTextNode(styles)); - doc.head.appendChild(style); +// style.append(doc.createTextNode(styles)); + doc.head.append(style); } function loadScript(src) { @@ -59,8 +59,8 @@ function loadScript(src) { script.onerror = () => reject(new Error(src)); script.src = src; // script.type = 'text/javascript'; - doc.head.appendChild(script); -// doc.body.appendChild(element); + doc.head.append(script); +// doc.body.append(element); }); } diff --git a/dev/Common/Globals.js b/dev/Common/Globals.js index bd5c07dc4..4b68fab72 100644 --- a/dev/Common/Globals.js +++ b/dev/Common/Globals.js @@ -1,8 +1,8 @@ import ko from 'ko'; import { KeyState } from 'Common/Enums'; -export const $html = jQuery('html'); -export const $htmlCL = document.documentElement.classList; +export const $html = document.documentElement; +export const $htmlCL = $html.classList; /** * @type {?} diff --git a/dev/Common/HtmlEditor.js b/dev/Common/HtmlEditor.js index fcfc4ef0b..49ce273e6 100644 --- a/dev/Common/HtmlEditor.js +++ b/dev/Common/HtmlEditor.js @@ -106,7 +106,6 @@ class HtmlEditor { this.onModeChange = onModeChange; this.element = element; - this.$element = jQuery(element); this.resize = this.resizeEditor.throttle(100); @@ -414,7 +413,7 @@ class HtmlEditor { resizeEditor() { if (this.editor && this.__resizable) { try { - this.editor.resize(this.$element.width(), this.$element.innerHeight()); + this.editor.resize(this.element.clientWidth, this.element.clientHeight); } catch (e) {} // eslint-disable-line no-empty } } diff --git a/dev/Common/Selector.js b/dev/Common/Selector.js index 1e7139d16..45a00ac6c 100644 --- a/dev/Common/Selector.js +++ b/dev/Common/Selector.js @@ -15,7 +15,6 @@ class Selector { iSelectNextHelper = 0; iFocusedNextHelper = 0; - oContentVisible; oContentScrollable; sItemSelector; @@ -262,12 +261,11 @@ class Selector { this.focusedItem(null); } - init(contentVisible, contentScrollable, keyScope = 'all') { - this.oContentVisible = contentVisible; - this.oContentScrollable = contentScrollable ? contentScrollable[0] : null; + init(contentScrollable, keyScope = 'all') { + this.oContentScrollable = contentScrollable; - if (this.oContentVisible && this.oContentScrollable) { - jQuery(this.oContentVisible) + if (contentScrollable) { + jQuery(contentScrollable) .on('selectstart', (event) => { if (event && event.preventDefault) { event.preventDefault(); @@ -289,8 +287,9 @@ class Selector { }); key('enter', keyScope, () => { - if (this.focusedItem() && !this.focusedItem().selected()) { - this.actionClick(this.focusedItem()); + const focused = this.focusedItem(); + if (focused && !focused.selected()) { + this.actionClick(focused); return false; } @@ -500,45 +499,29 @@ class Selector { * @returns {boolean} */ scrollToFocused() { - if (!this.oContentVisible || !this.oContentScrollable) { - return false; + const scrollable = this.oContentScrollable; + if (scrollable) { + let block, focused = scrollable.querySelector(this.sItemFocusedSelector); + if (focused) { + const fRect = focused.getBoundingClientRect(), + sRect = scrollable.getBoundingClientRect(); + if (fRect.top < sRect.top) { + block = 'start'; + } else if (fRect.bottom > sRect.bottom) { + block = 'end'; + } + block && focused.scrollIntoView(block === 'start'); + } else { + scrollable.scrollTop = 0; + } } - - const offset = 20, - list = this.list(), - $focused = jQuery(this.sItemFocusedSelector, this.oContentScrollable), - pos = $focused.position(), - visibleHeight = this.oContentVisible.height(), - focusedHeight = $focused.outerHeight(); - - if (list && list[0] && list[0].focused()) { - this.oContentScrollable.scrollTop = 0; - return true; - } else if (pos && (0 > pos.top || pos.top + focusedHeight > visibleHeight)) { - let top = this.oContentScrollable.scrollTop + pos.top; - this.oContentScrollable.scrollTop = - 0 > pos.top - ? top - offset - : top - visibleHeight + focusedHeight + offset - ; - - return true; - } - - return false; } /** * @returns {boolean} */ scrollToTop() { - if (!this.oContentVisible || !this.oContentScrollable) { - return false; - } - - this.oContentScrollable.scrollTop = 0; - - return true; + this.oContentScrollable && (this.oContentScrollable.scrollTop = 0); } eventClickFunction(item, event) { diff --git a/dev/Common/Translator.js b/dev/Common/Translator.js index 6c40f77ac..893c023fa 100644 --- a/dev/Common/Translator.js +++ b/dev/Common/Translator.js @@ -1,13 +1,12 @@ import ko from 'ko'; import { Notification, UploadErrorCode } from 'Common/Enums'; -import { pInt } from 'Common/Utils'; -import { $html, $htmlCL } from 'Common/Globals'; import { langLink } from 'Common/Links'; let I18N_DATA = window.rainloopI18N || {}; -const I18N_NOTIFICATION_DATA = {}; -const I18N_NOTIFICATION_MAP = [ +const doc = document, +I18N_NOTIFICATION_DATA = {}, +I18N_NOTIFICATION_MAP = [ [Notification.InvalidToken, 'NOTIFICATIONS/INVALID_TOKEN'], [Notification.InvalidToken, 'NOTIFICATIONS/INVALID_TOKEN'], [Notification.AuthError, 'NOTIFICATIONS/AUTH_ERROR'], @@ -101,26 +100,24 @@ export function i18n(key, valueList, defaulValue) { return result; } -const i18nToNode = (element) => { - const $el = jQuery(element), - key = $el.data('i18n'); - +const i18nToNode = element => { + const key = element.dataset.i18n; if (key) { if ('[' === key.substr(0, 1)) { switch (key.substr(0, 6)) { case '[html]': - $el.html(i18n(key.substr(6))); + element.innerHTML = i18n(key.substr(6)); break; case '[place': - $el.attr('placeholder', i18n(key.substr(13))); + element.placeholder = i18n(key.substr(13)); break; case '[title': - $el.attr('title', i18n(key.substr(7))); + element.title = i18n(key.substr(7)); break; // no default } } else { - $el.text(i18n(key)); + element.textContent = i18n(key); } } }; @@ -129,11 +126,9 @@ const i18nToNode = (element) => { * @param {Object} elements * @param {boolean=} animate = false */ -export function i18nToNodes(elements) { +export function i18nToNodes(element) { setTimeout(() => - jQuery('[data-i18n]', elements).each((index, item) => { - i18nToNode(item); - }) + element.querySelectorAll('[data-i18n]').forEach(item => i18nToNode(item)) , 1); } @@ -141,7 +136,7 @@ const reloadData = () => { if (window.rainloopI18N) { I18N_DATA = window.rainloopI18N || {}; - i18nToNodes(document); + i18nToNodes(doc); dispatchEvent(new CustomEvent('reload-time')); trigger(!trigger()); @@ -209,7 +204,7 @@ export function getNotification(code, message = '', defCode = null) { */ export function getNotificationFromResponse(response, defCode = Notification.UnknownNotification) { return response && response.ErrorCode - ? getNotification(pInt(response.ErrorCode), response.ErrorMessage || '') + ? getNotification(parseInt(response.ErrorCode, 10) || defCode, response.ErrorMessage || '') : getNotification(defCode); } @@ -253,8 +248,6 @@ export function getUploadErrorDescByCode(code) { export function reload(admin, language) { const start = Date.now(); - $htmlCL.add('rl-changing-language'); - return new Promise((resolve, reject) => { return fetch(langLink(language, admin), {cache: 'reload'}) .then(response => { @@ -269,18 +262,19 @@ export function reload(admin, language) { reject(new Error(error.message)) }) .then(data => { - var script = document.createElement('script'); + var script = doc.createElement('script'); script.text = data; - document.head.appendChild(script).parentNode.removeChild(script); + doc.head.append(script).remove(); setTimeout( () => { reloadData(); - const isRtl = ['ar', 'ar_sa', 'he', 'he_he', 'ur', 'ur_ir'].includes((language || '').toLowerCase()); + const isRtl = ['ar', 'ar_sa', 'he', 'he_he', 'ur', 'ur_ir'].includes((language || '').toLowerCase()), + htmlCL = doc.documentElement.classList; - $htmlCL.remove('rl-changing-language', 'rl-rtl', 'rl-ltr'); - // $html.attr('dir', isRtl ? 'rtl' : 'ltr') - $htmlCL.add(isRtl ? 'rl-rtl' : 'rl-ltr'); + htmlCL.remove('rl-rtl', 'rl-ltr'); + htmlCL.add(isRtl ? 'rl-rtl' : 'rl-ltr'); + // doc.documentElement.dir = isRtl ? 'rtl' : 'ltr' resolve(); }, @@ -289,6 +283,3 @@ export function reload(admin, language) { }); }); } - -// init section -$htmlCL.add('rl-' + ($html.attr('dir') || 'ltr')); diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js index b1f893270..b5ad9c9a3 100644 --- a/dev/Common/Utils.js +++ b/dev/Common/Utils.js @@ -3,8 +3,7 @@ import { Mime } from 'Common/Mime'; const doc = document, - $ = jQuery, - $div = $('
'), + tpl = doc.createElement('template'), isArray = Array.isArray, htmlmap = { '&': '&', @@ -15,6 +14,13 @@ const }, htmlspecialchars = str => (''+str).replace(/[&<>"']/g, m => htmlmap[m]); +export function htmlToElement(html) { + var template = document.createElement('template'); + template.innerHTML = html.trim(); + return template.content.firstChild; +} + + /** * @param {(string|number)} value * @param {boolean=} includeZero = true @@ -137,7 +143,7 @@ export function inFocus() { try { if (doc.activeElement) { if (undefined === doc.activeElement.__inFocusCache) { - doc.activeElement.__inFocusCache = $(doc.activeElement).is( + doc.activeElement.__inFocusCache = doc.activeElement.matches( 'input,textarea,iframe,.cke_editable' ); } @@ -156,8 +162,7 @@ export function inFocus() { export function removeInFocus(force) { if (doc.activeElement && doc.activeElement.blur) { try { - const activeEl = $(doc.activeElement); - if (force || (activeEl && activeEl.is('input,textarea'))) { + if (force || doc.activeElement.matches('input,textarea')) { doc.activeElement.blur(); } } catch (e) {} // eslint-disable-line no-empty @@ -275,19 +280,6 @@ export function convertLangName(language, isEng = false) { ); } -/** - * @returns {object} - */ -export function draggablePlace() { - return $( - ']*><\/p>/gi, '') .replace(/
]*>([\s\S\r\n\t]*)<\/pre>/gim, convertPre)
.replace(/[\s]+/gm, ' ')
@@ -507,16 +440,13 @@ export function htmlToPlain(html) {
.replace(/"/gi, '"')
.replace(/<[^>]*>/gm, '');
- text = $div.html(text).text();
-
- text = text
+ text = splitPlainText(tpl.textContent
.replace(/\n[ \t]+/gm, '\n')
.replace(/[\n]{3,}/gm, '\n\n')
.replace(/>/gi, '>')
.replace(/</gi, '<')
- .replace(/&/gi, '&');
-
- text = splitPlainText(text);
+ .replace(/&/gi, '&')
+ );
pos = 0;
limit = 800;
@@ -530,7 +460,6 @@ export function htmlToPlain(html) {
if ((-1 === iP2 || iP3 < iP2) && iP1 < iP3) {
text = text.substring(0, iP1) + convertBlockquote(text.substring(iP1 + 13, iP3)) + text.substring(iP3 + 11);
-
pos = 0;
} else if (-1 < iP2 && iP2 < iP3) {
pos = iP2 - 1;
@@ -552,7 +481,7 @@ export function htmlToPlain(html) {
* @param {boolean} findEmailAndLinksInText = false
* @returns {string}
*/
-export function plainToHtml(plain, findEmailAndLinksInText = false) {
+export function plainToHtml(plain) {
plain = plain.toString().replace(/\r/g, '');
plain = plain.replace(/^>[> ]>+/gm, ([match]) => (match ? match.replace(/[ ]+/g, '') : match));
@@ -595,9 +524,7 @@ export function plainToHtml(plain, findEmailAndLinksInText = false) {
aText = aNextText;
} while (bDo);
- plain = aText.join('\n');
-
- plain = plain
+ return aText.join('\n')
// .replace(/~~~\/blockquote~~~\n~~~blockquote~~~/g, '\n')
.replace(/&/g, '&')
.replace(/>/g, '>')
@@ -605,8 +532,6 @@ export function plainToHtml(plain, findEmailAndLinksInText = false) {
.replace(/~~~blockquote~~~[\s]*/g, '')
.replace(/[\s]*~~~\/blockquote~~~/g, '
')
.replace(/\n/g, '
');
-
- return findEmailAndLinksInText ? findEmailAndLinks(plain) : plain;
}
window['rainloop_Utils_htmlToPlain'] = htmlToPlain; // eslint-disable-line dot-notation
@@ -766,39 +691,6 @@ export function selectElement(element) {
sel.addRange(range);
}
-/**
- * @param {boolean=} delay = false
- */
-export function triggerAutocompleteInputChange(delay = false) {
- const fFunc = () => $('.checkAutocomplete').trigger('change');
-
- if (delay) {
- setTimeout(fFunc, 100);
- } else {
- fFunc();
- }
-}
-
-const configurationScriptTagCache = {};
-
-/**
- * @param {string} configuration
- * @returns {object}
- */
-export function getConfigurationFromScriptTag(configuration) {
- if (!configurationScriptTagCache[configuration]) {
- configurationScriptTagCache[configuration] = $(
- 'script[type="application/json"][data-configuration="' + configuration + '"]'
- );
- }
-
- try {
- return JSON.parse(configurationScriptTagCache[configuration].text());
- } catch (e) {} // eslint-disable-line no-empty
-
- return {};
-}
-
/**
* @param {Object|Array} objectOrObjects
* @returns {void}
diff --git a/dev/Component/Abstract.js b/dev/Component/Abstract.js
index 8fe531ed1..03fb22e97 100644
--- a/dev/Component/Abstract.js
+++ b/dev/Component/Abstract.js
@@ -30,7 +30,7 @@ const componentExportHelper = (ClassObject, templateID = '') => ({
params.component = componentInfo;
params.element = jQuery(componentInfo.element);
- i18nToNodes(params.element);
+ i18nToNodes(componentInfo.element);
if (undefined !== params.inline && ko.unwrap(params.inline)) {
params.element.css('display', 'inline-block');
diff --git a/dev/External/ko.js b/dev/External/ko.js
index bed90edc1..656229039 100644
--- a/dev/External/ko.js
+++ b/dev/External/ko.js
@@ -2,6 +2,7 @@ import { SaveSettingsStep } from 'Common/Enums';
const
$ = jQuery,
+ doc = document,
ko = window.ko,
Translator = () => require('Common/Translator'),
isFunction = v => typeof v === 'function';
@@ -75,7 +76,7 @@ ko.bindingHandlers.tooltip = {
ko.bindingHandlers.tooltipErrorTip = {
init: element => {
- document.addEventListener('click', () => element.removeAttribute('data-rainloopErrorTip'));
+ doc.addEventListener('click', () => element.removeAttribute('data-rainloopErrorTip'));
ko.utils.domNodeDisposal.addDisposeCallback(element, () => element.removeAttribute('data-rainloopErrorTip'));
},
update: (element, fValueAccessor) => {
@@ -197,13 +198,13 @@ ko.bindingHandlers.modal = {
});
},
update: (element, fValueAccessor) => {
- const Globals = require('Common/Globals');
+ const htmlCL = doc.documentElement.classList;
$(element).modal(ko.unwrap(fValueAccessor()) ? 'show' : 'hide');
- if (Globals.$htmlCL.contains('no-mobile')) {
- Globals.$htmlCL.add('rl-modal-animation');
- setTimeout(() => Globals.$htmlCL.remove('rl-modal-animation'), 500);
+ if (htmlCL.contains('no-mobile')) {
+ htmlCL.add('rl-modal-animation');
+ setTimeout(() => htmlCL.remove('rl-modal-animation'), 500);
}
}
};
@@ -226,11 +227,11 @@ ko.bindingHandlers.i18nUpdate = {
};
ko.bindingHandlers.link = {
- update: (element, fValueAccessor) => element.setAttribute('href', ko.unwrap(fValueAccessor()))
+ update: (element, fValueAccessor) => element.href = ko.unwrap(fValueAccessor())
};
ko.bindingHandlers.title = {
- update: (element, fValueAccessor) => element.setAttribute('title', ko.unwrap(fValueAccessor()))
+ update: (element, fValueAccessor) => element.title = ko.unwrap(fValueAccessor())
};
ko.bindingHandlers.initDom = {
@@ -247,7 +248,7 @@ ko.bindingHandlers.draggable = {
scrollSpeed = 3,
fAllValueFunc = fAllBindingsAccessor(),
selector = fAllValueFunc ? fAllValueFunc.droppableSelector : '',
- droppable = selector ? document.querySelector(selector) : null,
+ droppable = selector ? doc.querySelector(selector) : null,
conf = {
distance: 20,
handle: '.dragHandle',
@@ -352,7 +353,7 @@ ko.bindingHandlers.saveTrigger = {
$el.data(
'save-trigger-type',
- $el.is('input[type=text],input[type=email],input[type=password],select,textarea') ? 'input' : 'custom'
+ element.matches('input[type=text],input[type=email],input[type=password],select,textarea') ? 'input' : 'custom'
);
if ('custom' === $el.data('save-trigger-type')) {
diff --git a/dev/Knoin/AbstractViewNext.js b/dev/Knoin/AbstractViewNext.js
index b48c3eb9f..483f997bb 100644
--- a/dev/Knoin/AbstractViewNext.js
+++ b/dev/Knoin/AbstractViewNext.js
@@ -53,7 +53,7 @@ export class AbstractViewNext {
closeCommand() {} // eslint-disable-line no-empty-function
querySelector(selectors) {
- return this.viewModelDom[0].querySelector(selectors);
+ return this.viewModelDom.querySelector(selectors);
}
}
diff --git a/dev/Knoin/Knoin.js b/dev/Knoin/Knoin.js
index 1d5ee33b3..90eed9cea 100644
--- a/dev/Knoin/Knoin.js
+++ b/dev/Knoin/Knoin.js
@@ -7,7 +7,8 @@ import { $htmlCL, VIEW_MODELS } from 'Common/Globals';
let currentScreen = null,
defaultScreenName = '';
-const SCREENS = {}, $ = jQuery,
+const SCREENS = {},
+ qs = s => document.querySelector(s),
isNonEmptyArray = values => Array.isArray(values) && values.length,
popupVisibilityNames = ko.observableArray([]);
@@ -29,10 +30,8 @@ export const ViewType = {
* @returns {void}
*/
export function hideLoading() {
- $('#rl-content').addClass('rl-content-show');
- $('#rl-loading')
- .hide()
- .remove();
+ qs('#rl-content').classList.add('rl-content-show');
+ qs('#rl-loading').remove();
}
/**
@@ -156,7 +155,7 @@ export function buildViewModel(ViewModelClass, vmScreen) {
let vmDom = null;
const vm = new ViewModelClass(vmScreen),
position = ViewModelClass.__type || '',
- vmPlace = position ? $('#rl-content #rl-' + position.toLowerCase()) : null;
+ vmPlace = position ? qs('#rl-content #rl-' + position.toLowerCase()) : null;
ViewModelClass.__builded = true;
ViewModelClass.__vm = vm;
@@ -166,15 +165,14 @@ export function buildViewModel(ViewModelClass, vmScreen) {
vm.viewModelTemplateID = ViewModelClass.__templateID;
vm.viewModelPosition = ViewModelClass.__type;
- if (vmPlace && 1 === vmPlace.length) {
- vmDom = $('')
- .addClass('rl-view-model')
- .addClass('RL-' + vm.viewModelTemplateID)
- .hide();
- vmDom.appendTo(vmPlace);
+ if (vmPlace) {
+ vmDom = jQuery('');
+ vmDom[0].classList.add('rl-view-model', 'RL-' + vm.viewModelTemplateID);
+ vmDom[0].hidden = true;
+ vmPlace.append(vmDom[0]);
- vm.viewModelDom = vmDom;
- ViewModelClass.__dom = vmDom;
+ vm.viewModelDom = vmDom[0];
+ ViewModelClass.__dom = vmDom[0];
if (ViewType.Popup === position) {
vm.cancelCommand = vm.closeCommand = createCommand(() => {
@@ -183,11 +181,11 @@ export function buildViewModel(ViewModelClass, vmScreen) {
vm.modalVisibility.subscribe((value) => {
if (value) {
- vm.viewModelDom.show();
+ vm.viewModelDom.hidden = false;
vm.storeAndSetKeyScope();
popupVisibilityNames.push(vm.viewModelName);
- vm.viewModelDom.css('z-index', 3000 + popupVisibilityNames().length + 10);
+ vm.viewModelDom.style.zIndex = 3000 + popupVisibilityNames().length + 10;
vm.onShowWithDelay && setTimeout(()=>vm.onShowWithDelay, 500);
} else {
@@ -197,9 +195,9 @@ export function buildViewModel(ViewModelClass, vmScreen) {
vm.restoreKeyScope();
popupVisibilityNames.remove(vm.viewModelName);
- vm.viewModelDom.css('z-index', 2000);
+ vm.viewModelDom.style.zIndex = 2000;
- setTimeout(() => vm.viewModelDom.hide(), 300);
+ setTimeout(() => vm.viewModelDom.hidden = true, 300);
}
});
}
@@ -245,7 +243,7 @@ export function showScreenPopup(ViewModelClassToShow, params = []) {
ModalView.__vm.onShow && ModalView.__vm.onShow(...params);
// if (!bMobileDevice) {
- const af = ModalView.__dom[0].querySelector('[autofocus]');
+ const af = ModalView.__dom.querySelector('[autofocus]');
af && af.focus();
}
}
@@ -327,7 +325,7 @@ export function screenOnRoute(screenName, subPart) {
ViewModelClass.__dom &&
ViewType.Popup !== ViewModelClass.__vm.viewModelPosition
) {
- ViewModelClass.__dom.hide();
+ ViewModelClass.__dom.hidden = true;
ViewModelClass.__vm.viewModelVisibility(false);
ViewModelClass.__vm.onHide && ViewModelClass.__vm.onHide();
@@ -353,13 +351,13 @@ export function screenOnRoute(screenName, subPart) {
) {
ViewModelClass.__vm.onBeforeShow && ViewModelClass.__vm.onBeforeShow();
- ViewModelClass.__dom.show();
+ ViewModelClass.__dom.hidden = false;
ViewModelClass.__vm.viewModelVisibility(true);
ViewModelClass.__vm.onShow && ViewModelClass.__vm.onShow();
// if (!bMobileDevice) {
- const af = ViewModelClass.__dom[0].querySelector('[autofocus]');
+ const af = ViewModelClass.__dom.querySelector('[autofocus]');
af && af.focus();
ViewModelClass.__vm.onShowWithDelay && setTimeout(()=>ViewModelClass.__vm.onShowWithDelay, 200);
diff --git a/dev/Model/Message.js b/dev/Model/Message.js
index f89e1b550..7e6d13046 100644
--- a/dev/Model/Message.js
+++ b/dev/Model/Message.js
@@ -5,7 +5,8 @@ import { i18n } from 'Common/Translator';
import {
pInt,
- previewMessage,
+ deModule,
+ encodeHtml,
friendlySize,
isNonEmptyArray
} from 'Common/Utils';
@@ -20,7 +21,7 @@ import { emailArrayFromJson, emailArrayToStringClear, emailArrayToString, replyH
import { AttachmentModel, staticCombinedIconClass } from 'Model/Attachment';
import { AbstractModel } from 'Knoin/AbstractModel';
-const $ = jQuery, isArray = Array.isArray;
+const isArray = Array.isArray;
class MessageModel extends AbstractModel {
constructor() {
@@ -604,13 +605,6 @@ class MessageModel extends AbstractModel {
return [toResult, ccResult];
}
- /**
- * @returns {string}
- */
- textBodyToString() {
- return this.body ? this.body.html() : '';
- }
-
/**
* @returns {string}
*/
@@ -625,24 +619,30 @@ class MessageModel extends AbstractModel {
viewPopupMessage(print = false) {
const timeStampInUTC = this.dateTimeStampInUTC() || 0,
ccLine = this.ccToLine(false),
- m = 0 < timeStampInUTC ? new Date(timeStampInUTC * 1000) : null;
+ m = 0 < timeStampInUTC ? new Date(timeStampInUTC * 1000) : null,
+ win = open(''),
+ doc = win.document;
- previewMessage(
- {
- title: this.subject(),
- subject: this.subject(),
- date: m ? m.format('LLL') : '',
- fromCreds: this.fromToLine(false),
- toLabel: i18n('MESSAGE/LABEL_TO'),
- toCreds: this.toToLine(false),
- ccClass: ccLine ? '' : 'rl-preview-hide',
- ccLabel: i18n('MESSAGE/LABEL_CC'),
- ccCreds: ccLine
- },
- this.body,
- this.isHtml(),
- print
+ doc.write(
+ deModule(require('Html/PreviewMessage.html'))
+ .replace('{{title}}', encodeHtml(this.subject()))
+ .replace('{{subject}}', encodeHtml(this.subject()))
+ .replace('{{date}}', encodeHtml(m ? m.format('LLL') : ''))
+ .replace('{{fromCreds}}', encodeHtml(this.fromToLine(false)))
+ .replace('{{toCreds}}', encodeHtml(this.toToLine(false)))
+ .replace('{{toLabel}}', encodeHtml(i18n('MESSAGE/LABEL_TO')))
+ .replace('{{ccClass}}', encodeHtml(ccLine ? '' : 'rl-preview-hide'))
+ .replace('{{ccCreds}}', encodeHtml(ccLine))
+ .replace('{{ccLabel}}', encodeHtml(i18n('MESSAGE/LABEL_CC')))
+ .replace('{{bodyClass}}', this.isHtml() ? 'html' : 'plain')
+ .replace('{{html}}', this.bodyAsHTML())
);
+
+ doc.close();
+
+ if (print) {
+ setTimeout(() => win.print(), 100);
+ }
}
printMessage() {
@@ -725,74 +725,60 @@ class MessageModel extends AbstractModel {
return this;
}
- showExternalImages(lazy = false) {
- if (this.body && this.body.data('rl-has-images')) {
+ showExternalImages() {
+ if (this.body && this.body.rlHasImages) {
this.hasImages(false);
- this.body.data('rl-has-images', false);
+ this.body.rlHasImages = false;
- let attr = this.proxy ? 'data-x-additional-src' : 'data-x-src';
- $('[' + attr + ']', this.body).each(function() {
- const $this = $(this); // eslint-disable-line no-invalid-this
- if (lazy && $this.is('img')) {
- $this.attr('loading', 'lazy');
+ let body = this.body, attr = this.proxy ? 'data-x-additional-src' : 'data-x-src';
+ body.querySelectorAll('[' + attr + ']').forEach(node => {
+ if (node.matches('img')) {
+ node.loading = 'lazy';
}
- $this.attr('src', $this.attr(attr)).removeAttr('data-loaded');
+ node.src = node.getAttribute(attr);
+ node.removeAttribute('data-loaded');
});
attr = this.proxy ? 'data-x-additional-style-url' : 'data-x-style-url';
- $('[' + attr + ']', this.body).each(function() {
- const $this = $(this); // eslint-disable-line no-invalid-this
- let style = $this.attr('style').trim();
- style = style ? (';' === style.substr(-1) ? style + ' ' : style + '; ') : '';
- $this.attr('style', style + $this.attr(attr));
+ body.querySelectorAll('[' + attr + ']').forEach(node => {
+ node.setAttribute('style', ((node.getAttribute('style')||'')
+ + ';' + node.getAttribute(attr))
+ .replace(/^[;\s]+/,''));
});
}
}
- showInternalImages(lazy = false) {
- if (this.body && !this.body.data('rl-init-internal-images')) {
- this.body.data('rl-init-internal-images', true);
+ showInternalImages() {
+ if (this.body && !this.body.rlInitInternalImages) {
+ this.body.rlInitInternalImages = true;
- const self = this;
-
- $('[data-x-src-cid]', this.body).each(function() {
- const $this = $(this), // eslint-disable-line no-invalid-this
- attachment = self.findAttachmentByCid($this.attr('data-x-src-cid'));
+ const body = this.body;
+ body.querySelectorAll('[data-x-src-cid]').forEach(node => {
+ const attachment = this.findAttachmentByCid(node.dataset.xSrcCid);
if (attachment && attachment.download) {
- $this.attr('src', attachment.linkPreview());
+ node.src = attachment.linkPreview();
}
});
- $('[data-x-src-location]', this.body).each(function() {
- const $this = $(this); // eslint-disable-line no-invalid-this
- let attachment = self.findAttachmentByContentLocation($this.attr('data-x-src-location'));
- if (!attachment) {
- attachment = self.findAttachmentByCid($this.attr('data-x-src-location'));
- }
-
+ body.querySelectorAll('[data-x-src-location]').forEach(node => {
+ const attachment = this.findAttachmentByContentLocation(node.dataset.xSrcLocation)
+ || this.findAttachmentByCid(node.dataset.xSrcLocation);
if (attachment && attachment.download) {
- if (lazy && $this.is('img')) {
- $this.attr('loading', 'lazy');
+ if (node.matches('img')) {
+ node.loading = 'lazy';
}
- $this.attr('src', attachment.linkPreview());
+ node.src = attachment.linkPreview();
}
});
- $('[data-x-style-cid]', this.body).each(function() {
- let style = '',
- name = '';
-
- const $this = $(this), // eslint-disable-line no-invalid-this
- attachment = self.findAttachmentByCid($this.attr('data-x-style-cid'));
-
- if (attachment && attachment.linkPreview) {
- name = $this.attr('data-x-style-cid-name');
- if (name) {
- style = $this.attr('style').trim();
- style = style ? (';' === style.substr(-1) ? style + ' ' : style + '; ') : '';
- $this.attr('style', style + name + ": url('" + attachment.linkPreview() + "')");
- }
+ body.querySelectorAll('[style-cid]').forEach(node => {
+ const name = node.dataset.xStyleCidName,
+ attachment = this.findAttachmentByCid(node.dataset.xStyleCid);
+ if (attachment && attachment.linkPreview && name) {
+ node.setAttribute('style', ((node.getAttribute('style')||'')
+ + ';' + name + ": url('" + attachment.linkPreview() + "')")
+ .replace(/^[;\s]+/,''));
}
});
}
@@ -800,22 +786,37 @@ class MessageModel extends AbstractModel {
storeDataInDom() {
if (this.body) {
- this.body.data('rl-is-html', !!this.isHtml());
- this.body.data('rl-has-images', !!this.hasImages());
+ this.body.rlIsHtml = !!this.isHtml();
+ this.body.rlHasImages = !!this.hasImages();
}
}
fetchDataFromDom() {
if (this.body) {
- this.isHtml(!!this.body.data('rl-is-html'));
- this.hasImages(!!this.body.data('rl-has-images'));
+ this.isHtml(!!this.body.rlIsHtml);
+ this.hasImages(!!this.body.rlHasImages);
}
}
- replacePlaneTextBody(plain) {
+ /**
+ * @returns {string}
+ */
+ bodyAsHTML() {
if (this.body) {
- this.body.html(plain).addClass('b-text-part plain');
+ let clone = this.body.cloneNode(true),
+ attr = 'data-html-editor-font-wrapper';
+ clone.querySelectorAll('blockquote.rl-bq-switcher').forEach(
+ node => node.classList.remove('rl-bq-switcher','hidden-bq')
+ );
+ clone.querySelectorAll('.rlBlockquoteSwitcher').forEach(
+ node => node.remove()
+ );
+ clone.querySelectorAll('['+attr+']').forEach(
+ node => node.removeAttribute(attr)
+ );
+ return clone.innerHTML;
}
+ return '';
}
/**
diff --git a/dev/Remote/AbstractAjax.js b/dev/Remote/AbstractAjax.js
index 42d181f1c..e4c0fd019 100644
--- a/dev/Remote/AbstractAjax.js
+++ b/dev/Remote/AbstractAjax.js
@@ -116,7 +116,6 @@ class AbstractAjaxRemote {
* @param {?number=} iTimeOut = 20000
* @param {string=} sGetAdd = ''
* @param {Array=} aAbortActions = []
- * @returns {jQuery.jqXHR}
*/
ajaxRequest(fResultCallback, params, iTimeOut = 20000, sGetAdd = '', abortActions = []) {
params = params || {};
diff --git a/dev/Screen/AbstractSettings.js b/dev/Screen/AbstractSettings.js
index f6e3c88fd..ce5d59ca4 100644
--- a/dev/Screen/AbstractSettings.js
+++ b/dev/Screen/AbstractSettings.js
@@ -34,7 +34,6 @@ class AbstractSettingsScreen extends AbstractScreen {
onRoute(subName) {
let settingsScreen = null,
RoutedSettingsViewModel = null,
- viewModelPlace = null,
viewModelDom = null;
RoutedSettingsViewModel = VIEW_MODELS.settings.find(
@@ -67,20 +66,19 @@ class AbstractSettingsScreen extends AbstractScreen {
if (RoutedSettingsViewModel.__builded && RoutedSettingsViewModel.__vm) {
settingsScreen = RoutedSettingsViewModel.__vm;
} else {
- viewModelPlace = this.oViewModelPlace;
- if (viewModelPlace && 1 === viewModelPlace.length) {
+ if (this.oViewModelPlace) {
settingsScreen = new RoutedSettingsViewModel();
- viewModelDom = jQuery('')
- .addClass('rl-settings-view-model')
- .hide();
- viewModelDom.appendTo(viewModelPlace);
+ viewModelDom = jQuery('');
+ viewModelDom[0].classList.add('rl-settings-view-model');
+ viewModelDom[0].hidden = true;
+ this.oViewModelPlace.append(viewModelDom[0]);
- settingsScreen.viewModelDom = viewModelDom;
+ settingsScreen.viewModelDom = viewModelDom[0];
settingsScreen.__rlSettingsData = RoutedSettingsViewModel.__rlSettingsData;
- RoutedSettingsViewModel.__dom = viewModelDom;
+ RoutedSettingsViewModel.__dom = viewModelDom[0];
RoutedSettingsViewModel.__builded = true;
RoutedSettingsViewModel.__vm = settingsScreen;
@@ -106,7 +104,7 @@ class AbstractSettingsScreen extends AbstractScreen {
// hide
if (o.oCurrentSubScreen) {
o.oCurrentSubScreen.onHide && o.oCurrentSubScreen.onHide();
- o.oCurrentSubScreen.viewModelDom.hide();
+ o.oCurrentSubScreen.viewModelDom.hidden = true;
}
// --
@@ -115,7 +113,7 @@ class AbstractSettingsScreen extends AbstractScreen {
// show
if (o.oCurrentSubScreen) {
o.oCurrentSubScreen.onBeforeShow && o.oCurrentSubScreen.onBeforeShow();
- o.oCurrentSubScreen.viewModelDom.show();
+ o.oCurrentSubScreen.viewModelDom.hidden = false;
o.oCurrentSubScreen.onShow && o.oCurrentSubScreen.onShow();
o.oCurrentSubScreen.onShowWithDelay && setTimeout(() => o.oCurrentSubScreen.onShowWithDelay(), 200);
@@ -127,7 +125,7 @@ class AbstractSettingsScreen extends AbstractScreen {
);
});
- jQuery('#rl-content .b-settings .b-content')[0].scrollTop = 0;
+ document.querySelector('#rl-content .b-settings .b-content').scrollTop = 0;
}
// --
}, 1);
@@ -140,7 +138,7 @@ class AbstractSettingsScreen extends AbstractScreen {
onHide() {
if (this.oCurrentSubScreen && this.oCurrentSubScreen.viewModelDom) {
this.oCurrentSubScreen.onHide && this.oCurrentSubScreen.onHide();
- this.oCurrentSubScreen.viewModelDom.hide();
+ this.oCurrentSubScreen.viewModelDom.hidden = true;
}
}
@@ -164,7 +162,7 @@ class AbstractSettingsScreen extends AbstractScreen {
}
});
- this.oViewModelPlace = jQuery('#rl-content #rl-settings-subscreen');
+ this.oViewModelPlace = document.getElementById('rl-settings-subscreen');
}
routes() {
diff --git a/dev/Screen/User/MailBox.js b/dev/Screen/User/MailBox.js
index e707dd139..9492c3331 100644
--- a/dev/Screen/User/MailBox.js
+++ b/dev/Screen/User/MailBox.js
@@ -128,7 +128,7 @@ class MailBoxUserScreen extends AbstractScreen {
, 1);
}
- $html.on('click', '#rl-right', () => {
+ jQuery($html).on('click', '#rl-right', () => {
moveAction(false);
});
}
diff --git a/dev/Stores/User/Message.js b/dev/Stores/User/Message.js
index a18f04f89..7fb88d473 100644
--- a/dev/Stores/User/Message.js
+++ b/dev/Stores/User/Message.js
@@ -6,7 +6,8 @@ import {
pInt,
pString,
plainToHtml,
- findEmailAndLinks
+ findEmailAndLinks,
+ htmlToElement
} from 'Common/Utils';
import {
@@ -44,25 +45,17 @@ import { getApp } from 'Helper/Apps/User';
import Remote from 'Remote/User/Ajax';
const
- $ = jQuery,
- $div = $(''),
- $hcont = $(''),
- getRealHeight = $el => {
- $el
- .clone()
- .show()
- .appendTo($hcont);
- const result = $hcont.height();
- $hcont.empty();
+ hcont = htmlToElement(''),
+ getRealHeight = el => {
+ hcont.innerHTML = el.outerHTML;
+ const result = hcont.clientHeight;
+ hcont.innerHTML = '';
return result;
};
let iMessageBodyCacheCount = 0;
-$hcont
- .attr('area', 'hidden')
- .css({ position: 'absolute', left: -5000 })
- .appendTo($('body'));
+document.body.append(hcont);
class MessageUserStore {
constructor() {
@@ -218,12 +211,6 @@ class MessageUserStore {
this.messageLoading.subscribe(value => this.messageLoadingThrottle(value));
- this.messagesBodiesDom.subscribe((dom) => {
- if (dom && !(dom instanceof $)) {
- this.messagesBodiesDom($(dom));
- }
- });
-
this.messageListEndFolder.subscribe(folder => {
const message = this.message();
if (message && folder && folder !== message.folderFullNameRaw) {
@@ -233,22 +220,20 @@ class MessageUserStore {
}
purgeMessageBodyCache() {
- let count = 0;
const end = iMessageBodyCacheCount - MESSAGE_BODY_CACHE_LIMIT;
-
if (0 < end) {
+ let count = 0;
const messagesDom = this.messagesBodiesDom();
if (messagesDom) {
- messagesDom.find('.rl-cache-class').each(function() {
- const item = $(this); // eslint-disable-line no-invalid-this
- if (end > item.data('rl-cache-count')) {
- item.addClass('rl-cache-purge');
- count += 1;
+ messagesDom.querySelectorAll('.rl-cache-class').forEach(node => {
+ if (end > node.rlCacheCount) {
+ node.classList.add('rl-cache-purge');
+ ++count;
}
});
if (0 < count) {
- setTimeout(() => messagesDom.find('.rl-cache-purge').remove(), 350);
+ setTimeout(() => messagesDom.querySelectorAll('.rl-cache-purge').forEach(node => node.remove()), 350);
}
}
}
@@ -291,9 +276,7 @@ class MessageUserStore {
hideMessageBodies() {
const messagesDom = this.messagesBodiesDom();
- if (messagesDom) {
- messagesDom.find('.b-text-part').hide();
- }
+ messagesDom && messagesDom.querySelectorAll('.b-text-part').forEach(el => el.hidden = true);
}
/**
@@ -441,30 +424,17 @@ class MessageUserStore {
* @param {Object} messageTextBody
*/
initBlockquoteSwitcher(messageTextBody) {
- if (messageTextBody) {
- const $oList = $('blockquote:not(.rl-bq-switcher)', messageTextBody).filter(function() {
- return !$(this).parent().closest('blockquote', messageTextBody).length;
- });
-
- if ($oList && $oList.length) {
- $oList.each(function() {
- const $this = $(this); // eslint-disable-line no-invalid-this
-
- let h = $this.height() || getRealHeight($this);
-
- if ($this.text().trim() && (0 === h || 100 < h)) {
- $this.addClass('rl-bq-switcher hidden-bq');
- $('')
- .insertBefore($this)
- .on('click.rlBlockquoteSwitcher', () => {
- $this.toggleClass('hidden-bq');
- })
- .after('
')
- .before('
');
- }
- });
+ messageTextBody && messageTextBody.querySelectorAll('blockquote:not(.rl-bq-switcher)').forEach(node => {
+ if (node.textContent.trim() && !node.parentNode.closest('blockquote')) {
+ let h = node.clientHeight || getRealHeight(node);
+ if (0 === h || 100 < h) {
+ const el = htmlToElement('•••');
+ node.classList.add('rl-bq-switcher','hidden-bq');
+ node.before(el);
+ el.addEventListener('click', () => node.classList.toggle('hidden-bq'));
+ }
}
- }
+ });
}
/**
@@ -472,11 +442,9 @@ class MessageUserStore {
* @param {Object} message
*/
initOpenPgpControls(messageTextBody, message) {
- if (messageTextBody && messageTextBody.find) {
- messageTextBody.find('.b-plain-openpgp:not(.inited)').each(function() {
- PgpStore.initMessageBodyControls($(this), message); // eslint-disable-line no-invalid-this
- });
- }
+ messageTextBody && messageTextBody.querySelectorAll('.b-plain-openpgp:not(.inited)').forEach(node =>
+ PgpStore.initMessageBodyControls(node, message)
+ );
}
setMessage(data, cached) {
@@ -521,19 +489,22 @@ class MessageUserStore {
message.initFlagsByJson(data.Result);
}
- messagesDom = messagesDom && messagesDom[0] ? messagesDom : null;
if (messagesDom) {
id = 'rl-mgs-' + message.hash.replace(/[^a-zA-Z0-9]/g, '');
- const textBody = messagesDom.find('#' + id);
- if (!textBody || !textBody[0]) {
+ const textBody = document.getElementById(id);
+ if (textBody) {
+ iMessageBodyCacheCount += 1;
+ textBody.rlCacheCount = iMessageBodyCacheCount;
+ message.fetchDataFromDom();
+ } else {
let isHtml = false;
if (data.Result.Html) {
isHtml = true;
resultHtml = data.Result.Html.toString();
} else if (data.Result.Plain) {
isHtml = false;
- resultHtml = plainToHtml(data.Result.Plain.toString(), false);
+ resultHtml = plainToHtml(data.Result.Plain.toString());
if ((message.isPgpSigned() || message.isPgpEncrypted()) && PgpStore.capaOpenPGP()) {
plain = pString(data.Result.Plain);
@@ -544,16 +515,17 @@ class MessageUserStore {
/-----BEGIN PGP SIGNED MESSAGE-----/.test(plain) && /-----BEGIN PGP SIGNATURE-----/.test(plain);
}
- $div.empty();
+ const pre = document.createElement('pre');
if (pgpSigned && message.isPgpSigned()) {
- resultHtml = $div.append($('').text(plain)).html();
+ pre.className = 'b-plain-openpgp signed';
+ pre.textContent = plain;
} else if (isPgpEncrypted && message.isPgpEncrypted()) {
- resultHtml = $div.append($('').text(plain)).html();
+ pre.className = 'b-plain-openpgp encrypted';
+ pre.textContent = plain;
} else {
- resultHtml = '' + resultHtml + '
';
+ pre.innerHTML = resultHtml;
}
-
- $div.empty();
+ resultHtml = pre.outerHTML;
message.isPgpSigned(pgpSigned);
message.isPgpEncrypted(isPgpEncrypted);
@@ -567,41 +539,31 @@ class MessageUserStore {
iMessageBodyCacheCount += 1;
- body = $('')
- .hide()
- .addClass('rl-cache-class');
- body.data('rl-cache-count', iMessageBodyCacheCount);
-
- body.html(findEmailAndLinks(resultHtml)).addClass('b-text-part ' + (isHtml ? 'html' : 'plain'));
+ body = htmlToElement(''
+ + findEmailAndLinks(resultHtml)
+ + '');
+ body.rlCacheCount = iMessageBodyCacheCount;
message.isHtml(!!isHtml);
message.hasImages(!!data.Result.HasExternals);
- message.body = body;
- if (message.body) {
- messagesDom.append(message.body);
- }
+ messagesDom.append(body);
message.storeDataInDom();
if (data.Result.HasInternals) {
- message.showInternalImages(true);
+ message.showInternalImages();
}
if (message.hasImages() && SettingsStore.showImages()) {
- message.showExternalImages(true);
+ message.showExternalImages();
}
this.purgeMessageBodyCacheThrottle();
- } else {
- message.body = textBody;
- if (message.body) {
- iMessageBodyCacheCount += 1;
- message.body.data('rl-cache-count', iMessageBodyCacheCount);
- message.fetchDataFromDom();
- }
}
+ message.body = body || textBody;
this.messageActiveDom(message.body);
this.hideMessageBodies();
@@ -612,7 +574,7 @@ class MessageUserStore {
this.initBlockquoteSwitcher(body);
}
- message.body.show();
+ message.body.hidden = false;
}
initMessageFlagsFromCache(message);
diff --git a/dev/Stores/User/Pgp.js b/dev/Stores/User/Pgp.js
index 9c7def9ce..28b5d1fe8 100644
--- a/dev/Stores/User/Pgp.js
+++ b/dev/Stores/User/Pgp.js
@@ -1,12 +1,134 @@
import ko from 'ko';
import { i18n } from 'Common/Translator';
-import { isNonEmptyArray, pString } from 'Common/Utils';
+import { isNonEmptyArray, pString, htmlToElement } from 'Common/Utils';
import AccountStore from 'Stores/User/Account';
import { showScreenPopup } from 'Knoin/Knoin';
+function controlsHelper(dom, verControl, success, title, text)
+{
+ dom.classList.toggle('error', !success);
+ dom.classList.toggle('success', success);
+ verControl.classList.toggle('error', !success);
+ verControl.classList.toggle('success', success);
+ dom.title = verControl.title = title;
+
+ if (undefined !== text) {
+ dom.textContent = text.trim();
+ }
+}
+
+function domControlEncryptedClickHelper(store, dom, armoredMessage, recipients) {
+ return function() {
+ let message = null;
+
+ if (this.classList.contains('success')) {
+ return false;
+ }
+
+ try {
+ message = store.openpgp.message.readArmored(armoredMessage);
+ } catch (e) {
+ console.log(e);
+ }
+
+ if (message && message.getText && message.verify && message.decrypt) {
+ store.decryptMessage(
+ message,
+ recipients,
+ (validPrivateKey, decryptedMessage, validPublicKey, signingKeyIds) => {
+ if (decryptedMessage) {
+ if (validPublicKey) {
+ controlsHelper(
+ dom,
+ this,
+ true,
+ i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
+ 'USER': validPublicKey.user + ' (' + validPublicKey.id + ')'
+ }),
+ decryptedMessage.getText()
+ );
+ } else if (validPrivateKey) {
+ const keyIds = isNonEmptyArray(signingKeyIds) ? signingKeyIds : null,
+ additional = keyIds
+ ? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(value => !!value).join(', ')
+ : '';
+
+ controlsHelper(
+ dom,
+ this,
+ false,
+ i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') + (additional ? ' (' + additional + ')' : ''),
+ decryptedMessage.getText()
+ );
+ } else {
+ controlsHelper(dom, this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
+ }
+ } else {
+ controlsHelper(dom, this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
+ }
+ }
+ );
+
+ return false;
+ }
+
+ controlsHelper(dom, this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
+ return false;
+ };
+}
+
+function domControlSignedClickHelper(store, dom, armoredMessage) {
+ return function() {
+ let message = null;
+
+ if (this.classList.contains('success') || this.classList.contains('error')) {
+ return false;
+ }
+
+ try {
+ message = store.openpgp.cleartext.readArmored(armoredMessage);
+ } catch (e) {
+ console.log(e);
+ }
+
+ if (message && message.getText && message.verify) {
+ store.verifyMessage(message, (validKey, signingKeyIds) => {
+ if (validKey) {
+ controlsHelper(
+ dom,
+ this,
+ true,
+ i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
+ 'USER': validKey.user + ' (' + validKey.id + ')'
+ }),
+ message.getText()
+ );
+ } else {
+ const keyIds = isNonEmptyArray(signingKeyIds) ? signingKeyIds : null,
+ additional = keyIds
+ ? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(value => !!value).join(', ')
+ : '';
+
+ controlsHelper(
+ dom,
+ this,
+ false,
+ i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') + (additional ? ' (' + additional + ')' : '')
+ );
+ }
+ });
+
+ return false;
+ }
+
+ controlsHelper(dom, this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
+ return false;
+ };
+}
+
class PgpUserStore {
constructor() {
this.capaOpenPGP = ko.observable(false);
@@ -209,174 +331,34 @@ class PgpUserStore {
return false;
}
- controlsHelper(dom, verControl, success, title, text) {
- if (success) {
- dom
- .removeClass('error')
- .addClass('success')
- .attr('title', title);
- verControl
- .removeClass('error')
- .addClass('success')
- .attr('title', title);
- } else {
- dom
- .removeClass('success')
- .addClass('error')
- .attr('title', title);
- verControl
- .removeClass('success')
- .addClass('error')
- .attr('title', title);
- }
-
- if (undefined !== text) {
- dom.text(text.trim());
- }
- }
-
- static domControlEncryptedClickHelper(store, dom, armoredMessage, recipients) {
- return function() {
- let message = null;
- const $this = jQuery(this); // eslint-disable-line no-invalid-this
-
- if ($this.hasClass('success')) {
- return false;
- }
-
- try {
- message = store.openpgp.message.readArmored(armoredMessage);
- } catch (e) {
- console.log(e);
- }
-
- if (message && message.getText && message.verify && message.decrypt) {
- store.decryptMessage(
- message,
- recipients,
- (validPrivateKey, decryptedMessage, validPublicKey, signingKeyIds) => {
- if (decryptedMessage) {
- if (validPublicKey) {
- store.controlsHelper(
- dom,
- $this,
- true,
- i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
- 'USER': validPublicKey.user + ' (' + validPublicKey.id + ')'
- }),
- decryptedMessage.getText()
- );
- } else if (validPrivateKey) {
- const keyIds = isNonEmptyArray(signingKeyIds) ? signingKeyIds : null,
- additional = keyIds
- ? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(value => !!value).join(', ')
- : '';
-
- store.controlsHelper(
- dom,
- $this,
- false,
- i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') + (additional ? ' (' + additional + ')' : ''),
- decryptedMessage.getText()
- );
- } else {
- store.controlsHelper(dom, $this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
- }
- } else {
- store.controlsHelper(dom, $this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
- }
- }
- );
-
- return false;
- }
-
- store.controlsHelper(dom, $this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
- return false;
- };
- }
-
- static domControlSignedClickHelper(store, dom, armoredMessage) {
- return function() {
- let message = null;
- const $this = jQuery(this); // eslint-disable-line no-invalid-this
-
- if ($this.hasClass('success') || $this.hasClass('error')) {
- return false;
- }
-
- try {
- message = store.openpgp.cleartext.readArmored(armoredMessage);
- } catch (e) {
- console.log(e);
- }
-
- if (message && message.getText && message.verify) {
- store.verifyMessage(message, (validKey, signingKeyIds) => {
- if (validKey) {
- store.controlsHelper(
- dom,
- $this,
- true,
- i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
- 'USER': validKey.user + ' (' + validKey.id + ')'
- }),
- message.getText()
- );
- } else {
- const keyIds = isNonEmptyArray(signingKeyIds) ? signingKeyIds : null,
- additional = keyIds
- ? keyIds.map(item => (item && item.toHex ? item.toHex() : null)).filter(value => !!value).join(', ')
- : '';
-
- store.controlsHelper(
- dom,
- $this,
- false,
- i18n('PGP_NOTIFICATIONS/UNVERIFIRED_SIGNATURE') + (additional ? ' (' + additional + ')' : '')
- );
- }
- });
-
- return false;
- }
-
- store.controlsHelper(dom, $this, false, i18n('PGP_NOTIFICATIONS/DECRYPTION_ERROR'));
- return false;
- };
- }
-
/**
* @param {*} dom
* @param {MessageModel} rainLoopMessage
*/
initMessageBodyControls(dom, rainLoopMessage) {
- if (dom && !dom.hasClass('inited')) {
- dom.addClass('inited');
+ const cl = dom && dom.classList;
+ if (!cl.has('inited')) {
+ cl.add('inited');
- const encrypted = dom.hasClass('encrypted'),
- signed = dom.hasClass('signed'),
+ const encrypted = cl.has('encrypted'),
+ signed = cl.has('signed'),
recipients = rainLoopMessage ? rainLoopMessage.getEmails(['from', 'to', 'cc']) : [];
let verControl = null;
if (encrypted || signed) {
- const domText = dom.text();
- dom.data('openpgp-original', domText);
+ const domText = dom.textContent;
+ verControl = htmlToElement(''); // 🔒
if (encrypted) {
- verControl = jQuery('')
- .attr('title', i18n('MESSAGE/PGP_ENCRYPTED_MESSAGE_DESC'))
- .on('click', PgpUserStore.domControlEncryptedClickHelper(this, dom, domText, recipients));
- } else if (signed) {
- verControl = jQuery('')
- .attr('title', i18n('MESSAGE/PGP_SIGNED_MESSAGE_DESC'))
- .on('click', PgpUserStore.domControlSignedClickHelper(this, dom, domText));
+ verControl.title = i18n('MESSAGE/PGP_ENCRYPTED_MESSAGE_DESC');
+ verControl.addEventHandler('click', domControlEncryptedClickHelper(this, dom, domText, recipients));
+ } else {
+ verControl.title = i18n('MESSAGE/PGP_SIGNED_MESSAGE_DESC');
+ verControl.addEventHandler('click', domControlSignedClickHelper(this, dom, domText));
}
- if (verControl) {
- dom.before(verControl).before('');
- }
+ dom.before(verControl, document.createElement('div'));
}
}
}
diff --git a/dev/Stores/User/Settings.js b/dev/Stores/User/Settings.js
index 991839343..2115d62ee 100644
--- a/dev/Stores/User/Settings.js
+++ b/dev/Stores/User/Settings.js
@@ -2,7 +2,6 @@ import ko from 'ko';
import { MESSAGES_PER_PAGE, MESSAGES_PER_PAGE_VALUES } from 'Common/Consts';
import { Layout, EditorDefaultType } from 'Common/Enums';
-import { $htmlCL } from 'Common/Globals';
import { pInt } from 'Common/Utils';
import * as Settings from 'Storage/Settings';
@@ -43,10 +42,11 @@ class SettingsUserStore {
}
subscribers() {
- this.layout.subscribe((value) => {
- $htmlCL.toggle('rl-no-preview-pane', Layout.NoPreview === value);
- $htmlCL.toggle('rl-side-preview-pane', Layout.SidePreview === value);
- $htmlCL.toggle('rl-bottom-preview-pane', Layout.BottomPreview === value);
+ const htmlCL = document.documentElement.classList;
+ this.layout.subscribe(value => {
+ htmlCL.toggle('rl-no-preview-pane', Layout.NoPreview === value);
+ htmlCL.toggle('rl-side-preview-pane', Layout.SidePreview === value);
+ htmlCL.toggle('rl-bottom-preview-pane', Layout.BottomPreview === value);
dispatchEvent(new CustomEvent('rl-layout', {detail:value}));
});
}
diff --git a/dev/Styles/MessageView.less b/dev/Styles/MessageView.less
index 841c61028..4fc74e60a 100644
--- a/dev/Styles/MessageView.less
+++ b/dev/Styles/MessageView.less
@@ -376,13 +376,13 @@ html.rl-no-preview-pane {
background-color: #eee;
border: 1px solid #999;
- display: inline-block;
+ display: block;
width: 30px;
height: 14px;
line-height: 14px;
text-align: center;
cursor: pointer;
- margin: 10px 0px;
+ margin: 2em 0 10px;
opacity: 0.5;
&:hover {
diff --git a/dev/View/Admin/Login.js b/dev/View/Admin/Login.js
index 40804ccdc..41cb50884 100644
--- a/dev/View/Admin/Login.js
+++ b/dev/View/Admin/Login.js
@@ -1,7 +1,5 @@
import ko from 'ko';
-import { triggerAutocompleteInputChange } from 'Common/Utils';
-
import { StorageResultType, Notification } from 'Common/Enums';
import { getNotification } from 'Common/Translator';
@@ -37,8 +35,6 @@ class LoginAdminView extends AbstractViewNext {
this.loginErrorAnimation = ko.observable(false).extend({ 'falseTimeout': 500 });
this.passwordErrorAnimation = ko.observable(false).extend({ 'falseTimeout': 500 });
-// this.loginFocus = ko.observable(false);
-
this.formHidden = ko.observable(false);
this.formError = ko.computed(() => this.loginErrorAnimation() || this.passwordErrorAnimation());
@@ -59,8 +55,6 @@ class LoginAdminView extends AbstractViewNext {
@command((self) => !self.submitRequest())
submitCommand() {
- triggerAutocompleteInputChange();
-
this.loginError(false);
this.passwordError(false);
@@ -98,13 +92,6 @@ class LoginAdminView extends AbstractViewNext {
routeOff();
}
- onHide() {
- }
-
- onBuild() {
- triggerAutocompleteInputChange(true);
- }
-
submitForm() {
this.submitCommand();
}
diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js
index fc15d56d5..ed654d6ed 100644
--- a/dev/View/Popup/Compose.js
+++ b/dev/View/Popup/Compose.js
@@ -13,7 +13,6 @@ import {
import {
isNonEmptyArray,
- clearBqSwitcher,
replySubjectAdd,
encodeHtml,
inFocus,
@@ -855,13 +854,7 @@ class ComposePopupView extends AbstractViewNext {
sDate = momentorFormat(message.dateTimeStampInUTC(), 'FULL');
sSubject = message.subject();
aDraftInfo = message.aDraftInfo;
-
- const clonedText = jQuery(message.body).clone();
- if (clonedText) {
- clearBqSwitcher(clonedText);
-
- sText = clonedText.html();
- }
+ sText = message.bodyAsHTML();
let resplyAllParts = null;
switch (lineComposeType) {
diff --git a/dev/View/Popup/Contacts.js b/dev/View/Popup/Contacts.js
index 7d0524459..34d49e6b5 100644
--- a/dev/View/Popup/Contacts.js
+++ b/dev/View/Popup/Contacts.js
@@ -610,9 +610,7 @@ class ContactsPopupView extends AbstractViewNext {
}
onBuild(dom) {
- this.oContentVisible = jQuery('.b-list-content', dom);
-
- this.selector.init(this.oContentVisible, this.oContentVisible, KeyState.ContactList);
+ this.selector.init(dom[0].querySelector('.b-list-content'), KeyState.ContactList);
key('delete', KeyState.ContactList, () => {
this.deleteCommand();
diff --git a/dev/View/Popup/MessageOpenPgp.js b/dev/View/Popup/MessageOpenPgp.js
index fb12b4f69..0e37ee867 100644
--- a/dev/View/Popup/MessageOpenPgp.js
+++ b/dev/View/Popup/MessageOpenPgp.js
@@ -120,10 +120,8 @@ class MessageOpenPgpPopupView extends AbstractViewNext {
this.privateKeys(privateKeys);
if (this.viewModelDom) {
- this.viewModelDom
- .find('.key-list__item')
- .first()
- .click();
+ const el = this.viewModelDom.querySelector('.key-list__item');
+ el && el.click();
}
}
}
diff --git a/dev/View/User/Login.js b/dev/View/User/Login.js
index 35b73e28f..8df922182 100644
--- a/dev/View/User/Login.js
+++ b/dev/View/User/Login.js
@@ -8,7 +8,7 @@ import {
Notification
} from 'Common/Enums';
-import { convertLangName, triggerAutocompleteInputChange } from 'Common/Utils';
+import { convertLangName } from 'Common/Utils';
import { getNotification, getNotificationFromResponse, reload as translatorReload } from 'Common/Translator';
@@ -72,9 +72,6 @@ class LoginUserView extends AbstractViewNext {
(this.additionalCode.visibility() && this.additionalCode.errorAnimation())
);
-// this.emailFocus = ko.observable(false);
-// this.passwordFocus = ko.observable(false);
-
this.email.subscribe(() => {
this.emailError(false);
this.additionalCode('');
@@ -144,8 +141,6 @@ class LoginUserView extends AbstractViewNext {
@command((self) => !self.submitRequest())
submitCommand() {
- triggerAutocompleteInputChange();
-
this.emailError(false);
this.passwordError(false);
@@ -280,8 +275,6 @@ class LoginUserView extends AbstractViewNext {
);
});
}, 50);
-
- triggerAutocompleteInputChange(true);
}
submitForm() {
@@ -291,16 +284,6 @@ class LoginUserView extends AbstractViewNext {
selectLanguage() {
showScreenPopup(require('View/Popup/Languages'), [this.language, this.languages(), LanguageStore.userLanguage()]);
}
-
- selectLanguageOnTab(bShift) {
- if (!bShift) {
-// setTimeout(() => this.emailFocus(true), 50);
-
- return false;
- }
-
- return true;
- }
}
export { LoginUserView, LoginUserView as default };
diff --git a/dev/View/User/MailBox/FolderList.js b/dev/View/User/MailBox/FolderList.js
index 7a42d7c4f..a326d0948 100644
--- a/dev/View/User/MailBox/FolderList.js
+++ b/dev/View/User/MailBox/FolderList.js
@@ -17,8 +17,6 @@ import { getApp } from 'Helper/Apps/User';
import { view, ViewType, showScreenPopup, setHash } from 'Knoin/Knoin';
import { AbstractViewNext } from 'Knoin/AbstractViewNext';
-const $ = jQuery;
-
@view({
name: 'View/User/MailBox/FolderList',
type: ViewType.Left,
@@ -28,7 +26,6 @@ class FolderListMailBoxUserView extends AbstractViewNext {
constructor() {
super();
- this.oContentVisible = null;
this.oContentScrollable = null;
this.composeInEdit = AppStore.composeInEdit;
@@ -61,10 +58,8 @@ class FolderListMailBoxUserView extends AbstractViewNext {
}
onBuild(dom) {
- this.oContentVisible = $('.b-content', dom);
- this.oContentScrollable = this.oContentVisible ? this.oContentVisible[0] : null;
-
const self = this,
+ qs = s => dom[0].querySelector(s),
isMobile = Settings.appSettingsGet('mobile'),
fSelectFolder = (el, event, starred) => {
const isMove = moveAction();
@@ -108,6 +103,8 @@ class FolderListMailBoxUserView extends AbstractViewNext {
}
};
+ this.oContentScrollable = qs('.b-content');
+
dom
.on('click', '.b-folders .e-item .e-link .e-collapsed-sign', function(event) {
// eslint-disable-line prefer-arrow-callback
@@ -132,21 +129,22 @@ class FolderListMailBoxUserView extends AbstractViewNext {
key('up, down', KeyState.FolderList, (event, handler) => {
const keyCode = handler && 'up' === handler.shortcut ? EventKeyCode.Up : EventKeyCode.Down,
- $items = $('.b-folders .e-item .e-link:not(.hidden):visible', dom);
-
- if (event && $items.length) {
- let index = $items.index($items.filter('.focused'));
- if (-1 < index) {
- $items.eq(index).removeClass('focused');
+ $items = jQuery('.b-folders .e-item .e-link:not(.hidden):visible', dom);
+ let index = $items.length;
+ if (event && index) {
+ while (index--) {
+ if ($items[index].matches('.focused')) {
+ $items[index].classList.remove('focused');
+ break;
+ }
}
-
if (EventKeyCode.Up === keyCode && 0 < index) {
- index -= 1;
+ --index;
} else if (EventKeyCode.Down === keyCode && index < $items.length - 1) {
- index += 1;
+ ++index;
}
- $items.eq(index).addClass('focused');
+ $items[index].classList.add('focused');
self.scrollToFocused();
}
@@ -154,24 +152,22 @@ class FolderListMailBoxUserView extends AbstractViewNext {
});
key('enter', KeyState.FolderList, () => {
- const $items = $('.b-folders .e-item .e-link:not(.hidden).focused', dom);
- if ($items.length && $items[0]) {
+ const item = qs('.b-folders .e-item .e-link:not(.hidden).focused');
+ if (item) {
AppStore.focusedState(Focused.MessageList);
- $items.click();
+ item.click();
}
return false;
});
key('space', KeyState.FolderList, () => {
- const $items = $('.b-folders .e-item .e-link:not(.hidden).focused', dom);
- if ($items.length && $items[0]) {
- const folder = ko.dataFor($items[0]);
- if (folder) {
- const collapsed = folder.collapsed();
- getApp().setExpandedFolder(folder.fullNameHash, collapsed);
- folder.collapsed(!collapsed);
- }
+ const item = qs('.b-folders .e-item .e-link:not(.hidden).focused'),
+ folder = item && ko.dataFor(item);
+ if (folder) {
+ const collapsed = folder.collapsed();
+ getApp().setExpandedFolder(folder.fullNameHash, collapsed);
+ folder.collapsed(!collapsed);
}
return false;
@@ -183,10 +179,12 @@ class FolderListMailBoxUserView extends AbstractViewNext {
return false;
});
- AppStore.focusedState.subscribe((value) => {
- $('.b-folders .e-item .e-link.focused', dom).removeClass('focused');
+ AppStore.focusedState.subscribe(value => {
+ let el = qs('.b-folders .e-item .e-link.focused');
+ el && qs('.b-folders .e-item .e-link.focused').classList.remove('focused');
if (Focused.FolderList === value) {
- $('.b-folders .e-item .e-link.selected', dom).addClass('focused');
+ el = qs('.b-folders .e-item .e-link.selected');
+ el && qs('.b-folders .e-item .e-link.selected').classList.add('focused');
}
});
}
@@ -206,28 +204,20 @@ class FolderListMailBoxUserView extends AbstractViewNext {
}
scrollToFocused() {
- if (!this.oContentVisible || !this.oContentScrollable) {
- return false;
- }
-
- const offset = 20,
- focused = $('.e-item .e-link.focused', this.oContentScrollable),
- pos = focused.position(),
- visibleHeight = this.oContentVisible.height(),
- focusedHeight = focused.outerHeight();
-
- if (pos && (0 > pos.top || pos.top + focusedHeight > visibleHeight)) {
- let top = this.oContentScrollable.scrollTop + pos.top;
- if (0 > pos.top) {
- this.oContentScrollable.scrollTop = top - offset;
- } else {
- this.oContentScrollable.scrollTop = top - visibleHeight + focusedHeight + offset;
+ const scrollable = this.oContentScrollable;
+ if (scrollable) {
+ let block, focused = scrollable.querySelector('.e-item .e-link.focused');
+ if (focused) {
+ const fRect = focused.getBoundingClientRect(),
+ sRect = scrollable.getBoundingClientRect();
+ if (fRect.top < sRect.top) {
+ block = 'start';
+ } else if (fRect.bottom > sRect.bottom) {
+ block = 'end';
+ }
+ block && focused.scrollIntoView(block === 'start');
}
-
- return true;
}
-
- return false;
}
/**
@@ -237,9 +227,9 @@ class FolderListMailBoxUserView extends AbstractViewNext {
*/
messagesDrop(toFolder, ui) {
if (toFolder && ui && ui.helper) {
- const fromFolderFullNameRaw = ui.helper.data('rl-folder'),
+ const fromFolderFullNameRaw = ui.helper.rlFolder,
copy = $htmlCL.contains('rl-ctrl-key-pressed'),
- uids = ui.helper.data('rl-uids');
+ uids = ui.helper.rlUids;
if (fromFolderFullNameRaw && Array.isArray(uids)) {
getApp().moveMessagesToFolder(fromFolderFullNameRaw, uids, toFolder.fullNameRaw, copy);
diff --git a/dev/View/User/MailBox/MessageList.js b/dev/View/User/MailBox/MessageList.js
index 35a67cbc7..1659f9dcf 100644
--- a/dev/View/User/MailBox/MessageList.js
+++ b/dev/View/User/MailBox/MessageList.js
@@ -15,7 +15,7 @@ import { UNUSED_OPTION_VALUE } from 'Common/Consts';
import { bMobileDevice, leftPanelDisabled, moveAction } from 'Common/Globals';
-import { computedPagenatorHelper, draggablePlace, friendlySize } from 'Common/Utils';
+import { computedPagenatorHelper, friendlySize, htmlToElement } from 'Common/Utils';
import { mailBox, append } from 'Common/Links';
import { Selector } from 'Common/Selector';
@@ -267,9 +267,9 @@ class MessageListMailBoxUserView extends AbstractViewNext {
}
});
- MessageStore.messageListEndHash.subscribe(() => {
- this.selector.scrollToTop();
- });
+ MessageStore.messageListEndHash.subscribe((() =>
+ this.selector.scrollToFocused()
+ ).throttle(50));
}
@command()
@@ -502,14 +502,20 @@ class MessageListMailBoxUserView extends AbstractViewNext {
oMessageListItem.checked(true);
}
- const el = draggablePlace(),
+ const el = htmlToElement('' +
+ ' ' +
+ '' +
+ '' +
+ ''),
updateUidsInfo = () => {
const uids = MessageStore.messageListCheckedOrSelectedUidsWithSubMails();
- el.data('rl-uids', uids);
- el.find('.text').text('' + uids.length);
+ el.rlUids = uids;
+ el.querySelector('.text').textContent = uids.length;
};
- el.data('rl-folder', FolderStore.currentFolderFullNameRaw());
+ document.getElementById('rl-hidden').append(el);
+
+ el.rlFolder = FolderStore.currentFolderFullNameRaw();
updateUidsInfo();
setTimeout(updateUidsInfo,1);
@@ -735,9 +741,7 @@ class MessageListMailBoxUserView extends AbstractViewNext {
onBuild(dom) {
const self = this;
- this.oContentVisible = jQuery('.b-content', dom);
-
- this.selector.init(this.oContentVisible, this.oContentVisible, KeyState.MessageList);
+ this.selector.init(dom[0].querySelector('.b-content'), KeyState.MessageList);
if (this.mobile) {
dom.on('click', () => {
diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js
index 9cbd4fd7c..eef7b7e05 100644
--- a/dev/View/User/MailBox/MessageView.js
+++ b/dev/View/User/MailBox/MessageView.js
@@ -243,8 +243,8 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
return '';
});
- this.messageActiveDom.subscribe((dom) => {
- this.bodyBackgroundColor(dom ? this.detectDomBackgroundColor(dom) : '');
+ this.messageActiveDom.subscribe(dom => {
+ this.bodyBackgroundColor(this.detectDomBackgroundColor(dom));
}, this);
this.message.subscribe((message) => {
@@ -357,45 +357,26 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
}
detectDomBackgroundColor(dom) {
- let limit = 5,
- result = '';
+ let color = '';
- const fFindDom = function(inputDom) {
- const children = inputDom ? inputDom.children() : null;
- return children && 1 === children.length && children.is('table,div,center') ? children : null;
- },
- fFindColor = function(inputDom) {
- let color = '';
- if (inputDom) {
- color = inputDom.css('background-color') || '';
- if (!inputDom.is('table')) {
- color = isTransparent(color) ? '' : color;
- }
- }
+ if (dom) {
+ let limit = 5,
+ aC = dom;
+ while (!color && aC && limit--) {
+ let children = aC.children;
+ if (!children || 1 !== children.length || !children[0].matches('table,div,center')) break;
- return color;
- };
-
- if (dom && 1 === dom.length) {
- let aC = dom;
- while (!result) {
- limit -= 1;
- if (0 >= limit) {
- break;
- }
-
- aC = fFindDom(aC);
- if (aC) {
- result = fFindColor(aC);
- } else {
- break;
+ aC = children[0];
+ color = aC.style.backgroundColor || '';
+ if (!aC.matches('table')) {
+ color = isTransparent(color) ? '' : color;
}
}
- result = isTransparent(result) ? '' : result;
+ color = isTransparent(color) ? '' : color;
}
- return result;
+ return color;
}
fullScreen() {
@@ -545,7 +526,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
!!event &&
3 !== event.which &&
mailToHelper(
- jQuery(this).attr('href'),
+ this.href,
Settings.capa(Capa.Composer) ? require('View/Popup/Compose') : null // eslint-disable-line no-invalid-this
)
);
@@ -701,13 +682,11 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
// toggle message blockquotes
key('b', [KeyState.MessageList, KeyState.MessageView], () => {
- if (MessageStore.message() && MessageStore.message().body) {
- MessageStore.message()
- .body.find('.rlBlockquoteSwitcher')
- .click();
+ const message = MessageStore.message();
+ if (message && message.body) {
+ message.body.querySelectorAll('.rlBlockquoteSwitcher').forEach(node => node.click());
return false;
}
-
return true;
});
@@ -878,7 +857,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext {
*/
showImages(message) {
if (message && message.showExternalImages) {
- message.showExternalImages(true);
+ message.showExternalImages();
}
}
diff --git a/dev/boot.js b/dev/boot.js
index 91b6920f4..7cf230af1 100644
--- a/dev/boot.js
+++ b/dev/boot.js
@@ -16,7 +16,7 @@ progress.className = "progressjs-inner";
progress.appendChild(doc.createElement('div')).className = "progressjs-percent";
setPercentWidth(1);
-doc.body.appendChild(container);
+doc.body.append(container);
win.progressJs = new class {
set(percent) {
@@ -80,7 +80,7 @@ function writeCSS(css) {
const style = doc.createElement('style');
style.type = 'text/css';
style.textContent = css;
- doc.head.appendChild(style);
+ doc.head.append(style);
}
function loadScript(src) {
@@ -93,8 +93,8 @@ function loadScript(src) {
script.onerror = () => reject(new Error(src));
script.src = src;
// script.type = 'text/javascript';
- doc.head.appendChild(script);
-// doc.body.appendChild(element);
+ doc.head.append(script);
+// doc.body.append(element);
});
}
diff --git a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html
index a35007d67..a189c25fe 100644
--- a/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html
+++ b/rainloop/v/0.0.0/app/templates/Views/Admin/AdminLogin.html
@@ -9,7 +9,7 @@