mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-08-25 18:19:22 +03:00
Merge branch 'master' into plugin-hooks
This commit is contained in:
commit
bb05e3ada9
264 changed files with 875 additions and 9117 deletions
27
README.md
27
README.md
|
|
@ -116,23 +116,23 @@ RainLoop 1.15 vs SnappyMail
|
||||||
|
|
||||||
|js/* |RainLoop |Snappy |
|
|js/* |RainLoop |Snappy |
|
||||||
|--------------- |--------: |--------: |
|
|--------------- |--------: |--------: |
|
||||||
|admin.js |2.158.025 | 101.796 |
|
|admin.js |2.158.025 | 100.608 |
|
||||||
|app.js |4.215.733 | 501.679 |
|
|app.js |4.215.733 | 495.934 |
|
||||||
|boot.js | 672.433 | 4.726 |
|
|boot.js | 672.433 | 4.726 |
|
||||||
|libs.js | 647.679 | 227.974 |
|
|libs.js | 647.679 | 227.974 |
|
||||||
|polyfills.js | 325.908 | 0 |
|
|polyfills.js | 325.908 | 0 |
|
||||||
|serviceworker.js | 0 | 285 |
|
|serviceworker.js | 0 | 285 |
|
||||||
|TOTAL |8.019.778 | 836.460 |
|
|TOTAL |8.019.778 | 829.355 |
|
||||||
|
|
||||||
|js/min/* |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli |
|
|js/min/* |RainLoop |Snappy |RL gzip |SM gzip |RL brotli |SM brotli |
|
||||||
|--------------- |--------: |--------: |------: |------: |--------: |--------: |
|
|--------------- |--------: |--------: |------: |------: |--------: |--------: |
|
||||||
|admin.min.js | 255.514 | 51.172 | 73.899 | 15.082 | 60.674 | 13.491 |
|
|admin.min.js | 255.514 | 50.607 | 73.899 | 14.944 | 60.674 | 13.364 |
|
||||||
|app.min.js | 516.000 | 243.404 |140.430 | 71.302 |110.657 | 60.167 |
|
|app.min.js | 516.000 | 240.553 |140.430 | 70.291 |110.657 | 59.309 |
|
||||||
|boot.min.js | 66.456 | 2.525 | 22.553 | 1.391 | 20.043 | 1.201 |
|
|boot.min.js | 66.456 | 2.442 | 22.553 | 1.371 | 20.043 | 1.178 |
|
||||||
|libs.min.js | 574.626 | 115.877 |177.280 | 42.809 |151.855 | 38.099 |
|
|libs.min.js | 574.626 | 115.877 |177.280 | 42.809 |151.855 | 38.099 |
|
||||||
|polyfills.min.js | 32.608 | 0 | 11.315 | 0 | 10.072 | 0 |
|
|polyfills.min.js | 32.608 | 0 | 11.315 | 0 | 10.072 | 0 |
|
||||||
|TOTAL |1.445.204 | 412.978 |425.477 |130.584 |353.301 |112.958 |
|
|TOTAL |1.445.204 | 409.479 |425.477 |129.415 |353.301 |111.950 |
|
||||||
|TOTAL (no admin) |1.189.690 | 361.806 |351.061 |115.502 |292.627 | 99.467 |
|
|TOTAL (no admin) |1.189.690 | 358.872 |351.061 |114.471 |292.627 | 98.586 |
|
||||||
|
|
||||||
For a user its around 66% smaller and faster than traditional RainLoop.
|
For a user its around 66% smaller and faster than traditional RainLoop.
|
||||||
|
|
||||||
|
|
@ -166,12 +166,12 @@ For a user its around 66% smaller and faster than traditional RainLoop.
|
||||||
|
|
||||||
|css/* |RainLoop |Snappy |RL gzip |SM gzip |SM brotli |
|
|css/* |RainLoop |Snappy |RL gzip |SM gzip |SM brotli |
|
||||||
|------------ |-------: |-------: |------: |------: |--------: |
|
|------------ |-------: |-------: |------: |------: |--------: |
|
||||||
|app.css | 340.334 | 107.316 | 46,959 | 18.818 | 16.150 |
|
|app.css | 340.334 | 107.279 | 46,959 | 18.816 | 16.160 |
|
||||||
|app.min.css | 274.791 | 88.449 | 39.618 | 16.838 | 14.830 |
|
|app.min.css | 274.791 | 88.402 | 39.618 | 16.831 | 14.827 |
|
||||||
|boot.css | | 2.066 | | 913 | 742 |
|
|boot.css | | 2.066 | | 913 | 742 |
|
||||||
|boot.min.css | | 1.696 | | 818 | 664 |
|
|boot.min.css | | 1.696 | | 818 | 664 |
|
||||||
|admin.css | | 48.053 | | 9.494 | 8.310 |
|
|admin.css | | 46.393 | | 9.237 | 8.073 |
|
||||||
|admin.min.css | | 38.740 | | 8.441 | 7.501 |
|
|admin.min.css | | 37.306 | | 8.191 | 7.282 |
|
||||||
|
|
||||||
|
|
||||||
### Squire vs CKEditor
|
### Squire vs CKEditor
|
||||||
|
|
@ -189,8 +189,7 @@ Still TODO:
|
||||||
|
|
||||||
CKEditor including the 7 asset requests (css,language,plugins,icons) is 633.46 KB / 180.47 KB (gzip).
|
CKEditor including the 7 asset requests (css,language,plugins,icons) is 633.46 KB / 180.47 KB (gzip).
|
||||||
|
|
||||||
To use the old CKEditor, you must enable it in /data/\_data\_/\_default\_/configs/application.ini
|
To use the old CKEditor, you must install the plugin.
|
||||||
in the [labs] section add/edit: `use_ck_html_editor = On`
|
|
||||||
|
|
||||||
### PHP73 branch
|
### PHP73 branch
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
doc,
|
|
||||||
elementById,
|
elementById,
|
||||||
Settings
|
Settings
|
||||||
} from 'Common/Globals';
|
} from 'Common/Globals';
|
||||||
|
|
@ -26,27 +25,6 @@ export class AbstractApp {
|
||||||
this.Remote = Remote;
|
this.Remote = Remote;
|
||||||
}
|
}
|
||||||
|
|
||||||
remote() {
|
|
||||||
return this.Remote || null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} link
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
download(link) {
|
|
||||||
if (ThemeStore.isMobile()) {
|
|
||||||
open(link, '_self');
|
|
||||||
focus();
|
|
||||||
} else {
|
|
||||||
const oLink = doc.createElement('a');
|
|
||||||
oLink.href = link;
|
|
||||||
doc.body.appendChild(oLink).click();
|
|
||||||
oLink.remove();
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
logoutReload(close = false) {
|
logoutReload(close = false) {
|
||||||
const url = logoutLink();
|
const url = logoutLink();
|
||||||
|
|
||||||
|
|
@ -74,7 +52,7 @@ export class AbstractApp {
|
||||||
|
|
||||||
i18nToNodes(componentInfo.element);
|
i18nToNodes(componentInfo.element);
|
||||||
|
|
||||||
if (undefined !== params.inline && ko.unwrap(params.inline)) {
|
if (params.inline && ko.unwrap(params.inline)) {
|
||||||
params.element.style.display = 'inline-block';
|
params.element.style.display = 'inline-block';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -87,12 +65,8 @@ export class AbstractApp {
|
||||||
register('Input', InputComponent);
|
register('Input', InputComponent);
|
||||||
register('Select', SelectComponent);
|
register('Select', SelectComponent);
|
||||||
register('TextArea', TextAreaComponent);
|
register('TextArea', TextAreaComponent);
|
||||||
|
register('Checkbox', CheckboxMaterialDesignComponent, 'CheckboxMaterialDesignComponent');
|
||||||
register('CheckboxSimple', CheckboxComponent, 'CheckboxComponent');
|
register('CheckboxSimple', CheckboxComponent, 'CheckboxComponent');
|
||||||
if (!Settings.app('materialDesign')) {
|
|
||||||
register('Checkbox', CheckboxComponent);
|
|
||||||
} else {
|
|
||||||
register('Checkbox', CheckboxMaterialDesignComponent, 'CheckboxMaterialDesignComponent');
|
|
||||||
}
|
|
||||||
|
|
||||||
initOnStartOrLangChange();
|
initOnStartOrLangChange();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,6 @@ class AdminApp extends AbstractApp {
|
||||||
this.weakPassword = ko.observable(false);
|
this.weakPassword = ko.observable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootend() {
|
|
||||||
progressJs.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
bootstart() {
|
bootstart() {
|
||||||
super.bootstart();
|
super.bootstart();
|
||||||
|
|
||||||
|
|
@ -35,7 +31,7 @@ class AdminApp extends AbstractApp {
|
||||||
startScreens([LoginAdminScreen]);
|
startScreens([LoginAdminScreen]);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.bootend();
|
progressJs.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -867,6 +867,23 @@ class AppUser extends AbstractApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} link
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
download(link) {
|
||||||
|
if (ThemeStore.isMobile()) {
|
||||||
|
open(link, '_self');
|
||||||
|
focus();
|
||||||
|
} else {
|
||||||
|
const oLink = createElement('a');
|
||||||
|
oLink.href = link;
|
||||||
|
doc.body.appendChild(oLink).click();
|
||||||
|
oLink.remove();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
logout() {
|
logout() {
|
||||||
Remote.logout(() => this.logoutReload((SettingsGet('ParentEmail')||{length:0}).length));
|
Remote.logout(() => this.logoutReload((SettingsGet('ParentEmail')||{length:0}).length));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,96 +11,96 @@ const
|
||||||
sizes = ['B', 'KiB', 'MiB', 'GiB', 'TiB'],
|
sizes = ['B', 'KiB', 'MiB', 'GiB', 'TiB'],
|
||||||
|
|
||||||
exts = {
|
exts = {
|
||||||
'eml': 'message/rfc822',
|
eml: 'message/rfc822',
|
||||||
'mime': 'message/rfc822',
|
mime: 'message/rfc822',
|
||||||
'rtx': 'text/richtext',
|
rtx: 'text/richtext',
|
||||||
'vcard': 'text/vcard',
|
vcard: 'text/vcard',
|
||||||
'vcf': 'text/vcard',
|
vcf: 'text/vcard',
|
||||||
'htm': 'text/html',
|
htm: 'text/html',
|
||||||
'html': 'text/html',
|
html: 'text/html',
|
||||||
'csv': 'text/csv',
|
csv: 'text/csv',
|
||||||
'ics': 'text/calendar',
|
ics: 'text/calendar',
|
||||||
'ifb': 'text/calendar',
|
ifb: 'text/calendar',
|
||||||
'xml': 'text/xml',
|
xml: 'text/xml',
|
||||||
'json': app+'json',
|
json: app+'json',
|
||||||
'p10': app+'pkcs10',
|
p10: app+'pkcs10',
|
||||||
'p7c': app+'pkcs7-mime',
|
p7c: app+'pkcs7-mime',
|
||||||
'p7m': app+'pkcs7-mime',
|
p7m: app+'pkcs7-mime',
|
||||||
'p7s': app+'pkcs7-signature',
|
p7s: app+'pkcs7-signature',
|
||||||
'torrent': app+'x-bittorrent',
|
torrent: app+'x-bittorrent',
|
||||||
|
|
||||||
// scripts
|
// scripts
|
||||||
'js': app+'javascript',
|
js: app+'javascript',
|
||||||
'pl': 'text/perl',
|
pl: 'text/perl',
|
||||||
'css': 'text/css',
|
css: 'text/css',
|
||||||
'asp': 'text/asp',
|
asp: 'text/asp',
|
||||||
'php': app+'x-httpd-php',
|
php: app+'x-httpd-php',
|
||||||
'phtml': app+'x-httpd-php',
|
phtml: app+'x-httpd-php',
|
||||||
|
|
||||||
// images
|
// images
|
||||||
'jpg': 'image/jpeg',
|
jpg: 'image/jpeg',
|
||||||
'ico': 'image/x-icon',
|
ico: 'image/x-icon',
|
||||||
'tif': 'image/tiff',
|
tif: 'image/tiff',
|
||||||
'svg': 'image/svg+xml',
|
svg: 'image/svg+xml',
|
||||||
'svgz': 'image/svg+xml',
|
svgz: 'image/svg+xml',
|
||||||
|
|
||||||
// archives
|
// archives
|
||||||
'zip': app+'zip',
|
zip: app+'zip',
|
||||||
'7z': app+'x-7z-compressed',
|
'7z': app+'x-7z-compressed',
|
||||||
'rar': app+'x-rar-compressed',
|
rar: app+'x-rar-compressed',
|
||||||
'cab': app+'vnd.ms-cab-compressed',
|
cab: app+'vnd.ms-cab-compressed',
|
||||||
'gz': app+'x-gzip',
|
gz: app+'x-gzip',
|
||||||
'tgz': app+'x-gzip',
|
tgz: app+'x-gzip',
|
||||||
'bz': app+'x-bzip',
|
bz: app+'x-bzip',
|
||||||
'bz2': app+'x-bzip2',
|
bz2: app+'x-bzip2',
|
||||||
'deb': app+'x-debian-package',
|
deb: app+'x-debian-package',
|
||||||
|
|
||||||
// audio
|
// audio
|
||||||
'mp3': 'audio/mpeg',
|
mp3: 'audio/mpeg',
|
||||||
'wav': 'audio/x-wav',
|
wav: 'audio/x-wav',
|
||||||
'mp4a': 'audio/mp4',
|
mp4a: 'audio/mp4',
|
||||||
'weba': 'audio/webm',
|
weba: 'audio/webm',
|
||||||
'm3u': 'audio/x-mpegurl',
|
m3u: 'audio/x-mpegurl',
|
||||||
|
|
||||||
// video
|
// video
|
||||||
'qt': 'video/quicktime',
|
qt: 'video/quicktime',
|
||||||
'mov': 'video/quicktime',
|
mov: 'video/quicktime',
|
||||||
'wmv': 'video/windows-media',
|
wmv: 'video/windows-media',
|
||||||
'avi': 'video/x-msvideo',
|
avi: 'video/x-msvideo',
|
||||||
'3gp': 'video/3gpp',
|
'3gp': 'video/3gpp',
|
||||||
'3g2': 'video/3gpp2',
|
'3g2': 'video/3gpp2',
|
||||||
'mp4v': 'video/mp4',
|
mp4v: 'video/mp4',
|
||||||
'mpg4': 'video/mp4',
|
mpg4: 'video/mp4',
|
||||||
'ogv': 'video/ogg',
|
ogv: 'video/ogg',
|
||||||
'm4v': 'video/x-m4v',
|
m4v: 'video/x-m4v',
|
||||||
'asf': 'video/x-ms-asf',
|
asf: 'video/x-ms-asf',
|
||||||
'asx': 'video/x-ms-asf',
|
asx: 'video/x-ms-asf',
|
||||||
'wm': 'video/x-ms-wm',
|
wm: 'video/x-ms-wm',
|
||||||
'wmx': 'video/x-ms-wmx',
|
wmx: 'video/x-ms-wmx',
|
||||||
'wvx': 'video/x-ms-wvx',
|
wvx: 'video/x-ms-wvx',
|
||||||
'movie': 'video/x-sgi-movie',
|
movie: 'video/x-sgi-movie',
|
||||||
|
|
||||||
// adobe
|
// adobe
|
||||||
'pdf': app+'pdf',
|
pdf: app+'pdf',
|
||||||
'psd': 'image/vnd.adobe.photoshop',
|
psd: 'image/vnd.adobe.photoshop',
|
||||||
'ai': app+'postscript',
|
ai: app+'postscript',
|
||||||
'eps': app+'postscript',
|
eps: app+'postscript',
|
||||||
'ps': app+'postscript',
|
ps: app+'postscript',
|
||||||
|
|
||||||
// ms office
|
// ms office
|
||||||
'doc': app+'msword',
|
doc: app+'msword',
|
||||||
'rtf': app+'rtf',
|
rtf: app+'rtf',
|
||||||
'xls': app+'vnd.ms-excel',
|
xls: app+'vnd.ms-excel',
|
||||||
'ppt': app+'vnd.ms-powerpoint',
|
ppt: app+'vnd.ms-powerpoint',
|
||||||
'docx': msOffice+'wordprocessingml.document',
|
docx: msOffice+'wordprocessingml.document',
|
||||||
'xlsx': msOffice+'spreadsheetml.sheet',
|
xlsx: msOffice+'spreadsheetml.sheet',
|
||||||
'dotx': msOffice+'wordprocessingml.template',
|
dotx: msOffice+'wordprocessingml.template',
|
||||||
'pptx': msOffice+'presentationml.presentation',
|
pptx: msOffice+'presentationml.presentation',
|
||||||
|
|
||||||
// open office
|
// open office
|
||||||
'odt': openDoc+'text',
|
odt: openDoc+'text',
|
||||||
'ods': openDoc+'spreadsheet',
|
ods: openDoc+'spreadsheet',
|
||||||
'odp': openDoc+'presentation'
|
odp: openDoc+'presentation'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const FileType = {
|
export const FileType = {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import { createCKEditor } from 'External/CKEditor.js';
|
|
||||||
|
|
||||||
const
|
const
|
||||||
htmlre = /[&<>"']/g,
|
htmlre = /[&<>"']/g,
|
||||||
htmlmap = {
|
htmlmap = {
|
||||||
|
|
@ -180,11 +178,11 @@ class HtmlEditor {
|
||||||
this.onReady && this.onReady();
|
this.onReady && this.onReady();
|
||||||
};
|
};
|
||||||
|
|
||||||
if (window.CKEDITOR) {
|
if (rl.createWYSIWYG) {
|
||||||
this.editor = createCKEditor(this.element);
|
this.editor = rl.createWYSIWYG(this.element, onReady);
|
||||||
this.editor.on('instanceReady', onReady);
|
}
|
||||||
} else {
|
if (!this.editor) {
|
||||||
this.editor = new SquireUI(this.element, this.editor);
|
this.editor = new SquireUI(this.element);
|
||||||
setTimeout(onReady,1);
|
setTimeout(onReady,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ export function runHook(name, args = []) {
|
||||||
* @param {?number=} timeout
|
* @param {?number=} timeout
|
||||||
*/
|
*/
|
||||||
rl.pluginRemoteRequest = (callback, action, parameters, timeout) => {
|
rl.pluginRemoteRequest = (callback, action, parameters, timeout) => {
|
||||||
rl.app && rl.app.remote().defaultRequest(callback, 'Plugin' + action, parameters, timeout);
|
rl.app && rl.app.Remote.defaultRequest(callback, 'Plugin' + action, parameters, timeout);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import ko from 'ko';
|
import ko from 'ko';
|
||||||
import { Notification, UploadErrorCode } from 'Common/Enums';
|
import { Notification, UploadErrorCode } from 'Common/Enums';
|
||||||
import { langLink } from 'Common/Links';
|
import { langLink } from 'Common/Links';
|
||||||
import { doc } from 'Common/Globals';
|
import { doc, createElement } from 'Common/Globals';
|
||||||
|
|
||||||
let I18N_DATA = window.rainloopI18N || {};
|
let I18N_DATA = window.rainloopI18N || {};
|
||||||
|
|
||||||
|
|
@ -14,19 +14,12 @@ export const trigger = ko.observable(false);
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function i18n(key, valueList, defaulValue) {
|
export function i18n(key, valueList, defaulValue) {
|
||||||
let valueName = '',
|
let result = I18N_DATA[key] || defaulValue || key;
|
||||||
result = I18N_DATA[key];
|
|
||||||
|
|
||||||
if (undefined === result) {
|
if (valueList) {
|
||||||
result = undefined === defaulValue ? key : defaulValue;
|
Object.entries(valueList).forEach(([key, value]) => {
|
||||||
}
|
result = result.replace('%' + key + '%', value);
|
||||||
|
});
|
||||||
if (null != valueList) {
|
|
||||||
for (valueName in valueList) {
|
|
||||||
if (Object.prototype.hasOwnProperty.call(valueList, valueName)) {
|
|
||||||
result = result.replace('%' + valueName + '%', valueList[valueName]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
@ -129,7 +122,7 @@ export function getUploadErrorDescByCode(code) {
|
||||||
*/
|
*/
|
||||||
export function reload(admin, language) {
|
export function reload(admin, language) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const script = doc.createElement('script');
|
const script = createElement('script');
|
||||||
script.onload = () => {
|
script.onload = () => {
|
||||||
// reload the data
|
// reload the data
|
||||||
if (window.rainloopI18N) {
|
if (window.rainloopI18N) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { SaveSettingsStep } from 'Common/Enums';
|
import { SaveSettingsStep } from 'Common/Enums';
|
||||||
import { doc, elementById } from 'Common/Globals';
|
import { doc, createElement, elementById } from 'Common/Globals';
|
||||||
|
|
||||||
export const
|
export const
|
||||||
isArray = Array.isArray,
|
isArray = Array.isArray,
|
||||||
|
|
@ -119,7 +119,7 @@ export function changeTheme(value, themeTrigger = ()=>{}) {
|
||||||
.then(data => {
|
.then(data => {
|
||||||
if (data && isArray(data) && 2 === data.length) {
|
if (data && isArray(data) && 2 === data.length) {
|
||||||
if (themeLink && !themeStyle) {
|
if (themeLink && !themeStyle) {
|
||||||
themeStyle = doc.createElement('style');
|
themeStyle = createElement('style');
|
||||||
themeStyle.id = 'app-theme-style';
|
themeStyle.id = 'app-theme-style';
|
||||||
themeLink.after(themeStyle);
|
themeLink.after(themeStyle);
|
||||||
themeLink.remove();
|
themeLink.remove();
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import { ComposeType, FolderType } from 'Common/EnumsUser';
|
||||||
import { EmailModel } from 'Model/Email';
|
import { EmailModel } from 'Model/Email';
|
||||||
import { encodeHtml } from 'Common/Html';
|
import { encodeHtml } from 'Common/Html';
|
||||||
import { isArray } from 'Common/Utils';
|
import { isArray } from 'Common/Utils';
|
||||||
import { doc } from 'Common/Globals';
|
import { createElement } from 'Common/Globals';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {(string|number)} value
|
* @param {(string|number)} value
|
||||||
|
|
@ -79,7 +79,7 @@ export function htmlToPlain(html) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const
|
const
|
||||||
tpl = doc.createElement('template'),
|
tpl = createElement('template'),
|
||||||
convertPre = (...args) =>
|
convertPre = (...args) =>
|
||||||
args && 1 < args.length
|
args && 1 < args.length
|
||||||
? args[1]
|
? args[1]
|
||||||
|
|
|
||||||
79
dev/External/CKEditor.js
vendored
79
dev/External/CKEditor.js
vendored
|
|
@ -1,79 +0,0 @@
|
||||||
export function createCKEditor(element)
|
|
||||||
{
|
|
||||||
const language = (rl.settings.get('Language') || 'en').toLowerCase(),
|
|
||||||
|
|
||||||
htmlEditorLangsMap = {
|
|
||||||
'ar_sa': 'ar-sa',
|
|
||||||
'pt_br': 'pt-br',
|
|
||||||
'zh_cn': 'zh-cn',
|
|
||||||
};
|
|
||||||
|
|
||||||
const editor = CKEDITOR.appendTo(element, {
|
|
||||||
title: false,
|
|
||||||
stylesSet: false,
|
|
||||||
// customConfig: '',
|
|
||||||
// contentsCss: '',
|
|
||||||
toolbarGroups: [
|
|
||||||
{ name: 'spec' },
|
|
||||||
{ name: 'styles' },
|
|
||||||
{ name: 'basicstyles', groups: ['basicstyles', 'cleanup', 'bidi'] },
|
|
||||||
{ name: 'colors' },
|
|
||||||
{ name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align'] },
|
|
||||||
{ name: 'links' },
|
|
||||||
{ name: 'insert' },
|
|
||||||
{ name: 'document', groups: ['mode', 'document', 'doctools'] },
|
|
||||||
{ name: 'others' }
|
|
||||||
],
|
|
||||||
|
|
||||||
removePlugins: 'liststyle' + (rl.settings.app('allowHtmlEditorBitiButtons') ? '' : ',bidi'),
|
|
||||||
removeButtons: 'Format,Undo,Redo,Cut,Copy,Paste,Anchor,Strike,Subscript,Superscript,Image,SelectAll'
|
|
||||||
+ (rl.settings.app('allowHtmlEditorSourceButton') ? '' : ',Source'),
|
|
||||||
removeDialogTabs: 'link:advanced;link:target;image:advanced;images:advanced',
|
|
||||||
|
|
||||||
extraPlugins: 'plain,signature',
|
|
||||||
|
|
||||||
allowedContent: true,
|
|
||||||
extraAllowedContent: true,
|
|
||||||
|
|
||||||
fillEmptyBlocks: false,
|
|
||||||
// ignoreEmptyParagraph: true,
|
|
||||||
disableNativeSpellChecker: false,
|
|
||||||
|
|
||||||
colorButton_enableAutomatic: false,
|
|
||||||
// colorButton_enableMore: true,
|
|
||||||
|
|
||||||
font_defaultLabel: 'Arial',
|
|
||||||
fontSize_defaultLabel: '13',
|
|
||||||
fontSize_sizes: '10/10px;12/12px;13/13px;14/14px;16/16px;18/18px;20/20px;24/24px;28/28px;36/36px;48/48px',
|
|
||||||
|
|
||||||
enterMode: CKEDITOR.ENTER_BR,
|
|
||||||
shiftEnterMode: CKEDITOR.ENTER_P,
|
|
||||||
language: htmlEditorLangsMap[language] || language.substr(0,2)
|
|
||||||
});
|
|
||||||
|
|
||||||
editor.on('key', event => !(event && event.data && 'Tab' == event.data.key));
|
|
||||||
|
|
||||||
editor.on('drop', event => {
|
|
||||||
const dt = event.data.dataTransfer,
|
|
||||||
id = dt.id,
|
|
||||||
file = dt.getFilesCount() ? dt.getFile(0) : 0;
|
|
||||||
if (file && id && file.type && file.type.match(/^image/i)) {
|
|
||||||
const imageId = `[img=${id}]`,
|
|
||||||
reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onloadend = () => {
|
|
||||||
if (reader.result && 'wysiwyg' === editor.mode) {
|
|
||||||
try {
|
|
||||||
editor.setData(editor.getData().replace(imageId, `<img src="${reader.result}"/>`));
|
|
||||||
} catch (e) {} // eslint-disable-line no-empty
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
|
|
||||||
dt.setData('text/html', imageId);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return editor;
|
|
||||||
}
|
|
||||||
12
dev/External/ko.js
vendored
12
dev/External/ko.js
vendored
|
|
@ -1,4 +1,4 @@
|
||||||
import { i18n, i18nToNodes, trigger } from 'Common/Translator';
|
import { i18nToNodes } from 'Common/Translator';
|
||||||
import { doc, createElement } from 'Common/Globals';
|
import { doc, createElement } from 'Common/Globals';
|
||||||
import { SaveSettingsStep } from 'Common/Enums';
|
import { SaveSettingsStep } from 'Common/Enums';
|
||||||
import { isNonEmptyArray, isFunction } from 'Common/Utils';
|
import { isNonEmptyArray, isFunction } from 'Common/Utils';
|
||||||
|
|
@ -6,16 +6,6 @@ import { isNonEmptyArray, isFunction } from 'Common/Utils';
|
||||||
const
|
const
|
||||||
koValue = value => !ko.isObservable(value) && isFunction(value) ? value() : ko.unwrap(value);
|
koValue = value => !ko.isObservable(value) && isFunction(value) ? value() : ko.unwrap(value);
|
||||||
|
|
||||||
ko.bindingHandlers.tooltip = {
|
|
||||||
init: (element, fValueAccessor) => {
|
|
||||||
const sValue = koValue(fValueAccessor());
|
|
||||||
element.title = i18n(sValue);
|
|
||||||
trigger.subscribe(() => element.title = i18n(sValue));
|
|
||||||
},
|
|
||||||
update: (element, fValueAccessor) =>
|
|
||||||
element.title = i18n(koValue(fValueAccessor()))
|
|
||||||
};
|
|
||||||
|
|
||||||
ko.bindingHandlers.tooltipErrorTip = {
|
ko.bindingHandlers.tooltipErrorTip = {
|
||||||
init: element => {
|
init: element => {
|
||||||
doc.addEventListener('click', () => element.removeAttribute('data-rainloopErrorTip'));
|
doc.addEventListener('click', () => element.removeAttribute('data-rainloopErrorTip'));
|
||||||
|
|
|
||||||
|
|
@ -272,22 +272,22 @@ export class MessageModel extends AbstractModel {
|
||||||
lineAsCss() {
|
lineAsCss() {
|
||||||
let classes = [];
|
let classes = [];
|
||||||
Object.entries({
|
Object.entries({
|
||||||
'deleted': this.deleted(),
|
deleted: this.deleted(),
|
||||||
'deleted-mark': this.isDeleted(),
|
'deleted-mark': this.isDeleted(),
|
||||||
'selected': this.selected(),
|
selected: this.selected(),
|
||||||
'checked': this.checked(),
|
checked: this.checked(),
|
||||||
'flagged': this.isFlagged(),
|
flagged: this.isFlagged(),
|
||||||
'unseen': this.isUnseen(),
|
unseen: this.isUnseen(),
|
||||||
'answered': this.isAnswered(),
|
answered: this.isAnswered(),
|
||||||
'forwarded': this.isForwarded(),
|
forwarded: this.isForwarded(),
|
||||||
'focused': this.focused(),
|
focused: this.focused(),
|
||||||
'important': this.isImportant(),
|
important: this.isImportant(),
|
||||||
'withAttachments': this.hasAttachments(),
|
withAttachments: this.hasAttachments(),
|
||||||
'new': this.newForAnimation(),
|
new: this.newForAnimation(),
|
||||||
'emptySubject': !this.subject(),
|
emptySubject: !this.subject(),
|
||||||
// 'hasChildrenMessage': 1 < this.threadsLen(),
|
// hasChildrenMessage: 1 < this.threadsLen(),
|
||||||
'hasUnseenSubMessage': this.hasUnseenSubMessage(),
|
hasUnseenSubMessage: this.hasUnseenSubMessage(),
|
||||||
'hasFlaggedSubMessage': this.hasFlaggedSubMessage()
|
hasFlaggedSubMessage: this.hasFlaggedSubMessage()
|
||||||
}).forEach(([key, value]) => value && classes.push(key));
|
}).forEach(([key, value]) => value && classes.push(key));
|
||||||
return classes.join(' ');
|
return classes.join(' ');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ export class AbstractFetchRemote
|
||||||
*/
|
*/
|
||||||
jsVersion(fCallback, sVersion) {
|
jsVersion(fCallback, sVersion) {
|
||||||
this.defaultRequest(fCallback, 'Version', {
|
this.defaultRequest(fCallback, 'Version', {
|
||||||
'Version': sVersion
|
Version: sVersion
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,19 +13,19 @@ export class BrandingAdminSettings {
|
||||||
|
|
||||||
this.title.subscribe(value =>
|
this.title.subscribe(value =>
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.title.trigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.title.trigger, this), {
|
||||||
'Title': value.trim()
|
Title: value.trim()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this.loadingDesc.subscribe(value =>
|
this.loadingDesc.subscribe(value =>
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.loadingDesc.trigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.loadingDesc.trigger, this), {
|
||||||
'LoadingDescription': value.trim()
|
LoadingDescription: value.trim()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
this.faviconUrl.subscribe(value =>
|
this.faviconUrl.subscribe(value =>
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.faviconUrl.trigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.faviconUrl.trigger, this), {
|
||||||
'FaviconUrl': value.trim()
|
FaviconUrl: value.trim()
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,12 +74,12 @@ export class ContactsAdminSettings {
|
||||||
addSubscribablesTo(this, {
|
addSubscribablesTo(this, {
|
||||||
enableContacts: value =>
|
enableContacts: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'ContactsEnable': value ? 1 : 0
|
ContactsEnable: value ? 1 : 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
contactsSync: value =>
|
contactsSync: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'ContactsSync': value ? 1 : 0
|
ContactsSync: value ? 1 : 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
contactsType: value => {
|
contactsType: value => {
|
||||||
|
|
@ -87,23 +87,23 @@ export class ContactsAdminSettings {
|
||||||
this.testContactsError(false);
|
this.testContactsError(false);
|
||||||
this.testContactsErrorMessage('');
|
this.testContactsErrorMessage('');
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.contactsTypeTrigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.contactsTypeTrigger, this), {
|
||||||
'ContactsPdoType': value.trim()
|
ContactsPdoType: value.trim()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
pdoDsn: value =>
|
pdoDsn: value =>
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.pdoDsnTrigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.pdoDsnTrigger, this), {
|
||||||
'ContactsPdoDsn': value.trim()
|
ContactsPdoDsn: value.trim()
|
||||||
}),
|
}),
|
||||||
|
|
||||||
pdoUser: value =>
|
pdoUser: value =>
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.pdoUserTrigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.pdoUserTrigger, this), {
|
||||||
'ContactsPdoUser': value.trim()
|
ContactsPdoUser: value.trim()
|
||||||
}),
|
}),
|
||||||
|
|
||||||
pdoPassword: value =>
|
pdoPassword: value =>
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.pdoPasswordTrigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.pdoPasswordTrigger, this), {
|
||||||
'ContactsPdoPassword': value.trim()
|
ContactsPdoPassword: value.trim()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -121,10 +121,10 @@ export class ContactsAdminSettings {
|
||||||
this.testing(true);
|
this.testing(true);
|
||||||
|
|
||||||
Remote.testContacts(this.onTestContactsResponse, {
|
Remote.testContacts(this.onTestContactsResponse, {
|
||||||
'ContactsPdoType': this.contactsType(),
|
ContactsPdoType: this.contactsType(),
|
||||||
'ContactsPdoDsn': this.pdoDsn(),
|
ContactsPdoDsn: this.pdoDsn(),
|
||||||
'ContactsPdoUser': this.pdoUser(),
|
ContactsPdoUser: this.pdoUser(),
|
||||||
'ContactsPdoPassword': this.pdoPassword()
|
ContactsPdoPassword: this.pdoPassword()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -93,12 +93,12 @@ export class GeneralAdminSettings {
|
||||||
addSubscribablesTo(this, {
|
addSubscribablesTo(this, {
|
||||||
mainAttachmentLimit: value =>
|
mainAttachmentLimit: value =>
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.attachmentLimitTrigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.attachmentLimitTrigger, this), {
|
||||||
'AttachmentLimit': pInt(value)
|
AttachmentLimit: pInt(value)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
language: value =>
|
language: value =>
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.languageTrigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.languageTrigger, this), {
|
||||||
'Language': value.trim()
|
Language: value.trim()
|
||||||
}),
|
}),
|
||||||
|
|
||||||
languageAdmin: value => {
|
languageAdmin: value => {
|
||||||
|
|
@ -106,14 +106,14 @@ export class GeneralAdminSettings {
|
||||||
translatorReload(true, value)
|
translatorReload(true, value)
|
||||||
.then(fReloadLanguageHelper(SaveSettingsStep.TrueResult), fReloadLanguageHelper(SaveSettingsStep.FalseResult))
|
.then(fReloadLanguageHelper(SaveSettingsStep.TrueResult), fReloadLanguageHelper(SaveSettingsStep.FalseResult))
|
||||||
.then(() => Remote.saveAdminConfig(null, {
|
.then(() => Remote.saveAdminConfig(null, {
|
||||||
'LanguageAdmin': value.trim()
|
LanguageAdmin: value.trim()
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
theme: value => {
|
theme: value => {
|
||||||
changeTheme(value, this.themeTrigger);
|
changeTheme(value, this.themeTrigger);
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.themeTrigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.themeTrigger, this), {
|
||||||
'Theme': value.trim()
|
Theme: value.trim()
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,27 +19,27 @@ export class LoginAdminSettings {
|
||||||
addSubscribablesTo(this, {
|
addSubscribablesTo(this, {
|
||||||
determineUserLanguage: value =>
|
determineUserLanguage: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'DetermineUserLanguage': value ? 1 : 0
|
DetermineUserLanguage: value ? 1 : 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
determineUserDomain: value =>
|
determineUserDomain: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'DetermineUserDomain': value ? 1 : 0
|
DetermineUserDomain: value ? 1 : 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
allowLanguagesOnLogin: value =>
|
allowLanguagesOnLogin: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'AllowLanguagesOnLogin': value ? 1 : 0
|
AllowLanguagesOnLogin: value ? 1 : 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
hideSubmitButton: value =>
|
hideSubmitButton: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'hideSubmitButton': value ? 1 : 0
|
hideSubmitButton: value ? 1 : 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
defaultDomain: value =>
|
defaultDomain: value =>
|
||||||
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.defaultDomain.trigger, this), {
|
Remote.saveAdminConfig(settingsSaveHelperSimpleFunction(this.defaultDomain.trigger, this), {
|
||||||
'LoginDefaultDomain': value.trim()
|
LoginDefaultDomain: value.trim()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export class PluginsAdminSettings {
|
||||||
|
|
||||||
this.enabledPlugins.subscribe(value =>
|
this.enabledPlugins.subscribe(value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'EnabledPlugins': value ? 1 : 0
|
EnabledPlugins: value ? 1 : 0
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,36 +57,36 @@ export class SecurityAdminSettings {
|
||||||
|
|
||||||
capaOpenPGP: value =>
|
capaOpenPGP: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'CapaOpenPGP': value ? 1 : 0
|
CapaOpenPGP: value ? 1 : 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
capaTwoFactorAuth: value => {
|
capaTwoFactorAuth: value => {
|
||||||
value || this.capaTwoFactorAuthForce(false);
|
value || this.capaTwoFactorAuthForce(false);
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'CapaTwoFactorAuth': value ? 1 : 0
|
CapaTwoFactorAuth: value ? 1 : 0
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
capaTwoFactorAuthForce: value =>
|
capaTwoFactorAuthForce: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'CapaTwoFactorAuthForce': value ? 1 : 0
|
CapaTwoFactorAuthForce: value ? 1 : 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
useLocalProxyForExternalImages: value =>
|
useLocalProxyForExternalImages: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'UseLocalProxyForExternalImages': value ? 1 : 0
|
UseLocalProxyForExternalImages: value ? 1 : 0
|
||||||
}),
|
}),
|
||||||
|
|
||||||
verifySslCertificate: value => {
|
verifySslCertificate: value => {
|
||||||
value => value || this.allowSelfSigned(true);
|
value => value || this.allowSelfSigned(true);
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'VerifySslCertificate': value ? 1 : 0
|
VerifySslCertificate: value ? 1 : 0
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
allowSelfSigned: value =>
|
allowSelfSigned: value =>
|
||||||
Remote.saveAdminConfig(null, {
|
Remote.saveAdminConfig(null, {
|
||||||
'AllowSelfSigned': value ? 1 : 0
|
AllowSelfSigned: value ? 1 : 0
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ export class ContactsUserSettings {
|
||||||
|
|
||||||
this.contactsAutosave.subscribe(value =>
|
this.contactsAutosave.subscribe(value =>
|
||||||
Remote.saveSettings(null, {
|
Remote.saveSettings(null, {
|
||||||
'ContactsAutosave': value ? 1 : 0
|
ContactsAutosave: value ? 1 : 0
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -68,19 +68,19 @@ export class GeneralUserSettings {
|
||||||
this.editorDefaultTypes = ko.computed(() => {
|
this.editorDefaultTypes = ko.computed(() => {
|
||||||
translatorTrigger();
|
translatorTrigger();
|
||||||
return [
|
return [
|
||||||
{ 'id': EditorDefaultType.Html, 'name': i18n('SETTINGS_GENERAL/LABEL_EDITOR_HTML') },
|
{ id: EditorDefaultType.Html, name: i18n('SETTINGS_GENERAL/LABEL_EDITOR_HTML') },
|
||||||
{ 'id': EditorDefaultType.Plain, 'name': i18n('SETTINGS_GENERAL/LABEL_EDITOR_PLAIN') },
|
{ id: EditorDefaultType.Plain, name: i18n('SETTINGS_GENERAL/LABEL_EDITOR_PLAIN') },
|
||||||
{ 'id': EditorDefaultType.HtmlForced, 'name': i18n('SETTINGS_GENERAL/LABEL_EDITOR_HTML_FORCED') },
|
{ id: EditorDefaultType.HtmlForced, name: i18n('SETTINGS_GENERAL/LABEL_EDITOR_HTML_FORCED') },
|
||||||
{ 'id': EditorDefaultType.PlainForced, 'name': i18n('SETTINGS_GENERAL/LABEL_EDITOR_PLAIN_FORCED') }
|
{ id: EditorDefaultType.PlainForced, name: i18n('SETTINGS_GENERAL/LABEL_EDITOR_PLAIN_FORCED') }
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
this.layoutTypes = ko.computed(() => {
|
this.layoutTypes = ko.computed(() => {
|
||||||
translatorTrigger();
|
translatorTrigger();
|
||||||
return [
|
return [
|
||||||
{ 'id': Layout.NoPreview, 'name': i18n('SETTINGS_GENERAL/LABEL_LAYOUT_NO_SPLIT') },
|
{ id: Layout.NoPreview, name: i18n('SETTINGS_GENERAL/LABEL_LAYOUT_NO_SPLIT') },
|
||||||
{ 'id': Layout.SidePreview, 'name': i18n('SETTINGS_GENERAL/LABEL_LAYOUT_VERTICAL_SPLIT') },
|
{ id: Layout.SidePreview, name: i18n('SETTINGS_GENERAL/LABEL_LAYOUT_VERTICAL_SPLIT') },
|
||||||
{ 'id': Layout.BottomPreview, 'name': i18n('SETTINGS_GENERAL/LABEL_LAYOUT_HORIZONTAL_SPLIT') }
|
{ id: Layout.BottomPreview, name: i18n('SETTINGS_GENERAL/LABEL_LAYOUT_HORIZONTAL_SPLIT') }
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -142,7 +142,7 @@ export class GeneralUserSettings {
|
||||||
}
|
}
|
||||||
|
|
||||||
testSystemNotification() {
|
testSystemNotification() {
|
||||||
NotificationUserStore.displayDesktopNotification('SnappyMail', 'Test notification', { });
|
NotificationUserStore.displayDesktopNotification('SnappyMail', 'Test notification');
|
||||||
}
|
}
|
||||||
|
|
||||||
selectLanguage() {
|
selectLanguage() {
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,14 @@ export class SecurityUserSettings {
|
||||||
this.autoLogoutOptions = ko.computed(() => {
|
this.autoLogoutOptions = ko.computed(() => {
|
||||||
translatorTrigger();
|
translatorTrigger();
|
||||||
return [
|
return [
|
||||||
{ 'id': 0, 'name': i18nLogout('NEVER_OPTION_NAME') },
|
{ id: 0, name: i18nLogout('NEVER_OPTION_NAME') },
|
||||||
{ 'id': 5, 'name': i18nLogout('MINUTES_OPTION_NAME', { 'MINUTES': 5 }) },
|
{ id: 5, name: i18nLogout('MINUTES_OPTION_NAME', { MINUTES: 5 }) },
|
||||||
{ 'id': 10, 'name': i18nLogout('MINUTES_OPTION_NAME', { 'MINUTES': 10 }) },
|
{ id: 10, name: i18nLogout('MINUTES_OPTION_NAME', { MINUTES: 10 }) },
|
||||||
{ 'id': 30, 'name': i18nLogout('MINUTES_OPTION_NAME', { 'MINUTES': 30 }) },
|
{ id: 30, name: i18nLogout('MINUTES_OPTION_NAME', { MINUTES: 30 }) },
|
||||||
{ 'id': 60, 'name': i18nLogout('MINUTES_OPTION_NAME', { 'MINUTES': 60 }) },
|
{ id: 60, name: i18nLogout('MINUTES_OPTION_NAME', { MINUTES: 60 }) },
|
||||||
{ 'id': 60 * 2, 'name': i18nLogout('HOURS_OPTION_NAME', { 'HOURS': 2 }) },
|
{ id: 60 * 2, name: i18nLogout('HOURS_OPTION_NAME', { HOURS: 2 }) },
|
||||||
{ 'id': 60 * 5, 'name': i18nLogout('HOURS_OPTION_NAME', { 'HOURS': 5 }) },
|
{ id: 60 * 5, name: i18nLogout('HOURS_OPTION_NAME', { HOURS: 5 }) },
|
||||||
{ 'id': 60 * 10, 'name': i18nLogout('HOURS_OPTION_NAME', { 'HOURS': 10 }) }
|
{ id: 60 * 10, name: i18nLogout('HOURS_OPTION_NAME', { HOURS: 10 }) }
|
||||||
];
|
];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export class ThemesUserSettings {
|
||||||
changeTheme(value, this.themeTrigger);
|
changeTheme(value, this.themeTrigger);
|
||||||
|
|
||||||
Remote.saveSettings(null, {
|
Remote.saveSettings(null, {
|
||||||
'Theme': value
|
Theme: value
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import ko from 'ko';
|
||||||
|
|
||||||
import { Scope, Notification } from 'Common/Enums';
|
import { Scope, Notification } from 'Common/Enums';
|
||||||
import { MessageSetAction } from 'Common/EnumsUser';
|
import { MessageSetAction } from 'Common/EnumsUser';
|
||||||
import { doc, elementById } from 'Common/Globals';
|
import { doc, createElement, elementById } from 'Common/Globals';
|
||||||
import { isNonEmptyArray, pInt, pString, addObservablesTo, addSubscribablesTo } from 'Common/Utils';
|
import { isNonEmptyArray, pInt, pString, addObservablesTo, addSubscribablesTo } from 'Common/Utils';
|
||||||
import { plainToHtml } from 'Common/UtilsUser';
|
import { plainToHtml } from 'Common/UtilsUser';
|
||||||
|
|
||||||
|
|
@ -247,16 +247,16 @@ export const MessageUserStore = new class {
|
||||||
NotificationUserStore.displayDesktopNotification(
|
NotificationUserStore.displayDesktopNotification(
|
||||||
AccountUserStore.email(),
|
AccountUserStore.email(),
|
||||||
i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', {
|
i18n('MESSAGE_LIST/NEW_MESSAGE_NOTIFICATION', {
|
||||||
'COUNT': len
|
COUNT: len
|
||||||
}),
|
}),
|
||||||
{ 'Url': mailBox(newMessages[0].Folder, 1) }
|
{ Url: mailBox(newMessages[0].Folder, 1) }
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
newMessages.forEach(item => {
|
newMessages.forEach(item => {
|
||||||
NotificationUserStore.displayDesktopNotification(
|
NotificationUserStore.displayDesktopNotification(
|
||||||
EmailCollectionModel.reviveFromJson(item.From).toString(),
|
EmailCollectionModel.reviveFromJson(item.From).toString(),
|
||||||
item.Subject,
|
item.Subject,
|
||||||
{ 'Folder': item.Folder, 'Uid': item.Uid }
|
{ Folder: item.Folder, Uid: item.Uid }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -504,7 +504,7 @@ export const MessageUserStore = new class {
|
||||||
/-----BEGIN PGP SIGNED MESSAGE-----/.test(plain) && /-----BEGIN PGP SIGNATURE-----/.test(plain);
|
/-----BEGIN PGP SIGNED MESSAGE-----/.test(plain) && /-----BEGIN PGP SIGNATURE-----/.test(plain);
|
||||||
}
|
}
|
||||||
|
|
||||||
const pre = doc.createElement('pre');
|
const pre = createElement('pre');
|
||||||
if (pgpSigned && message.isPgpSigned()) {
|
if (pgpSigned && message.isPgpSigned()) {
|
||||||
pre.className = 'b-plain-openpgp signed';
|
pre.className = 'b-plain-openpgp signed';
|
||||||
pre.textContent = plain;
|
pre.textContent = plain;
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import ko from 'ko';
|
||||||
|
|
||||||
import { i18n } from 'Common/Translator';
|
import { i18n } from 'Common/Translator';
|
||||||
import { isArray, isNonEmptyArray, pString } from 'Common/Utils';
|
import { isArray, isNonEmptyArray, pString } from 'Common/Utils';
|
||||||
import { doc } from 'Common/Globals';
|
import { createElement } from 'Common/Globals';
|
||||||
|
|
||||||
import { AccountUserStore } from 'Stores/User/Account';
|
import { AccountUserStore } from 'Stores/User/Account';
|
||||||
|
|
||||||
|
|
@ -49,7 +49,7 @@ function domControlEncryptedClickHelper(store, dom, armoredMessage, recipients)
|
||||||
this,
|
this,
|
||||||
true,
|
true,
|
||||||
i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
|
i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
|
||||||
'USER': validPublicKey.user + ' (' + validPublicKey.id + ')'
|
USER: validPublicKey.user + ' (' + validPublicKey.id + ')'
|
||||||
}),
|
}),
|
||||||
decryptedMessage.getText()
|
decryptedMessage.getText()
|
||||||
);
|
);
|
||||||
|
|
@ -105,7 +105,7 @@ function domControlSignedClickHelper(store, dom, armoredMessage) {
|
||||||
this,
|
this,
|
||||||
true,
|
true,
|
||||||
i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
|
i18n('PGP_NOTIFICATIONS/GOOD_SIGNATURE', {
|
||||||
'USER': validKey.user + ' (' + validKey.id + ')'
|
USER: validKey.user + ' (' + validKey.id + ')'
|
||||||
}),
|
}),
|
||||||
message.getText()
|
message.getText()
|
||||||
);
|
);
|
||||||
|
|
@ -361,7 +361,7 @@ export const PgpUserStore = new class {
|
||||||
verControl.addEventHandler('click', domControlSignedClickHelper(this, dom, domText));
|
verControl.addEventHandler('click', domControlSignedClickHelper(this, dom, domText));
|
||||||
}
|
}
|
||||||
|
|
||||||
dom.before(verControl, doc.createElement('div'));
|
dom.before(verControl, createElement('div'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,3 @@
|
||||||
@import "Animations.less";
|
@import "Animations.less";
|
||||||
|
|
||||||
@import "_End.less";
|
@import "_End.less";
|
||||||
/*
|
|
||||||
@import "_CkeFix.less";
|
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -1,213 +0,0 @@
|
||||||
/*.cke_button__sourcedialog_label {
|
|
||||||
display: none !important;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
.cke_chrome {
|
|
||||||
border: 1px solid #ccc !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_toolgroup {
|
|
||||||
padding-right: 0 !important;
|
|
||||||
background: #FBFBFB !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_toolgroup, .cke_combo_button {
|
|
||||||
border: 1px solid #A6A6A6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_top {
|
|
||||||
padding: 2px;
|
|
||||||
box-shadow: none !important;
|
|
||||||
border-bottom: 1px solid #b6b6b6 !important;
|
|
||||||
background: #F0F0F0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_combo_on a.cke_combo_button,
|
|
||||||
.cke_combo_off a.cke_combo_button:hover,
|
|
||||||
.cke_combo_off a.cke_combo_button:focus,
|
|
||||||
.cke_combo_off a.cke_combo_button:active {
|
|
||||||
padding: 1px !important;
|
|
||||||
margin-left: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_toolgroup a.cke_button:last-child:after,
|
|
||||||
.cke_toolgroup a.cke_button.cke_button_disabled:hover:last-child:after {
|
|
||||||
border: none !important;
|
|
||||||
height: 0 !important;
|
|
||||||
width: 0 !important;
|
|
||||||
margin: 0 !important;
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_button_on {
|
|
||||||
background: #ddd !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_combo {
|
|
||||||
margin-top: 1px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_combo__fontsize {
|
|
||||||
margin-left: 3px !important;
|
|
||||||
.cke_combo_text {
|
|
||||||
width: 40px !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_combo_text {
|
|
||||||
line-height: 24px !important;
|
|
||||||
padding-left: 8px !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_combo_button {
|
|
||||||
background: #FBFBFB !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_source {
|
|
||||||
font-family: var(--fontMono) !important;
|
|
||||||
padding: 10px !important;
|
|
||||||
padding-right: 0 !important;
|
|
||||||
box-shadow: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_plain {
|
|
||||||
|
|
||||||
background-color: #fff;
|
|
||||||
outline: none;
|
|
||||||
overflow: auto;
|
|
||||||
z-index: 1;
|
|
||||||
margin: 0;
|
|
||||||
border: 0;
|
|
||||||
|
|
||||||
padding: 10px;
|
|
||||||
padding-right: 0;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
font-family: var(--fontMono), monospace;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 16px;
|
|
||||||
color: #333;
|
|
||||||
resize: none;
|
|
||||||
|
|
||||||
border-radius: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_plain:focus, .cke_source:focus {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.b-compose .cke_chrome {
|
|
||||||
border-right: 0;
|
|
||||||
border-left: 0;
|
|
||||||
border-bottom: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_wysiwyg_div {
|
|
||||||
|
|
||||||
padding: 10px !important;
|
|
||||||
font-family: var(--fontSans);
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 16px;
|
|
||||||
color: #333;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding-left: 40px;
|
|
||||||
li {
|
|
||||||
list-style-type: disc !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ol {
|
|
||||||
padding-left: 40px;
|
|
||||||
li {
|
|
||||||
list-style-type: decimal !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pre, code {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
background: #fff;
|
|
||||||
border: none;
|
|
||||||
border-radius: 0;
|
|
||||||
font-family: var(--fontMono);
|
|
||||||
display: block;
|
|
||||||
word-break: normal;
|
|
||||||
word-wrap: break-word;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
display: inline;
|
|
||||||
padding: 2px 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
padding: 5px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
background-color: #f9f9f9;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre > code {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
border: 0;
|
|
||||||
border-left: solid 2px #444;
|
|
||||||
margin: 5px 0 5px 5px;
|
|
||||||
padding-left: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote p {
|
|
||||||
margin: 0 0 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
vertical-align: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: blue;
|
|
||||||
text-decoration: underline;
|
|
||||||
|
|
||||||
&:visited {
|
|
||||||
color: #609;
|
|
||||||
}
|
|
||||||
&:active {
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_dialog {
|
|
||||||
|
|
||||||
a:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_dialog_ui_labeled_content {
|
|
||||||
margin-top: 5px;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_dialog_ui_input_select, .cke_dialog_ui_input_text, .cke_dialog_ui_input_textarea {
|
|
||||||
|
|
||||||
box-shadow: none;
|
|
||||||
border-radius: 2px;
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 0;
|
|
||||||
border: 1px solid #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.cke_dialog_ui_input_select, .cke_dialog_ui_input_text {
|
|
||||||
height: 25px;
|
|
||||||
line-height: 25px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -226,7 +226,7 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
sendButtonSuccess: () => !this.sendError() && !this.sendSuccessButSaveError(),
|
sendButtonSuccess: () => !this.sendError() && !this.sendSuccessButSaveError(),
|
||||||
|
|
||||||
savedTimeText: () =>
|
savedTimeText: () =>
|
||||||
this.savedTime() ? i18n('COMPOSE/SAVED_TIME', { 'TIME': this.savedTime().format('LT') }) : '',
|
this.savedTime() ? i18n('COMPOSE/SAVED_TIME', { TIME: this.savedTime().format('LT') }) : '',
|
||||||
|
|
||||||
emptyToErrorTooltip: () => (this.emptyToError() ? i18n('COMPOSE/EMPTY_TO_ERROR_DESC') : ''),
|
emptyToErrorTooltip: () => (this.emptyToError() ? i18n('COMPOSE/EMPTY_TO_ERROR_DESC') : ''),
|
||||||
|
|
||||||
|
|
@ -254,9 +254,9 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
identitiesOptions: () =>
|
identitiesOptions: () =>
|
||||||
IdentityUserStore.map(item => ({
|
IdentityUserStore.map(item => ({
|
||||||
'item': item,
|
item: item,
|
||||||
'optValue': item.id(),
|
optValue: item.id(),
|
||||||
'optText': item.formattedName()
|
optText: item.formattedName()
|
||||||
})),
|
})),
|
||||||
|
|
||||||
currentIdentityView: () => {
|
currentIdentityView: () => {
|
||||||
|
|
@ -931,8 +931,8 @@ class ComposePopupView extends AbstractViewPopup {
|
||||||
case ComposeType.ReplyAll:
|
case ComposeType.ReplyAll:
|
||||||
sFrom = message.fromToLine(false, true);
|
sFrom = message.fromToLine(false, true);
|
||||||
sReplyTitle = i18n('COMPOSE/REPLY_MESSAGE_TITLE', {
|
sReplyTitle = i18n('COMPOSE/REPLY_MESSAGE_TITLE', {
|
||||||
'DATETIME': sDate,
|
DATETIME: sDate,
|
||||||
'EMAIL': sFrom
|
EMAIL: sFrom
|
||||||
});
|
});
|
||||||
|
|
||||||
sText = sText.replace(/<img[^>]+>/g, '').replace(/<a\s[^>]+><\/a>/g, '').trim();
|
sText = sText.replace(/<img[^>]+>/g, '').replace(/<a\s[^>]+><\/a>/g, '').trim();
|
||||||
|
|
|
||||||
|
|
@ -49,9 +49,9 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return oKey.users.map(user => ({
|
return oKey.users.map(user => ({
|
||||||
'id': oKey.guid,
|
id: oKey.guid,
|
||||||
'name': '(' + oKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() + ') ' + user,
|
name: '(' + oKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() + ') ' + user,
|
||||||
'key': oKey
|
key: oKey
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -64,9 +64,9 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return oKey.users.map(user => ({
|
return oKey.users.map(user => ({
|
||||||
'id': oKey.guid,
|
id: oKey.guid,
|
||||||
'name': '(' + oKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() + ') ' + user,
|
name: '(' + oKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() + ') ' + user,
|
||||||
'key': oKey
|
key: oKey
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
return opts.flat().filter(v => v);
|
return opts.flat().filter(v => v);
|
||||||
|
|
@ -114,7 +114,7 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
} else if (!this.signKey().key) {
|
} else if (!this.signKey().key) {
|
||||||
this.notification(
|
this.notification(
|
||||||
i18nPGP('NO_PRIVATE_KEY_FOUND_FOR', {
|
i18nPGP('NO_PRIVATE_KEY_FOUND_FOR', {
|
||||||
'EMAIL': this.signKey().email
|
EMAIL: this.signKey().email
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -150,7 +150,7 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
} else if (oKey && oKey.email) {
|
} else if (oKey && oKey.email) {
|
||||||
this.notification(
|
this.notification(
|
||||||
i18nPGP('NO_PUBLIC_KEYS_FOUND_FOR', {
|
i18nPGP('NO_PUBLIC_KEYS_FOUND_FOR', {
|
||||||
'EMAIL': oKey.email
|
EMAIL: oKey.email
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -196,7 +196,7 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
this.notification(
|
this.notification(
|
||||||
i18nPGP('PGP_ERROR', {
|
i18nPGP('PGP_ERROR', {
|
||||||
'ERROR': '' + e
|
ERROR: '' + e
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -211,13 +211,13 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
this.notification(
|
this.notification(
|
||||||
i18nPGP('PGP_ERROR', {
|
i18nPGP('PGP_ERROR', {
|
||||||
'ERROR': '' + e
|
ERROR: '' + e
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.notification(
|
this.notification(
|
||||||
i18nPGP('PGP_ERROR', {'ERROR': '' + e})
|
i18nPGP('PGP_ERROR', {ERROR: '' + e})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -237,11 +237,11 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
if (option) {
|
if (option) {
|
||||||
this.signKey({
|
this.signKey({
|
||||||
'empty': !option.key,
|
empty: !option.key,
|
||||||
'selected': ko.observable(!!option.key),
|
selected: ko.observable(!!option.key),
|
||||||
'users': option.key.users,
|
users: option.key.users,
|
||||||
'hash': option.key.id.substr(KEY_NAME_SUBSTR).toUpperCase(),
|
hash: option.key.id.substr(KEY_NAME_SUBSTR).toUpperCase(),
|
||||||
'key': option.key
|
key: option.key
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -252,12 +252,12 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
if (option) {
|
if (option) {
|
||||||
this.encryptKeys.push({
|
this.encryptKeys.push({
|
||||||
'empty': !option.key,
|
empty: !option.key,
|
||||||
'selected': ko.observable(!!option.key),
|
selected: ko.observable(!!option.key),
|
||||||
'removable': ko.observable(!this.sign() || !this.signKey() || this.signKey().key.id !== option.key.id),
|
removable: ko.observable(!this.sign() || !this.signKey() || this.signKey().key.id !== option.key.id),
|
||||||
'users': option.key.users,
|
users: option.key.users,
|
||||||
'hash': option.key.id.substr(KEY_NAME_SUBSTR).toUpperCase(),
|
hash: option.key.id.substr(KEY_NAME_SUBSTR).toUpperCase(),
|
||||||
'key': option.key
|
key: option.key
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -343,9 +343,9 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
const keys = PgpUserStore.findAllPrivateKeysByEmailNotNative(emailLine);
|
const keys = PgpUserStore.findAllPrivateKeysByEmailNotNative(emailLine);
|
||||||
if (keys && keys[0]) {
|
if (keys && keys[0]) {
|
||||||
this.signKey({
|
this.signKey({
|
||||||
'users': keys[0].users || [emailLine],
|
users: keys[0].users || [emailLine],
|
||||||
'hash': keys[0].id.substr(KEY_NAME_SUBSTR).toUpperCase(),
|
hash: keys[0].id.substr(KEY_NAME_SUBSTR).toUpperCase(),
|
||||||
'key': keys[0]
|
key: keys[0]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -360,14 +360,14 @@ class ComposeOpenPgpPopupView extends AbstractViewPopup {
|
||||||
const keys = PgpUserStore.findAllPublicKeysByEmailNotNative(recEmail);
|
const keys = PgpUserStore.findAllPublicKeysByEmailNotNative(recEmail);
|
||||||
return keys
|
return keys
|
||||||
? keys.map(publicKey => ({
|
? keys.map(publicKey => ({
|
||||||
'empty': !publicKey,
|
empty: !publicKey,
|
||||||
'selected': ko.observable(!!publicKey),
|
selected: ko.observable(!!publicKey),
|
||||||
'removable': ko.observable(
|
removable: ko.observable(
|
||||||
!this.sign() || !this.signKey() || this.signKey().key.id !== publicKey.id
|
!this.sign() || !this.signKey() || this.signKey().key.id !== publicKey.id
|
||||||
),
|
),
|
||||||
'users': publicKey ? publicKey.users || [recEmail] : [recEmail],
|
users: publicKey ? publicKey.users || [recEmail] : [recEmail],
|
||||||
'hash': publicKey ? publicKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() : '',
|
hash: publicKey ? publicKey.id.substr(KEY_NAME_SUBSTR).toUpperCase() : '',
|
||||||
'key': publicKey
|
key: publicKey
|
||||||
}))
|
}))
|
||||||
: [];
|
: [];
|
||||||
}).flat().validUnique(encryptKey => encryptKey.hash)
|
}).flat().validUnique(encryptKey => encryptKey.hash)
|
||||||
|
|
|
||||||
|
|
@ -63,13 +63,13 @@ class DomainPopupView extends AbstractViewPopup {
|
||||||
let result = '';
|
let result = '';
|
||||||
|
|
||||||
if (this.edit()) {
|
if (this.edit()) {
|
||||||
result = i18n('POPUPS_DOMAIN/TITLE_EDIT_DOMAIN', { 'NAME': name });
|
result = i18n('POPUPS_DOMAIN/TITLE_EDIT_DOMAIN', { NAME: name });
|
||||||
if (aliasName) {
|
if (aliasName) {
|
||||||
result += ' ← ' + aliasName;
|
result += ' ← ' + aliasName;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result = name
|
result = name
|
||||||
? i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME', { 'NAME': name })
|
? i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN_WITH_NAME', { NAME: name })
|
||||||
: i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN');
|
: i18n('POPUPS_DOMAIN/TITLE_ADD_DOMAIN');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -78,7 +78,7 @@ class DomainPopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
domainDesc: () => {
|
domainDesc: () => {
|
||||||
const name = this.name();
|
const name = this.name();
|
||||||
return !this.edit() && name ? i18n('POPUPS_DOMAIN/NEW_DOMAIN_DESC', { 'NAME': '*@' + name }) : '';
|
return !this.edit() && name ? i18n('POPUPS_DOMAIN/NEW_DOMAIN_DESC', { NAME: '*@' + name }) : '';
|
||||||
},
|
},
|
||||||
|
|
||||||
domainIsComputed: () => {
|
domainIsComputed: () => {
|
||||||
|
|
|
||||||
|
|
@ -66,22 +66,22 @@ class FilterPopupView extends AbstractViewPopup {
|
||||||
let i18nFilter = key => i18n('POPUPS_FILTER/SELECT_' + key);
|
let i18nFilter = key => i18n('POPUPS_FILTER/SELECT_' + key);
|
||||||
|
|
||||||
this.fieldOptions([
|
this.fieldOptions([
|
||||||
{ 'id': FilterConditionField.From, 'name': i18n('GLOBAL/FROM') },
|
{ id: FilterConditionField.From, name: i18n('GLOBAL/FROM') },
|
||||||
{ 'id': FilterConditionField.Recipient, 'name': i18nFilter('FIELD_RECIPIENTS') },
|
{ id: FilterConditionField.Recipient, name: i18nFilter('FIELD_RECIPIENTS') },
|
||||||
{ 'id': FilterConditionField.Subject, 'name': i18n('GLOBAL/SUBJECT') },
|
{ id: FilterConditionField.Subject, name: i18n('GLOBAL/SUBJECT') },
|
||||||
{ 'id': FilterConditionField.Size, 'name': i18nFilter('FIELD_SIZE') },
|
{ id: FilterConditionField.Size, name: i18nFilter('FIELD_SIZE') },
|
||||||
{ 'id': FilterConditionField.Header, 'name': i18nFilter('FIELD_HEADER') }
|
{ id: FilterConditionField.Header, name: i18nFilter('FIELD_HEADER') }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this.typeOptions([
|
this.typeOptions([
|
||||||
{ 'id': FilterConditionType.Contains, 'name': i18nFilter('TYPE_CONTAINS') },
|
{ id: FilterConditionType.Contains, name: i18nFilter('TYPE_CONTAINS') },
|
||||||
{ 'id': FilterConditionType.NotContains, 'name': i18nFilter('TYPE_NOT_CONTAINS') },
|
{ id: FilterConditionType.NotContains, name: i18nFilter('TYPE_NOT_CONTAINS') },
|
||||||
{ 'id': FilterConditionType.EqualTo, 'name': i18nFilter('TYPE_EQUAL_TO') },
|
{ id: FilterConditionType.EqualTo, name: i18nFilter('TYPE_EQUAL_TO') },
|
||||||
{ 'id': FilterConditionType.NotEqualTo, 'name': i18nFilter('TYPE_NOT_EQUAL_TO') }
|
{ id: FilterConditionType.NotEqualTo, name: i18nFilter('TYPE_NOT_EQUAL_TO') }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// this.actionTypeOptions.push({'id': FilterAction.None,
|
// this.actionTypeOptions.push({id: FilterAction.None,
|
||||||
// 'name': i18n('GLOBAL/NONE')});
|
// name: i18n('GLOBAL/NONE')});
|
||||||
const modules = SieveUserStore.capa;
|
const modules = SieveUserStore.capa;
|
||||||
if (modules) {
|
if (modules) {
|
||||||
if (modules.includes('imap4flags')) {
|
if (modules.includes('imap4flags')) {
|
||||||
|
|
@ -90,45 +90,45 @@ class FilterPopupView extends AbstractViewPopup {
|
||||||
|
|
||||||
if (modules.includes('fileinto')) {
|
if (modules.includes('fileinto')) {
|
||||||
this.actionTypeOptions.push({
|
this.actionTypeOptions.push({
|
||||||
'id': FilterAction.MoveTo,
|
id: FilterAction.MoveTo,
|
||||||
'name': i18nFilter('ACTION_MOVE_TO')
|
name: i18nFilter('ACTION_MOVE_TO')
|
||||||
});
|
});
|
||||||
this.actionTypeOptions.push({
|
this.actionTypeOptions.push({
|
||||||
'id': FilterAction.Forward,
|
id: FilterAction.Forward,
|
||||||
'name': i18nFilter('ACTION_FORWARD_TO')
|
name: i18nFilter('ACTION_FORWARD_TO')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modules.includes('reject')) {
|
if (modules.includes('reject')) {
|
||||||
this.actionTypeOptions.push({ 'id': FilterAction.Reject, 'name': i18nFilter('ACTION_REJECT') });
|
this.actionTypeOptions.push({ id: FilterAction.Reject, name: i18nFilter('ACTION_REJECT') });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modules.includes('vacation')) {
|
if (modules.includes('vacation')) {
|
||||||
this.actionTypeOptions.push({
|
this.actionTypeOptions.push({
|
||||||
'id': FilterAction.Vacation,
|
id: FilterAction.Vacation,
|
||||||
'name': i18nFilter('ACTION_VACATION_MESSAGE')
|
name: i18nFilter('ACTION_VACATION_MESSAGE')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modules.includes('body')) {
|
if (modules.includes('body')) {
|
||||||
this.fieldOptions.push({ 'id': FilterConditionField.Body, 'name': i18nFilter('FIELD_BODY') });
|
this.fieldOptions.push({ id: FilterConditionField.Body, name: i18nFilter('FIELD_BODY') });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modules.includes('regex')) {
|
if (modules.includes('regex')) {
|
||||||
this.typeOptions.push({ 'id': FilterConditionType.Regex, 'name': 'Regex' });
|
this.typeOptions.push({ id: FilterConditionType.Regex, name: 'Regex' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.actionTypeOptions.push({ 'id': FilterAction.Discard, 'name': i18nFilter('ACTION_DISCARD') });
|
this.actionTypeOptions.push({ id: FilterAction.Discard, name: i18nFilter('ACTION_DISCARD') });
|
||||||
|
|
||||||
this.typeOptionsSize([
|
this.typeOptionsSize([
|
||||||
{ 'id': FilterConditionType.Over, 'name': i18nFilter('TYPE_OVER') },
|
{ id: FilterConditionType.Over, name: i18nFilter('TYPE_OVER') },
|
||||||
{ 'id': FilterConditionType.Under, 'name': i18nFilter('TYPE_UNDER') }
|
{ id: FilterConditionType.Under, name: i18nFilter('TYPE_UNDER') }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
this.typeOptionsBody([
|
this.typeOptionsBody([
|
||||||
{ 'id': FilterConditionType.Text, 'name': i18nFilter('TYPE_TEXT') },
|
{ id: FilterConditionType.Text, name: i18nFilter('TYPE_TEXT') },
|
||||||
{ 'id': FilterConditionType.Raw, 'name': i18nFilter('TYPE_RAW') }
|
{ id: FilterConditionType.Raw, name: i18nFilter('TYPE_RAW') }
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ class FolderClearPopupView extends AbstractViewPopup {
|
||||||
return folder ? folder.localName() : '';
|
return folder ? folder.localName() : '';
|
||||||
},
|
},
|
||||||
|
|
||||||
dangerDescHtml: () => i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { 'FOLDER': this.folderNameForClear() })
|
dangerDescHtml: () => i18n('POPUPS_CLEAR_FOLDER/DANGER_DESC_HTML_1', { FOLDER: this.folderNameForClear() })
|
||||||
});
|
});
|
||||||
|
|
||||||
decorateKoCommands(this, {
|
decorateKoCommands(this, {
|
||||||
|
|
|
||||||
|
|
@ -74,13 +74,13 @@ class PluginPopupView extends AbstractViewPopup {
|
||||||
if (isNonEmptyArray(config)) {
|
if (isNonEmptyArray(config)) {
|
||||||
this.configures(
|
this.configures(
|
||||||
config.map(item => ({
|
config.map(item => ({
|
||||||
'value': ko.observable(item[0]),
|
value: ko.observable(item[0]),
|
||||||
'placeholder': ko.observable(item[6]),
|
placeholder: ko.observable(item[6]),
|
||||||
'Name': item[1],
|
Name: item[1],
|
||||||
'Type': item[2],
|
Type: item[2],
|
||||||
'Label': item[3],
|
Label: item[3],
|
||||||
'Default': item[4],
|
Default: item[4],
|
||||||
'Desc': item[5]
|
Desc: item[5]
|
||||||
}))
|
}))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -114,15 +114,15 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
||||||
});
|
});
|
||||||
|
|
||||||
// append drag and drop
|
// append drag and drop
|
||||||
this.dragOver = ko.observable(false).extend({ 'throttle': 1 });
|
this.dragOver = ko.observable(false).extend({ throttle: 1 });
|
||||||
this.dragOverEnter = ko.observable(false).extend({ 'throttle': 1 });
|
this.dragOverEnter = ko.observable(false).extend({ throttle: 1 });
|
||||||
|
|
||||||
this.sLastSearchValue = '';
|
this.sLastSearchValue = '';
|
||||||
|
|
||||||
this.addComputables({
|
this.addComputables({
|
||||||
messageListSearchDesc: () => {
|
messageListSearchDesc: () => {
|
||||||
const value = MessageUserStore.listEndSearch();
|
const value = MessageUserStore.listEndSearch();
|
||||||
return value ? i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', { 'SEARCH': value }) : ''
|
return value ? i18n('MESSAGE_LIST/SEARCH_RESULT_FOR', { SEARCH: value }) : ''
|
||||||
},
|
},
|
||||||
|
|
||||||
messageListPaginator: computedPaginatorHelper(MessageUserStore.listPage,
|
messageListPaginator: computedPaginatorHelper(MessageUserStore.listPage,
|
||||||
|
|
@ -871,9 +871,9 @@ export class MessageListMailBoxUserView extends AbstractViewRight {
|
||||||
|
|
||||||
quotaTooltip() {
|
quotaTooltip() {
|
||||||
return i18n('MESSAGE_LIST/QUOTA_SIZE', {
|
return i18n('MESSAGE_LIST/QUOTA_SIZE', {
|
||||||
'SIZE': FileInfo.friendlySize(this.userUsageSize()),
|
SIZE: FileInfo.friendlySize(this.userUsageSize()),
|
||||||
'PROC': this.userUsageProc(),
|
PROC: this.userUsageProc(),
|
||||||
'LIMIT': FileInfo.friendlySize(this.userQuota())
|
LIMIT: FileInfo.friendlySize(this.userQuota())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -732,7 +732,7 @@ class MessageViewMailBoxUserView extends AbstractViewRight {
|
||||||
oMessage.folder,
|
oMessage.folder,
|
||||||
oMessage.uid,
|
oMessage.uid,
|
||||||
oMessage.readReceipt(),
|
oMessage.readReceipt(),
|
||||||
i18n('READ_RECEIPT/SUBJECT', { 'SUBJECT': oMessage.subject() }),
|
i18n('READ_RECEIPT/SUBJECT', { SUBJECT: oMessage.subject() }),
|
||||||
i18n('READ_RECEIPT/BODY', { 'READ-RECEIPT': AccountUserStore.email() })
|
i18n('READ_RECEIPT/BODY', { 'READ-RECEIPT': AccountUserStore.email() })
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -153,12 +153,6 @@ win.rl = {
|
||||||
.then(() => Promise.all([loadScript(appData.TemplatesLink), loadScript(appData.LangLink)]))
|
.then(() => Promise.all([loadScript(appData.TemplatesLink), loadScript(appData.LangLink)]))
|
||||||
.then(() => loadScript(appData.StaticAppJsLink))
|
.then(() => loadScript(appData.StaticAppJsLink))
|
||||||
.then(() => appData.PluginsLink ? loadScript(appData.PluginsLink) : Promise.resolve())
|
.then(() => appData.PluginsLink ? loadScript(appData.PluginsLink) : Promise.resolve())
|
||||||
.then(() =>
|
|
||||||
// Enable the old CKEditor?
|
|
||||||
(appData.Auth && appData.StaticEditorJsLink)
|
|
||||||
? loadScript(appData.StaticEditorJsLink)
|
|
||||||
: Promise.resolve()
|
|
||||||
)
|
|
||||||
.then(() => win.__APP_BOOT ? win.__APP_BOOT(showError) : showError())
|
.then(() => win.__APP_BOOT ? win.__APP_BOOT(showError) : showError())
|
||||||
.catch(e => {
|
.catch(e => {
|
||||||
showError();
|
showError();
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ if (!defined('APP_VERSION'))
|
||||||
{
|
{
|
||||||
define('APP_VERSION', '0.0.0');
|
define('APP_VERSION', '0.0.0');
|
||||||
define('APP_INDEX_ROOT_FILE', __FILE__);
|
define('APP_INDEX_ROOT_FILE', __FILE__);
|
||||||
define('APP_INDEX_ROOT_PATH', str_replace('\\', '/', rtrim(dirname(__FILE__), '\\/').'/'));
|
define('APP_INDEX_ROOT_PATH', strtr(__DIR__, DIRECTORY_SEPARATOR, '/') . '/');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (file_exists(APP_INDEX_ROOT_PATH.'snappymail/v/'.APP_VERSION.'/include.php'))
|
if (file_exists(APP_INDEX_ROOT_PATH.'snappymail/v/'.APP_VERSION.'/include.php'))
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"title": "SnappyMail",
|
"title": "SnappyMail",
|
||||||
"description": "Simple, modern & fast web-based email client",
|
"description": "Simple, modern & fast web-based email client",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.4.1",
|
"version": "2.4.2",
|
||||||
"homepage": "https://snappymail.eu",
|
"homepage": "https://snappymail.eu",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "DJ Maze",
|
"name": "DJ Maze",
|
||||||
|
|
|
||||||
93
plugins/ckeditor/ckeditor.js
vendored
Normal file
93
plugins/ckeditor/ckeditor.js
vendored
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
(rl => {
|
||||||
|
if (rl) {
|
||||||
|
const path = (rl.settings.app('webVersionPath') || 'snappymail/v/' + rl.settings.app('version') + '/'),
|
||||||
|
script = document.createElement('script');
|
||||||
|
script.src = path + 'static/ckeditor/ckeditor.js';
|
||||||
|
document.head.append(script);
|
||||||
|
|
||||||
|
rl.createWYSIWYG = (container, onReady) => {
|
||||||
|
if (!window.CKEDITOR) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const
|
||||||
|
language = (rl.settings.get('Language') || 'en').toLowerCase(),
|
||||||
|
htmlEditorLangsMap = {
|
||||||
|
'ar_sa': 'ar-sa',
|
||||||
|
'pt_br': 'pt-br',
|
||||||
|
'zh_cn': 'zh-cn',
|
||||||
|
},
|
||||||
|
editor = CKEDITOR.appendTo(container, {
|
||||||
|
title: false,
|
||||||
|
stylesSet: false,
|
||||||
|
// customConfig: '',
|
||||||
|
// contentsCss: '',
|
||||||
|
toolbarGroups: [
|
||||||
|
{ name: 'spec' },
|
||||||
|
{ name: 'styles' },
|
||||||
|
{ name: 'basicstyles', groups: ['basicstyles', 'cleanup', 'bidi'] },
|
||||||
|
{ name: 'colors' },
|
||||||
|
{ name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align'] },
|
||||||
|
{ name: 'links' },
|
||||||
|
{ name: 'insert' },
|
||||||
|
{ name: 'document', groups: ['mode', 'document', 'doctools'] },
|
||||||
|
{ name: 'others' }
|
||||||
|
],
|
||||||
|
|
||||||
|
removePlugins: 'liststyle' + (rl.settings.app('allowHtmlEditorBitiButtons') ? '' : ',bidi'),
|
||||||
|
removeButtons: 'Format,Undo,Redo,Cut,Copy,Paste,Anchor,Strike,Subscript,Superscript,Image,SelectAll'
|
||||||
|
+ (rl.settings.app('allowHtmlEditorSourceButton') ? '' : ',Source'),
|
||||||
|
removeDialogTabs: 'link:advanced;link:target;image:advanced;images:advanced',
|
||||||
|
|
||||||
|
extraPlugins: 'plain,signature',
|
||||||
|
|
||||||
|
allowedContent: true,
|
||||||
|
extraAllowedContent: true,
|
||||||
|
|
||||||
|
fillEmptyBlocks: false,
|
||||||
|
// ignoreEmptyParagraph: true,
|
||||||
|
disableNativeSpellChecker: false,
|
||||||
|
|
||||||
|
colorButton_enableAutomatic: false,
|
||||||
|
// colorButton_enableMore: true,
|
||||||
|
|
||||||
|
font_defaultLabel: 'Arial',
|
||||||
|
fontSize_defaultLabel: '13',
|
||||||
|
fontSize_sizes: '10/10px;12/12px;13/13px;14/14px;16/16px;18/18px;20/20px;24/24px;28/28px;36/36px;48/48px',
|
||||||
|
|
||||||
|
enterMode: CKEDITOR.ENTER_BR,
|
||||||
|
shiftEnterMode: CKEDITOR.ENTER_P,
|
||||||
|
language: htmlEditorLangsMap[language] || language.substr(0,2)
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.on('key', event => !(event && event.data && 'Tab' == event.data.key));
|
||||||
|
|
||||||
|
editor.on('drop', event => {
|
||||||
|
const dt = event.data.dataTransfer,
|
||||||
|
id = dt.id,
|
||||||
|
file = dt.getFilesCount() ? dt.getFile(0) : 0;
|
||||||
|
if (file && id && file.type && file.type.match(/^image/i)) {
|
||||||
|
const imageId = `[img=${id}]`,
|
||||||
|
reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onloadend = () => {
|
||||||
|
if (reader.result && 'wysiwyg' === editor.mode) {
|
||||||
|
try {
|
||||||
|
editor.setData(editor.getData().replace(imageId, `<img src="${reader.result}"/>`));
|
||||||
|
} catch (e) {} // eslint-disable-line no-empty
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
|
||||||
|
dt.setData('text/html', imageId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
editor.on('instanceReady', onReady);
|
||||||
|
|
||||||
|
return editor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
})(window.rl);
|
||||||
38
plugins/ckeditor/index.php
Normal file
38
plugins/ckeditor/index.php
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class CKEditorPlugin extends \RainLoop\Plugins\AbstractPlugin
|
||||||
|
{
|
||||||
|
const
|
||||||
|
NAME = 'CKEditor',
|
||||||
|
VERSION = '2.0',
|
||||||
|
RELEASE = '2021-03-25',
|
||||||
|
REQUIRED = '2.4.2',
|
||||||
|
DESCRIPTION = 'Use CKEditor instead of Squire as WYSIWYG';
|
||||||
|
|
||||||
|
public function Init() : void
|
||||||
|
{
|
||||||
|
$path = APP_VERSION_ROOT_PATH . 'static/ckeditor';
|
||||||
|
|
||||||
|
// Apache AH00037: Symbolic link not allowed or link target not accessible
|
||||||
|
// That's why we clone the source
|
||||||
|
if (!\is_dir($path)/* && !\is_link($path)*/) {
|
||||||
|
// $active = \symlink(__DIR__ . '/src', $path);
|
||||||
|
\mkdir($path, 0755);
|
||||||
|
$iterator = new \RecursiveIteratorIterator(
|
||||||
|
new \RecursiveDirectoryIterator(__DIR__ . '/src', \RecursiveDirectoryIterator::SKIP_DOTS),
|
||||||
|
\RecursiveIteratorIterator::SELF_FIRST
|
||||||
|
);
|
||||||
|
foreach ($iterator as $item) {
|
||||||
|
if ($item->isDir()) {
|
||||||
|
\mkdir($path . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
|
||||||
|
} else {
|
||||||
|
\copy($item, $path . DIRECTORY_SEPARATOR . $iterator->getSubPathName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (\is_file("{$path}/ckeditor.js")) {
|
||||||
|
$this->addJs('ckeditor.js');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/**
|
/**
|
||||||
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||||
*/
|
*/
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||||
For licensing, see LICENSE.md or http://ckeditor.com/license
|
For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||||
*/
|
*/
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/**
|
/**
|
||||||
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
|
||||||
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
* For licensing, see LICENSE.md or http://ckeditor.com/license
|
||||||
*/
|
*/
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue