mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-29 20:19:22 +03:00
Use less jQuery, more native
This commit is contained in:
parent
24cb874c87
commit
bdb36ec128
35 changed files with 492 additions and 779 deletions
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {?}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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'));
|
||||
|
|
|
|||
|
|
@ -3,8 +3,7 @@ import { Mime } from 'Common/Mime';
|
|||
|
||||
const
|
||||
doc = document,
|
||||
$ = jQuery,
|
||||
$div = $('<div></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 $(
|
||||
'<div class="draggablePlace">' +
|
||||
'<span class="text"></span> ' +
|
||||
'<i class="icon-copy icon-white visible-on-ctrl"></i>' +
|
||||
'<i class="icon-mail icon-white hidden-on-ctrl"></i>' +
|
||||
'</div>'
|
||||
).appendTo('#rl-hidden');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} domOption
|
||||
* @param {object} item
|
||||
|
|
@ -299,65 +291,6 @@ export function defautOptionsAfterRender(domItem, item) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} title
|
||||
* @param {Object} body
|
||||
* @param {boolean} isHtml
|
||||
* @param {boolean} print
|
||||
*/
|
||||
export function clearBqSwitcher(body) {
|
||||
body.find('blockquote.rl-bq-switcher').removeClass('rl-bq-switcher hidden-bq');
|
||||
body
|
||||
.find('.rlBlockquoteSwitcher')
|
||||
.off('.rlBlockquoteSwitcher')
|
||||
.remove();
|
||||
body.find('[data-html-editor-font-wrapper]').removeAttr('data-html-editor-font-wrapper');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {object} messageData
|
||||
* @param {Object} body
|
||||
* @param {boolean} isHtml
|
||||
* @param {boolean} print
|
||||
* @returns {void}
|
||||
*/
|
||||
export function previewMessage(
|
||||
{ title, subject, date, fromCreds, toCreds, toLabel, ccClass, ccCreds, ccLabel },
|
||||
body,
|
||||
isHtml,
|
||||
print
|
||||
) {
|
||||
const win = open(''),
|
||||
doc = win.document,
|
||||
bodyClone = body.clone(),
|
||||
bodyClass = isHtml ? 'html' : 'plain';
|
||||
|
||||
clearBqSwitcher(bodyClone);
|
||||
|
||||
const html = bodyClone ? bodyClone.html() : '';
|
||||
|
||||
doc.write(
|
||||
deModule(require('Html/PreviewMessage.html'))
|
||||
.replace('{{title}}', encodeHtml(title))
|
||||
.replace('{{subject}}', encodeHtml(subject))
|
||||
.replace('{{date}}', encodeHtml(date))
|
||||
.replace('{{fromCreds}}', encodeHtml(fromCreds))
|
||||
.replace('{{toCreds}}', encodeHtml(toCreds))
|
||||
.replace('{{toLabel}}', encodeHtml(toLabel))
|
||||
.replace('{{ccClass}}', encodeHtml(ccClass))
|
||||
.replace('{{ccCreds}}', encodeHtml(ccCreds))
|
||||
.replace('{{ccLabel}}', encodeHtml(ccLabel))
|
||||
.replace('{{bodyClass}}', bodyClass)
|
||||
.replace('{{html}}', html)
|
||||
);
|
||||
|
||||
doc.close();
|
||||
|
||||
if (print) {
|
||||
setTimeout(() => win.print(), 100);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Function} fCallback
|
||||
* @param {?} koTrigger
|
||||
|
|
@ -483,7 +416,7 @@ export function htmlToPlain(html) {
|
|||
fixAttibuteValue = (...args) => (args && 1 < args.length ? '' + args[1] + htmlspecialchars(args[2]) : ''),
|
||||
convertLinks = (...args) => (args && 1 < args.length ? args[1].trim() : '');
|
||||
|
||||
text = html
|
||||
tpl.innerHTML = html
|
||||
.replace(/<p[^>]*><\/p>/gi, '')
|
||||
.replace(/<pre[^>]*>([\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, '<blockquote>')
|
||||
.replace(/[\s]*~~~\/blockquote~~~/g, '</blockquote>')
|
||||
.replace(/\n/g, '<br />');
|
||||
|
||||
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}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue