diff --git a/jsdeps.json b/jsdeps.json
index ba486deba..c1d3179f4 100644
--- a/jsdeps.json
+++ b/jsdeps.json
@@ -36,28 +36,26 @@
},
{
"lib": "tinymce",
- "version": "4.8.2",
+ "version": "5.4.1",
"url": "https://download.tiny.cloud/tinymce/community/tinymce_$v.zip",
"dest": "program/js",
- "sha1": "d7fced05acdeeb78299585ea9909b0de2b3d759d",
+ "sha1": "1266dcbbc6d13fa789b3443a63acff4b75f5a911",
"license": "LGPL",
- "copyright": "Copyright (c) 1999-2015 Ephox Corp. All rights reserved",
+ "copyright": "Copyright (c) Tiny Technologies, Inc. All rights reserved",
"rm": "program/js/tinymce",
"map": {
"js/tinymce": "tinymce"
},
"omit": [
"tinymce/license.txt",
- "tinymce/jquery.tinymce.min.js"
- ],
- "addlicense": [
- "tinymce/tinymce.min.js"
+ "tinymce/jquery.tinymce.min.js",
+ "tinymce/themes/mobile"
]
},
{
"lib": "tinymce-langs",
- "version": "4.8.2",
- "url": "https://www.tiny.cloud/docs-4x/language/tinymce4x_languages.zip",
+ "version": "5.4.1",
+ "url": "https://www.tiny.cloud/tinymce-services-azure/1/i18n/download?langs=ar,hy,az,eu,be,bs,bg_BG,ca,zh_CN,zh_TW,hr,cs,cs_CZ,da,nl,en_CA,en_GB,eo,et,fo,fi,fr_FR,fr_CH,gd,gl,ka_GE,de,de_AT,el,he_IL,hi_IN,hu_HU,is_IS,id,ga,it,ja,kab,km_KH,ko_KR,ku,ku_IQ,lv,lt,lb,mk_MK,ml_IN,nb_NO,oc,fa,fa_IR,pl,pt_BR,pt_PT,ro,ru,sk,sl_SI,es,es_MX,sv_SE,tg,ta,ta_IN,tt,th_TH,tr,tr_TR,ug,uk,uk_UA,vi,vi_VN,cy&v=$v&extension=.zip",
"dest": "program/js/tinymce"
},
{
diff --git a/plugins/emoticons/composer.json b/plugins/emoticons/composer.json
index 30dd3928e..fa0f41ea5 100644
--- a/plugins/emoticons/composer.json
+++ b/plugins/emoticons/composer.json
@@ -3,7 +3,7 @@
"type": "roundcube-plugin",
"description": "Plugin that adds emoticons support.",
"license": "GPLv3+",
- "version": "2.0",
+ "version": "3.0",
"authors": [
{
"name": "Thomas Bruederli",
diff --git a/plugins/emoticons/emoticons.php b/plugins/emoticons/emoticons.php
index 4eefed873..bc76017eb 100644
--- a/plugins/emoticons/emoticons.php
+++ b/plugins/emoticons/emoticons.php
@@ -1,15 +1,15 @@
add_hook('message_part_after', array($this, 'message_part_after'));
- $this->add_hook('message_outgoing_body', array($this, 'message_outgoing_body'));
- $this->add_hook('html2text', array($this, 'html2text'));
$this->add_hook('html_editor', array($this, 'html_editor'));
if ($rcube->task == 'settings') {
@@ -35,8 +33,8 @@ class emoticons extends rcube_plugin
}
/**
- * 'message_part_after' hook handler to replace common plain text emoticons
- * with emoticon images (
)
+ * 'message_part_after' hook handler to replace common
+ * plain text emoticons with emoji
*/
function message_part_after($args)
{
@@ -48,65 +46,7 @@ class emoticons extends rcube_plugin
return $args;
}
- require_once __DIR__ . '/emoticons_engine.php';
-
- $args['body'] = emoticons_engine::text2icons($args['body']);
- }
-
- return $args;
- }
-
- /**
- * 'message_outgoing_body' hook handler to replace image emoticons from TinyMCE
- * editor with image attachments.
- */
- function message_outgoing_body($args)
- {
- if ($args['type'] == 'html') {
- $this->load_config();
-
- $rcube = rcube::get_instance();
- if (!$rcube->config->get('emoticons_compose', true)) {
- return $args;
- }
-
- require_once __DIR__ . '/emoticons_engine.php';
-
- // look for "emoticon" images from TinyMCE and change their src paths to
- // be file paths on the server instead of URL paths.
- $images = emoticons_engine::replace($args['body']);
-
- // add these images as attachments to the MIME message
- foreach ($images as $img_name => $img_file) {
- $args['message']->addHTMLImage($img_file, 'image/gif', '', true, $img_name);
- }
- }
-
- return $args;
- }
-
- /**
- * 'html2text' hook handler to replace image emoticons from TinyMCE
- * editor with plain text emoticons.
- *
- * This is executed on html2text action, i.e. when switching from HTML to text
- * in compose window (or similar place). Also when generating alternative
- * text/plain part.
- */
- function html2text($args)
- {
- $rcube = rcube::get_instance();
-
- if ($rcube->action == 'html2text' || $rcube->action == 'send') {
- $this->load_config();
-
- if (!$rcube->config->get('emoticons_compose', true)) {
- return $args;
- }
-
- require_once __DIR__ . '/emoticons_engine.php';
-
- $args['body'] = emoticons_engine::icons2text($args['body']);
+ $args['body'] = self::text2icons($args['body']);
}
return $args;
@@ -170,16 +110,58 @@ class emoticons extends rcube_plugin
*/
function preferences_save($args)
{
- $rcube = rcube::get_instance();
- $dont_override = $rcube->config->get('dont_override', array());
-
- if ($args['section'] == 'mailview' && !in_array('emoticons_display', $dont_override)) {
- $args['prefs']['emoticons_display'] = rcube_utils::get_input_value('_emoticons_display', rcube_utils::INPUT_POST) ? true : false;
+ if ($args['section'] == 'mailview') {
+ $args['prefs']['emoticons_display'] = !empty(rcube_utils::get_input_value('_emoticons_display', rcube_utils::INPUT_POST));
}
- else if ($args['section'] == 'compose' && !in_array('emoticons_compose', $dont_override)) {
- $args['prefs']['emoticons_compose'] = rcube_utils::get_input_value('_emoticons_compose', rcube_utils::INPUT_POST) ? true : false;
+ else if ($args['section'] == 'compose') {
+ $args['prefs']['emoticons_compose'] = !empty(rcube_utils::get_input_value('_emoticons_compose', rcube_utils::INPUT_POST));
}
return $args;
}
+
+ /**
+ * Replace common plain text emoticons with emoji
+ *
+ * @param string $text Text
+ *
+ * @return string Converted text
+ */
+ protected static function text2icons($text)
+ {
+ // This is a lookbehind assertion which will exclude html entities
+ // E.g. situation when ";)" in "")" shouldn't be replaced by the icon
+ // It's so long because of assertion format restrictions
+ $entity = '(? self::ico_tag('1f603', ':D' ), // laugh
+ '/:-?\(/' => self::ico_tag('1f626', ':(' ), // frown
+ '/'.$entity.';-?\)/' => self::ico_tag('1f609', ';)' ), // wink
+ '/8-?\)/' => self::ico_tag('1f60e', '8)' ), // cool
+ '/(? self::ico_tag('1f62e', ':O' ), // surprised
+ '/(? self::ico_tag('1f61b', ':P' ), // tongue out
+ '/(? self::ico_tag('1f631', ':-@' ), // yell
+ '/O:-?\)/i' => self::ico_tag('1f607', 'O:-)' ), // innocent
+ '/(? self::ico_tag('1f60a', ':-)' ), // smile
+ '/(? self::ico_tag('1f633', ':-$' ), // embarrassed
+ '/(? self::ico_tag('1f48b', ':-*' ), // kiss
+ '/(? self::ico_tag('1f615', ':-S' ), // undecided
+ );
+
+ return preg_replace(array_keys($map), array_values($map), $text);
+ }
+
+ protected static function ico_tag($ico, $title)
+ {
+ return html::span(array('title' => $title), "{$ico};");
+ }
}
diff --git a/plugins/emoticons/emoticons_engine.php b/plugins/emoticons/emoticons_engine.php
deleted file mode 100644
index 4d534cdc1..000000000
--- a/plugins/emoticons/emoticons_engine.php
+++ /dev/null
@@ -1,152 +0,0 @@
- 'smiley-cool',
- ':-#' => 'smiley-foot-in-mouth',
- ':-*' => 'smiley-kiss',
- ':-X' => 'smiley-sealed',
- ':-P' => 'smiley-tongue-out',
- ':-@' => 'smiley-yell',
- ":'(" => 'smiley-cry',
- ':-(' => 'smiley-frown',
- ':-D' => 'smiley-laughing',
- ':-)' => 'smiley-smile',
- ':-S' => 'smiley-undecided',
- ':-$' => 'smiley-embarassed',
- 'O:-)' => 'smiley-innocent',
- ':-|' => 'smiley-money-mouth',
- ':-O' => 'smiley-surprised',
- ';-)' => 'smiley-wink',
- );
-
- foreach ($emoticons as $idx => $file) {
- //
- $file = preg_quote(self::IMG_PATH . $file . '.gif', '/');
- $search[] = '/
]+\/>/i';
- $replace[] = $idx;
- }
-
- return preg_replace($search, $replace, $html);
- }
-
- /**
- * Replace common plain text emoticons with empticon
tags
- *
- * @param string $text Text
- *
- * @return string Converted text
- */
- public static function text2icons($text)
- {
- // This is a lookbehind assertion which will exclude html entities
- // E.g. situation when ";)" in "")" shouldn't be replaced by the icon
- // It's so long because of assertion format restrictions
- $entity = '(? self::img_tag('smiley-laughing.gif', ':D' ),
- '/:-D/' => self::img_tag('smiley-laughing.gif', ':-D' ),
- '/:\(/' => self::img_tag('smiley-frown.gif', ':(' ),
- '/:-\(/' => self::img_tag('smiley-frown.gif', ':-(' ),
- '/'.$entity.';\)/' => self::img_tag('smiley-wink.gif', ';)' ),
- '/'.$entity.';-\)/' => self::img_tag('smiley-wink.gif', ';-)' ),
- '/8\)/' => self::img_tag('smiley-cool.gif', '8)' ),
- '/8-\)/' => self::img_tag('smiley-cool.gif', '8-)' ),
- '/(? self::img_tag('smiley-surprised.gif', ':O' ),
- '/(? self::img_tag('smiley-surprised.gif', ':-O' ),
- '/(? self::img_tag('smiley-tongue-out.gif', ':P' ),
- '/(? self::img_tag('smiley-tongue-out.gif', ':-P' ),
- '/(? self::img_tag('smiley-yell.gif', ':@' ),
- '/(? self::img_tag('smiley-yell.gif', ':-@' ),
- '/O:\)/i' => self::img_tag('smiley-innocent.gif', 'O:)' ),
- '/O:-\)/i' => self::img_tag('smiley-innocent.gif', 'O:-)' ),
- '/(? self::img_tag('smiley-smile.gif', ':)' ),
- '/(? self::img_tag('smiley-smile.gif', ':-)' ),
- '/(? self::img_tag('smiley-embarassed.gif', ':$' ),
- '/(? self::img_tag('smiley-embarassed.gif', ':-$' ),
- '/(? self::img_tag('smiley-kiss.gif', ':*' ),
- '/(? self::img_tag('smiley-kiss.gif', ':-*' ),
- '/(? self::img_tag('smiley-undecided.gif', ':S' ),
- '/(? self::img_tag('smiley-undecided.gif', ':-S' ),
- );
-
- return preg_replace(array_keys($map), array_values($map), $text);
- }
-
- protected static function img_tag($ico, $title)
- {
- return html::img(array('src' => './' . self::IMG_PATH . $ico, 'title' => $title));
- }
-
- /**
- * Replace emoticon icons
'src' attribute, so it can
- * be replaced with real file by Mail_Mime.
- *
- * @param string &$html HTML content
- *
- * @return array List of image files
- */
- public static function replace(&$html)
- {
- // Replace this:
- //
- // with this:
- //
-
- $rcube = rcube::get_instance();
- $assets_dir = $rcube->config->get('assets_dir');
- $path = unslashify($assets_dir ?: INSTALL_PATH) . '/' . self::IMG_PATH;
- $offset = 0;
- $images = array();
-
- // remove any null-byte characters before parsing
- $html = preg_replace('/\x00/', '', $html);
-
- if (preg_match_all('# src=[\'"]([^\'"]+)#', $html, $matches, PREG_OFFSET_CAPTURE)) {
- foreach ($matches[1] as $m) {
- // find emoticon image tags
- if (preg_match('#'. self::IMG_PATH . '(.*)$#', $m[0], $imatches)) {
- $image_name = $imatches[1];
-
- // sanitize image name so resulting attachment doesn't leave images dir
- $image_name = preg_replace('/[^a-zA-Z0-9_\.\-]/i', '', $image_name);
- $image_file = $path . $image_name;
-
- // Add the same image only once
- $images[$image_name] = $image_file;
-
- $html = substr_replace($html, $image_file, $m[1] + $offset, strlen($m[0]));
- $offset += strlen($image_file) - strlen($m[0]);
- }
- }
- }
-
- return $images;
- }
-}
diff --git a/plugins/emoticons/localization/en_US.inc b/plugins/emoticons/localization/en_US.inc
index c1ab1dab8..c1f65d566 100644
--- a/plugins/emoticons/localization/en_US.inc
+++ b/plugins/emoticons/localization/en_US.inc
@@ -17,5 +17,3 @@
$labels = array();
$labels['emoticonsdisplay'] = 'Display emoticons in plain text messages';
$labels['emoticonscompose'] = 'Enable emoticons';
-
-?>
diff --git a/plugins/emoticons/tests/EmoticonsEngine.php b/plugins/emoticons/tests/EmoticonsEngine.php
deleted file mode 100644
index 58ad0668c..000000000
--- a/plugins/emoticons/tests/EmoticonsEngine.php
+++ /dev/null
@@ -1,48 +0,0 @@
- array('smiley-laughing.gif', ':D' ),
- ':-D' => array('smiley-laughing.gif', ':-D' ),
- ':(' => array('smiley-frown.gif', ':(' ),
- ':-(' => array('smiley-frown.gif', ':-(' ),
- '8)' => array('smiley-cool.gif', '8)' ),
- '8-)' => array('smiley-cool.gif', '8-)' ),
- ':O' => array('smiley-surprised.gif', ':O' ),
- ':-O' => array('smiley-surprised.gif', ':-O' ),
- ':P' => array('smiley-tongue-out.gif', ':P' ),
- ':-P' => array('smiley-tongue-out.gif', ':-P' ),
- ':@' => array('smiley-yell.gif', ':@' ),
- ':-@' => array('smiley-yell.gif', ':-@' ),
- 'O:)' => array('smiley-innocent.gif', 'O:)' ),
- 'O:-)' => array('smiley-innocent.gif', 'O:-)' ),
- ':)' => array('smiley-smile.gif', ':)' ),
- ':-)' => array('smiley-smile.gif', ':-)' ),
- ':$' => array('smiley-embarassed.gif', ':$' ),
- ':-$' => array('smiley-embarassed.gif', ':-$' ),
- ':*' => array('smiley-kiss.gif', ':*' ),
- ':-*' => array('smiley-kiss.gif', ':-*' ),
- ':S' => array('smiley-undecided.gif', ':S' ),
- ':-S' => array('smiley-undecided.gif', ':-S' ),
- );
-
- foreach ($map as $body => $expected) {
- $result = emoticons_engine::text2icons($body);
-
- $this->assertRegExp('/' . preg_quote($expected[0], '/') . '/', $result);
- $this->assertRegExp('/title="' . preg_quote($expected[1], '/') . '"/', $result);
- }
- }
-}
diff --git a/program/include/rcmail.php b/program/include/rcmail.php
index 2d5ee594e..09fcd3aef 100644
--- a/program/include/rcmail.php
+++ b/program/include/rcmail.php
@@ -2174,8 +2174,22 @@ class rcmail extends rcube
}
}
- $this->output->add_label('selectimage', 'addimage', 'selectmedia', 'addmedia', 'close');
+ $font_family = $this->output->get_env('default_font');
+ $font_size = $this->output->get_env('default_font_size');
+ $style = array();
+
+ if ($font_family) {
+ $style[] = "font-family: $font_family;";
+ }
+ if ($font_size) {
+ $style[] = "font-size: $font_size;";
+ }
+ if (!empty($style)) {
+ $config['content_style'] = "body {" . implode(' ', $style) . "}";
+ }
+
$this->output->set_env('editor_config', $config);
+ $this->output->add_label('selectimage', 'addimage', 'selectmedia', 'addmedia', 'close');
if ($path = $this->config->get('media_browser_css_location', 'program/resources/tinymce/browser.css')) {
if ($path != 'none' && ($path = $this->find_asset($path))) {
diff --git a/program/js/editor.js b/program/js/editor.js
index bc504c474..891ad7ddb 100644
--- a/program/js/editor.js
+++ b/program/js/editor.js
@@ -39,13 +39,17 @@ function rcube_text_editor(config, id)
abs_url = location.href.replace(/[?#].*$/, '').replace(/\/$/, ''),
conf = {
selector: '#' + ($('#' + id).is('.mce_editor') ? id : 'fake-editor-id'),
- cache_suffix: 's=4080200',
- theme: 'modern',
+ cache_suffix: 's=5040100',
+ theme: 'silver',
language: config.lang,
content_css: rcmail.assets_path(config.content_css),
+ content_style: config.content_style,
menubar: false,
statusbar: false,
- toolbar_items_size: 'small',
+ // toolbar_sticky: true, // does not work in scrollable element: https://github.com/tinymce/tinymce/issues/5227
+ toolbar_drawer: 'sliding',
+ toolbar: 'bold italic underline | alignleft aligncenter alignright alignjustify'
+ + ' | fontselect fontsizeselect | forecolor backcolor',
extended_valid_elements: 'font[face|size|color|style],span[id|class|align|style]',
fontsize_formats: '8pt 9pt 10pt 11pt 12pt 14pt 18pt 24pt 36pt',
// Allow style tag, have to be allowed inside body/div/blockquote (#7088)
@@ -55,10 +59,18 @@ function rcube_text_editor(config, id)
convert_urls: false, // #1486944
image_description: false,
paste_webkit_style: "color font-size font-family",
+ automatic_uploads: false, // allows to paste images
paste_data_images: true,
+ // Note: We disable contextmenu options specifically for browser_spellcheck:true.
+ // Otherwise user would have to use Right-Click with CTRL to get to
+ // the browser's spellchecker options. Should you disable browser_spellcheck
+ // you can enable other contextmenu options (by removing these options below).
browser_spellcheck: true,
+ contextmenu: 'spellchecker',
anchor_bottom: false,
- anchor_top: false
+ anchor_top: false,
+ file_picker_types: 'image media',
+ file_picker_callback: function(callback, value, meta) { ref.file_picker_callback(callback, value, meta); }
};
// register spellchecker for plain text editor
@@ -84,29 +96,22 @@ function rcube_text_editor(config, id)
// minimal editor
if (config.mode == 'identity') {
+ conf.toolbar += ' | charmap hr link unlink image code $extra';
$.extend(conf, {
- plugins: 'autolink charmap code colorpicker hr image link paste tabfocus textcolor',
- toolbar: 'bold italic underline alignleft aligncenter alignright alignjustify'
- + ' | outdent indent charmap hr link unlink image code forecolor'
- + ' | fontselect fontsizeselect',
- file_browser_callback: function(name, url, type, win) { ref.file_browser_callback(name, url, type); },
- file_browser_callback_types: 'image'
+ plugins: 'autolink charmap code hr image link paste tabfocus',
+ file_picker_types: 'image'
});
}
// full-featured editor
else {
- $.extend(conf, {
- plugins: 'autolink charmap code colorpicker directionality link lists image media nonbreaking'
- + ' paste table tabfocus textcolor searchreplace spellchecker',
- toolbar: 'bold italic underline | alignleft aligncenter alignright alignjustify'
- + ' | bullist numlist outdent indent ltr rtl blockquote | forecolor backcolor | fontselect fontsizeselect'
+ conf.toolbar += ' | bullist numlist outdent indent ltr rtl blockquote'
+ ' | link unlink table | $extra charmap image media | code searchreplace undo redo',
+ $.extend(conf, {
+ plugins: 'autolink charmap code directionality link lists image media nonbreaking'
+ + ' paste table tabfocus searchreplace spellchecker',
spellchecker_rpc_url: abs_url + '/?_task=utils&_action=spell_html&_remote=1',
spellchecker_language: rcmail.env.spell_lang,
- accessibility_focus: false,
- file_browser_callback: function(name, url, type, win) { ref.file_browser_callback(name, url, type); },
- // @todo: support more than image (types: file, image, media)
- file_browser_callback_types: 'image media'
+ min_height: 400,
});
}
@@ -176,7 +181,7 @@ function rcube_text_editor(config, id)
if (rcmail.env.action == 'compose') {
var area = $('#' + this.id),
- height = $('div.mce-toolbar-grp', area.parent()).first().height();
+ height = $('div.tox-toolbar__group', area.parent()).first().height();
// the editor might be still not fully loaded, making the editing area
// inaccessible, wait and try again (#1490310)
@@ -184,19 +189,9 @@ function rcube_text_editor(config, id)
return setTimeout(function () { ref.init_callback(editor); }, 300);
}
- var css = {},
- elem = rcube_find_object('_from'),
+ var elem = rcube_find_object('_from'),
fe = rcmail.env.compose_focus_elem;
- if (rcmail.env.default_font)
- css['font-family'] = rcmail.env.default_font;
-
- if (rcmail.env.default_font_size)
- css['font-size'] = rcmail.env.default_font_size;
-
- if (css['font-family'] || css['font-size'])
- $(this.editor.getBody()).css(css);
-
if (elem && elem.type == 'select-one') {
// insert signature (only for the first time)
if (!rcmail.env.identities_initialized)
@@ -654,21 +649,27 @@ function rcube_text_editor(config, id)
};
// image selector
- this.file_browser_callback = function(field_name, url, type)
+ this.file_picker_callback = function(callback, value, meta)
{
var i, button, elem, cancel, dialog, fn, hint, list = [],
+ type = meta.filetype,
form = $('.upload-form').clone();
// open image selector dialog
this.editor.windowManager.open({
title: rcmail.get_label('select' + type),
- width: 500,
- html: '
',
- buttons: [{text: rcmail.get_label('close'), onclick: function() { ref.file_browser_close(); }}]
+ body: {
+ type: 'panel',
+ items: [{
+ type: 'htmlpanel',
+ html: '',
+ }]
+ },
+ buttons: [{type: 'cancel', text: rcmail.get_label('close'), onclick: function() { ref.file_picker_close(); }}]
});
- rcmail.env.file_browser_field = field_name;
- rcmail.env.file_browser_type = type;
+ rcmail.env.file_picker_callback = callback;
+ rcmail.env.file_picker_type = type;
dialog = $('#image-selector');
@@ -681,14 +682,17 @@ function rcube_text_editor(config, id)
.text(rcmail.get_label('add' + type))
.focus();
+ if (!button.is('.btn'))
+ button.addClass('tox-button');
+
// fill images list with available images
for (i in rcmail.env.attachments) {
- if (elem = ref.file_browser_entry(i, rcmail.env.attachments[i])) {
+ if (elem = ref.file_picker_entry(i, rcmail.env.attachments[i])) {
list.push(elem);
}
}
- cancel = dialog.parent().parent().find('button').last().parent();
+ cancel = dialog.parents('.tox-dialog').find('button').last();
// Add custom Tab key handlers, tabindex does not work
list = $('#image-selector-list').append(list).on('keydown', 'li', function(e) {
@@ -754,7 +758,7 @@ function rcube_text_editor(config, id)
rcmail.env['file_dialog_event+' + type] = true;
rcmail.addEventListener('fileuploaded', function(attr) {
var elem;
- if (elem = ref.file_browser_entry(attr.name, attr.attachment)) {
+ if (elem = ref.file_picker_entry(attr.name, attr.attachment)) {
list.prepend(elem);
elem.focus();
}
@@ -765,23 +769,19 @@ function rcube_text_editor(config, id)
};
// close file browser window
- this.file_browser_close = function(url)
+ this.file_picker_close = function(url)
{
- var input = $('#' + rcmail.env.file_browser_field);
-
- if (url)
- input.val(url);
-
this.editor.windowManager.close();
- input.focus();
+ if (url)
+ rcmail.env.file_picker_callback(url);
if (rcmail.env.old_file_drop)
rcmail.gui_objects.filedrop = rcmail.env.old_file_drop;
};
// creates file browser entry
- this.file_browser_entry = function(file_id, file)
+ this.file_picker_entry = function(file_id, file)
{
if (!file.complete || !file.mimetype) {
return;
@@ -793,7 +793,7 @@ function rcube_text_editor(config, id)
var rx, img_src;
- switch (rcmail.env.file_browser_type) {
+ switch (rcmail.env.file_picker_type) {
case 'image':
rx = /^image\//i;
break;
@@ -817,10 +817,10 @@ function rcube_text_editor(config, id)
.data('url', href)
.append($('').append(img))
.append($('').text(file.name))
- .click(function() { ref.file_browser_close($(this).data('url')); })
+ .click(function() { ref.file_picker_close($(this).data('url')); })
.keydown(function(e) {
if (e.which == 13) {
- ref.file_browser_close($(this).data('url'));
+ ref.file_picker_close($(this).data('url'));
}
});
}
diff --git a/program/resources/tinymce/browser.css b/program/resources/tinymce/browser.css
index 320028783..1afb99174 100644
--- a/program/resources/tinymce/browser.css
+++ b/program/resources/tinymce/browser.css
@@ -1,20 +1,17 @@
/* This file contains the CSS data for media file selector of TinyMCE */
#image-selector {
- margin: 10px;
- margin-bottom: 30px;
padding-bottom: 85px;
+ border: 1px solid transparent;
}
#image-selector.droptarget.hover,
#image-selector.droptarget.active {
border: 1px solid #019bc6;
- box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
}
#image-selector.droptarget.hover {
background-color: #d9ecf4;
- box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
}
#image-selector form {
@@ -29,36 +26,29 @@
text-align: center;
}
-#image-selector a.button {
- color: #525252;
- text-decoration: none;
- font-size: 11px;
-}
-
#image-selector .upload-form {
text-align: center;
margin-bottom: 1rem;
}
-#image-selector .upload-form button {
- padding: 4px 8px;
- border: 1px solid #c0c0c0;
-}
-
#image-selector-list {
overflow-x: hidden;
overflow-y: auto;
- margin-left: 0;
+ padding: 0;
height: 250px;
}
#image-selector-list li {
line-height: 80px;
- padding: 2px;
+ padding: 3px;
+ padding-left: 5px;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
background: none;
+ display:flex;
+ align-items: center;
+ margin-bottom: 1px;
}
#image-selector-list li:hover,
@@ -72,7 +62,6 @@
}
#image-selector-list li span.name {
- vertical-align: middle;
font-weight: bold;
padding-left: 10px;
}
@@ -80,8 +69,14 @@
#image-selector-list li span.img {
height: 80px;
width: 80px;
+ min-width: 80px;
text-align: center;
- display: inline-block;
overflow: hidden;
line-height: 80px;
+ border-radius: 5px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #fff;
+ border: 1px solid #ddd;
}
diff --git a/skins/classic/common.css b/skins/classic/common.css
index 2c0eb97ba..7a01b0645 100644
--- a/skins/classic/common.css
+++ b/skins/classic/common.css
@@ -1568,42 +1568,33 @@ table.quota-info td.root {
}
/********** TinyMCE styles **********/
-.mce-btn-small button
-{
- height: 22px;
+
+div.tox .tox-toolbar,
+div.tox .tox-toolbar__overflow,
+div.tox .tox-toolbar__primary {
+ background-color: #f0f0f0;
}
-.mce-btn-small i
-{
- line-height: 16px !important;
- vertical-align: text-top !important;
+div.tox .tox-toolbar__primary {
+ border: 0;
}
-.mce-combobox button
-{
- padding: 6px 8px !important;
+div.tox div.tox-dialog-wrap__backdrop {
+ background: #aaa;
+ opacity: .3;
}
-.mce-tinymce
-{
- border-radius: 0 !important;
-{
-
-.mce-panel.mce-toolbar-grp
-{
- border: 0 !important;
+div.tox div.tox-dialog {
+ box-shadow: 1px 1px 18px #666;
+ border-width: 0;
}
-#image-selector-form.droptarget {
+#image-selector.droptarget {
background: url(images/filedrop.png) center bottom no-repeat;
}
-#image-selector-form.droptarget.hover
-{
+#image-selector.droptarget.hover {
background-color: #F0F0EE;
- box-shadow: 0 0 5px 0 #999;
- -moz-box-shadow: 0 0 5px 0 #999;
- -o-box-shadow: 0 0 5px 0 #999;
}
/** PGP key import dialog **/
diff --git a/skins/classic/functions.js b/skins/classic/functions.js
index 1b5bed403..a6a5b0ae3 100644
--- a/skins/classic/functions.js
+++ b/skins/classic/functions.js
@@ -577,7 +577,7 @@ resize_compose_body: function()
h = div.height() - 2,
x = bw.ie || bw.opera ? 4 : 0;
- $('#compose-body_ifr').width(w + 6).height(h - 1 - $('div.mce-toolbar').height());
+ $('#compose-body_ifr').width(w + 6).height(h - 1 - $('div.tox-toolbar').height());
$('#compose-body').width(w-x).height(h);
$('#googie_edit_layer').width(w).height(h);
},
diff --git a/skins/classic/mail.css b/skins/classic/mail.css
index 3ea340692..b11166427 100644
--- a/skins/classic/mail.css
+++ b/skins/classic/mail.css
@@ -1414,15 +1414,11 @@ div.hide-headers
border: 1px solid #999;
}
-#compose-body-div .mce-tinymce {
+#compose-body-div .tox-tinymce {
border: 0 !important;
width: 100% !important;
}
-.mce-top-part::before {
- box-shadow: none !important;
-}
-
#compose-div .boxlistcontent
{
bottom: 23px;
@@ -1764,10 +1760,6 @@ input.from_address
position: absolute;
}
-#image-selector {
- padding-bottom: 0 !important;
-}
-
/**** Styles for widescreen (3-column) view ****/
.widescreen #mailview-top {
diff --git a/skins/elastic/styles/colors.less b/skins/elastic/styles/colors.less
index 56a96f7a1..cb5daec1f 100644
--- a/skins/elastic/styles/colors.less
+++ b/skins/elastic/styles/colors.less
@@ -205,6 +205,10 @@
@color-datepicker-active-background: @color-main;
+// HTML editor
+@color-editor-disabled-mask: fadeout(lighten(@color-black, 85), 10);
+
+
// Image tools
@color-image-tools: #fff;
@color-image-tools-background: fadeout(@color-main, 60%);
diff --git a/skins/elastic/styles/widgets/dialogs.less b/skins/elastic/styles/widgets/dialogs.less
index 666f94ebf..38bf2f0d0 100644
--- a/skins/elastic/styles/widgets/dialogs.less
+++ b/skins/elastic/styles/widgets/dialogs.less
@@ -148,6 +148,7 @@ html.touch .popover {
max-width: initial;
margin: 0;
height: auto;
+ z-index: 1300; // above TinyMCE dialogs
.popover-header {
border-radius: .25rem .25rem 0 0 !important;
diff --git a/skins/elastic/styles/widgets/editor.less b/skins/elastic/styles/widgets/editor.less
index 74c2a10ff..a8c5d0df3 100644
--- a/skins/elastic/styles/widgets/editor.less
+++ b/skins/elastic/styles/widgets/editor.less
@@ -12,758 +12,335 @@
/*** Text Editor widget (and TinyMCE editor) ***/
-.mce-tinymce {
- &.mce-container.mce-panel {
+// use of div.tox instead of just .tox is to have prio over TinyMCE styles
+div.tox {
+ font-size: 1rem;
+
+ &, :not(.svg) {
+ .font-family;
+ }
+
+ &.tox-tinymce {
border-radius: .25rem;
- border-color: @color-input-border;
- overflow: hidden;
- }
-
- .mce-btn,
- .mce-panel {
- background-color: @color-input-addon-background;
- }
-
- .mce-panel {
- border-color: @color-input-border;
+ border: 1px solid @color-input-border;
}
&.focused {
border-color: @color-input-border-focus !important;
box-shadow: 0 0 0 .2rem @color-input-border-focus-shadow !important;
}
-}
-.mce-top-part::before,
-.mce-tinymce,
-.mce-window {
- box-shadow: none !important;
-}
+ .tox-toolbar-overlord {
+ z-index: 1; // for sticky header feature
-.mce-btn {
- &.mce-active {
- background: @color-btn-secondary-background !important;
+ & > div {
+ // The svg is copied from TinyMCE with modified height params
+ background: url("data:image/svg+xml;charset=utf8,%3Csvg height='33px' viewBox='0 0 40 33px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='32px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E");
+ background-color: @color-input-addon-background;
+ }
}
-}
-.mce-window {
- &.mce-container {
+ .tox-toolbar__primary {
+ border-top: 0;
+ }
+
+ // This one is for mobile
+ .tox-toolbar {
+ background-color: @color-input-addon-background;
+ }
+
+ .tox-edit-area {
border: 0;
+ }
- & :not(.mce-ico) {
- .font-family;
+ .tox-dialog {
+ border-radius: 0;
+ border-color: @color-layout-border;
+ box-shadow: none;
+ align-self: unset !important;
+
+ .tox-form__group {
+ margin-top: 0;
+ margin-bottom: .75rem;
+ }
+
+ .tox-dialog__body-nav-item--active {
+ color: @color-link;
+ border-color: transparent;
+
+ &:hover {
+ color: @color-link-hover;
+ }
}
}
- .mce-reset {
- background: #fff;
+ .tox-dialog__body-content {
+ overflow: unset;
}
- .mce-container-body {
- &.mce-abs-layout {
- overflow: unset;
- }
-
- .mce-abs-end {
- display: none;
- }
+ .tox-dialog-wrap__backdrop {
+ background-color: @color-dialog-overlay-background;
}
- .mce-window-head {
- height: @layout-header-height;
+ .tox-dialog__header {
+ height: (@layout-header-height - 1px);
border-bottom: 1px solid @color-dialog-header-border;
+ justify-content: flex-end; // fixes close button position when dialog has no title
padding: 0;
- .mce-title {
- line-height: @layout-header-height;
- font-size: 1.25rem;
- padding: 0 3rem 0 1rem;
+ .tox-button {
color: @color-dialog-header;
- }
-
- .mce-close {
- border: 0;
- color: @color-dialog-header;
- background: transparent;
right: 0;
- top: 0;
- position: absolute;
- height: (@layout-header-height - .75rem);
- width: 1.25em;
- margin: 0 .25rem;
- padding: .1rem .75rem;
- cursor: pointer;
- outline: 0;
+ height: (@layout-header-height - .7rem);
+ width: 2.25em;
+ margin-right: .4rem;
+
+ &:hover {
+ background: transparent;
+ border-color: transparent;
+ }
+
+ .tox-icon {
+ display: none;
+ }
&:before {
&:extend(.font-icon-class);
content: @fa-var-times;
- margin: 0;
- }
-
- i {
- display: none;
+ line-height: 1.5rem;
+ margin: 0 !important;
}
}
}
- .mce-foot {
+ .tox-dialog__footer {
+ height: (@layout-footer-height - 1px) !important;
border: 0;
- height: @layout-header-height !important;
- position: relative;
+ margin: 0;
+ padding: 0 1rem;
@media screen and (max-width: @screen-width-xs) {
border-top: 1px solid @color-dialog-header-border;
}
- .mce-container-body {
- height: 100% !important;
- display: flex;
- align-items: center;
- justify-content: flex-end; // just 'end' does not work in Chrome
+ & > div {
+ white-space: nowrap;
+ max-height: (@layout-footer-height - 1px);
- .mce-btn {
- position: initial;
- margin-right: .5rem;
- line-height: 1;
- width: auto !important;
- height: auto !important;
-
- &:last-child {
- margin-right: 1rem;
- }
-
- .mce-txt {
- line-height: 1.5;
- vertical-align: unset;
- }
-
- button:before {
- &:extend(.font-icon-class);
- display: inline;
- float: none;
- vertical-align: middle;
- margin-right: .4rem;
- }
- }
-
- .mce-abs-end {
- position: initial;
- width: 1rem;
- order: 9;
+ button:first-child {
+ margin: 0;
}
}
- .mce-btn {
- .btn-secondary;
- border-radius: .3rem;
- border-color: transparent;
-
- &:focus {
- border-color: transparent !important;
- color: @color-btn-secondary;
- background: @color-btn-secondary-background;
- }
-
- &.mce-primary {
- .btn-primary;
- }
-
- button:hover,
- button {
- color: @color-btn-secondary;
- padding: .5rem .75rem;
- }
- }
-
- .mce-btn:last-child button:before {
- content: @fa-var-times;
- }
-
- .mce-btn.mce-primary button:before {
- content: @fa-var-check;
- }
-
- .mce-search-foot {
- div:nth-of-type(2) button:before {
- content: @fa-var-search;
- }
- div:nth-of-type(3) button:before,
- div:nth-of-type(4) button:before {
- content: @fa-var-pencil-alt;
- }
- div:nth-of-type(6) button:before {
- content: @fa-var-chevron-left;
- }
- div:nth-of-type(7) button:before {
- content: @fa-var-chevron-right;
- }
- div:nth-of-type(7) button:after {
- &:extend(.font-icon-class);
- display: inline;
- float: none;
- margin: 0 0 0 .2rem;
- content: @fa-var-chevron-right;
- }
-
- @media screen and (min-width: (@screen-width-xs + 1px)) {
- div:nth-of-type(6) {
- margin-left: .5rem;
- }
- div:nth-of-type(7) button {
- &:before {
- display: none;
- }
- }
- }
- }
- }
-
- // Form elements, let's keep'em in .mce-window to make overwriting simpler
-
- .mce-formitem {
- min-width: 450px;
- position: unset !important;
-
- & > .mce-container-body {
- margin-bottom: .5rem;
-
- & > * {
- width: 75% !important;
- position: unset !important;
- }
-
- & > label {
- max-width: 25%;
- min-width: 25%;
- line-height: 2.5 !important;
- }
- }
-
- .mce-widget {
- border-radius: .25rem;
- }
- }
-
- .mce-form {
- padding: 1rem;
- box-sizing: border-box;
-
- .mce-form {
- padding: 0;
- position: unset !important;
- width: 100% !important;
-
- & > .mce-container-body {
- flex-wrap: wrap;
- height: auto !important;
- }
-
- .mce-formitem {
- min-width: 100%;
- width: 100% !important;
- }
- }
-
- .mce-container {
- height: auto !important;
-
- .mce-container-body {
- display: flex;
- height: auto !important;
-
- & > input:not([size="5"]) {
- position: relative;
- left: 0 !important;
- flex: 1;
- }
-
- }
- }
-
- & > .mce-container-body {
- box-sizing: border-box;
- width: 100% !important;
- }
-
- .mce-form-split {
- .mce-formitem {
- min-width: auto;
-
- & > .mce-container-body {
- width: 100% !important;
- }
- }
- }
-
- label {
- position: unset;
- line-height: 2.5 !important;
- height: auto !important;
- }
- }
-
- .mce-colorpicker {
- & + .mce-form {
- width: 150px !important;
- padding: 0;
-
- .mce-formitem {
- min-width: unset;
-
- & + :not(.mce-formitem) {
- height: 50px !important;
- }
- }
- }
- }
-
- .mce-textbox {
- padding: .375rem .75rem !important;
- line-height: 1.5;
- color: @color-font;
-
- &:not(textarea) {
- height: auto !important;
- }
-
- &:focus {
- color: @color-font;
- border-color: @color-input-border-focus;
- box-shadow: 0 0 0 .2rem @color-input-border-focus-shadow;
- }
-
- &[size="5"] {
- width: auto !important;
- }
-
- &.mce-multiline {
- line-height: 1.25;
- width: 100% !important;
- position: unset;
- box-sizing: border-box;
- display: block;
- }
- }
-
- .mce-listbox {
- button {
- line-height: 1.5;
- padding: .375rem .75rem;
- }
-
- &:focus {
- border-color: @color-input-border-focus !important;
- box-shadow: 0 0 0 .2rem @color-input-border-focus-shadow !important;
- }
- }
-
- .mce-checkbox {
- line-height: 2.5;
-
- i.mce-i-checkbox {
- border: 0;
- width: auto;
- color: @color-checkbox;
- text-indent: 0;
+ .tox-button {
+ .btn-primary;
+ font-weight: normal;
+ padding: .5rem .75rem;
&:before {
&:extend(.font-icon-class);
- margin: 0;
- content: @fa-var-toggle-off;
- }
- }
-
- &.mce-checked i.mce-i-checkbox:before {
- content: @fa-var-toggle-on;
- }
-
- &:focus {
- i.mce-i-checkbox {
- border: 0;
- }
- }
- }
-
- .mce-combobox {
- display: flex;
-
- input {
- border-radius: .3rem 0 0 .3rem;
- flex: 1;
-
- &:focus {
- z-index: 1;
- }
- }
-
- &.mce-combobox-fake {
- input {
- border-radius: .3rem;
- }
- }
-
- button {
- padding: .4rem .6rem;
- }
-
- .mce-btn {
- border-radius: 0 .3rem .3rem 0;
- background: @color-input-addon-background;
-
- &:focus {
- background-color: @color-input-border-focus-shadow;
- border-color: #c5c5c5;
- }
- }
- }
-
- .mce-tabs {
- padding-top: 1rem;
- margin: 0 1rem;
- border-color: @color-layout-border;
-
- .mce-tab {
- border-radius: .25rem .25rem 0 0;
- padding: .5rem 1rem;
- height: auto !important;
- border: 1px solid transparent;
- color: @color-link;
- background: transparent;
- margin-bottom: -1px;
-
- &.mce-active {
- border: 1px solid @color-layout-border;
- border-bottom-color: #fff;
- color: @color-font !important;
+ width: 1em;
+ content: @fa-var-check;
}
- &:not(.mce-active):hover {
- border: 1px solid @color-list-border;
- border-bottom-color: transparent;
- border-bottom: 0;
+ // this is redundant, but required because of tinymce styles interference
+ &:focus:not(:disabled) {
+ background: @color-btn-primary-background;
+ border-color: @color-btn-primary-background;
}
- &:focus {
- outline: unset !important;
- }
- }
- }
-
- .mce-label {
- text-shadow: none;
- color: @color-font;
- }
-}
-
-
-// Menus and popovers, e.g. color selector, emoticons selector, font selector
-.mce-menu,
-.mce-floatpanel.mce-popover {
- box-shadow: 3px 3px 5px @color-popover-shadow !important;
- border-color: @color-layout-border !important;
- border-radius: .3rem;
-}
-
-.mce-menu {
- .mce-menu-item.mce-active {
- color: @color-menu-hover;
- background-color: @color-menu-hover-background;
- }
-
- .popover-header {
- display: none !important;
- }
-}
-
-div.mce-menubtn.mce-opened {
- z-index: 65530 !important; // BUG: https://github.com/tinymce/tinymce/issues/4542
-}
-
-#mce-modal-block.mce-in {
- background-color: @color-dialog-overlay-background;
- opacity: 1 !important;
-}
-
-@media screen and (max-width: @screen-width-xs) {
- .mce-window {
- width: 100% !important;
- height: 100% !important;
- left: 0 !important;
- top: 0 !important;
- border-width: 0 !important;
-
- & > .mce-reset {
- display: flex;
- flex-direction: column;
- height: 100%;
- }
-
- .mce-window-body {
- flex: 1;
- overflow-y: auto !important;
- }
-
- & > .mce-reset > div,
- .mce-container-body {
- width: 100% !important;
- }
-
- .mce-window-head {
- background-color: @color-layout-mobile-header-background;
-
- .mce-title {
- font-size: 1rem;
- text-align: center;
- padding: 0 1rem;
- }
-
- .mce-close {
- display: none;
- }
- }
-
- .mce-foot {
- background-color: @color-layout-mobile-footer-background;
-
- .mce-container-body {
- justify-content: space-evenly;
-
- .mce-btn {
- position: initial;
- height: 100% !important;
- margin: 0;
- background: transparent;
- border-width: 0;
-
- &:focus {
- box-shadow: none;
- }
-
- &:hover {
- background: transparent;
- }
-
- &:last-child {
- margin: 0;
- }
-
- button {
- color: @color-font;
- padding: .45rem;
- font-size: .9rem;
-
- &:before {
- display: block;
- float: none;
- width: 100%;
- margin: 0;
- line-height: 1.75;
- height: 1.75rem;
- }
- }
- }
-
- .mce-abs-end {
- display: none;
- }
- }
-
- .mce-search-foot {
- div:nth-of-type(7) button:after {
- display: none;
- }
- }
- }
-
- .mce-form,
- .mce-form + .mce-container, // for Embed tab in Media dialog
- .mce-formitem,
- .mce-combobox,
- .mce-panel:not(.mce-popover) {
- width: 100% !important;
- }
-
- .mce-formitem {
- min-width: unset;
- }
-
- .mce-form {
- & > .mce-container-body {
- display: flex;
- flex-direction: column;
- left: 0;
- right: 0;
- box-sizing: border-box;
- }
-
- .mce-container-body {
- height: auto !important;
- flex-direction: column;
-
- & > label {
- position: unset !important;
- width: 100% !important;
- max-width: 100%;
- }
-
- & > label + * {
- position: unset !important;
- width: auto !important;
- }
-
- & > .mce-checkbox {
- position: absolute;
- left: 0 !important;
- top: 3rem !important;
- }
- }
- }
-
- // FIXME: How to fix the input width in less hacky way?
- .mce-combobox input {
- max-width: ~"calc(100% - 4rem)";
- }
- .mce-combobox-fake input {
- max-width: ~"calc(100% - 1.7rem)";
- }
- }
-
- .mce-menu {
- width: @layout-mobile-menu-width !important;
- right: 0;
- top: 0 !important;
- left: auto !important;
- height: 100% !important;
- max-height: unset !important;
- padding: 0 !important;
- margin: 0 !important;
- border-radius: 0;
- border: 0 !important;
-
- .popover-header {
- display: block !important;
-
- a {
- font-size: 1.2rem;
- line-height: @layout-touch-header-height;
+ &.tox-button--secondary {
+ .btn-secondary;
+ color: @color-btn-secondary;
&:before {
content: @fa-var-times;
}
- }
- }
- .mce-container-body {
- width: 100% !important;
- }
-
- .mce-menu-item {
- height: @layout-touch-menu-record-height;
- line-height: @layout-touch-menu-record-height;
- padding: 0 .5rem;
- border-left: 0;
- border-bottom: 1px solid @color-list-border;
- margin: 0;
-
- .mce-ico {
- font-size: 150%;
- padding: 0 .7rem 0 .25rem;
- margin-top: -.2rem;
- }
-
- .mce-text {
- font-size: 1.2rem;
- .font-family;
- line-height: @layout-touch-menu-record-height;
- color: @color-font;
- }
-
- .mce-caret {
- display: none;
- }
-
- &.mce-menu-item-preview {
- &.mce-active {
- border-left: none;
- position: relative;
-
- &:after {
- .font-icon-class; // :extend() does not work here
- content: @fa-var-check;
- position: absolute;
- right: .5rem;
- top: 0;
- color: @color-font;
- }
+ // this is redundant, but required because of tinymce styles interference
+ &:focus:not(:disabled) {
+ background: @color-btn-secondary-background;
+ border-color: @color-btn-secondary-background;
}
}
+ }
+ }
- &.mce-menu-item-expand {
- position: relative;
+ .tox-search-dialog {
+ .tox-form__group:not(:first-child) {
+ flex: initial !important;
+ }
- &:after {
- .font-icon-class; // :extend() does not work here
- content: @fa-var-angle-right;
- position: absolute;
- right: .5rem;
- top: 0;
+ .tox-dialog__footer-start {
+ button {
+ padding: .25rem;
+ }
+ }
+
+ .tox-dialog__footer-end {
+ button {
+ &:before {
+ content: @fa-var-pencil-alt !important;
+ }
+
+ &:nth-of-type(1):before {
+ content: @fa-var-search !important;
+ }
+ }
+ }
+ }
+
+ .tox-dialog__title {
+ line-height: @layout-header-height;
+ font-size: 1.25rem;
+ font-weight: bold;
+ padding: 0 0 0 1rem;
+ width: 100%;
+ color: @color-dialog-header;
+ }
+
+ // Make toolbar buttons smaller
+ .tox-tbtn {
+ height: 28px;
+
+ &:not(.tox-tbtn--select,.tox-split-button__chevron) {
+ width: 32px;
+ }
+ }
+
+ .tox-label {
+ color: @color-font;
+ padding-bottom: .25rem;
+ }
+
+ // Adding .form-control does not work with TinyMCE skins,
+ // so we have to overwrite some props here
+ .tox-color-input > input,
+ .tox-selectfield select,
+ .tox-textarea,
+ .tox-textfield {
+ .font-family !important;
+ font-size: @page-font-size;
+ line-height: 1.5;
+ color: @color-font;
+ border-radius: .25rem;
+ min-height: 0;
+ padding: .375rem .75rem;
+
+ &:focus {
+ border-color: @color-input-border-focus;
+ box-shadow: 0 0 0 .2rem @color-input-border-focus-shadow;
+ }
+ }
+
+ .tox-color-input span {
+ top: 5px;
+ }
+
+ .custom-switch {
+ position: relative;
+ font-size: 1rem;
+ margin-top: .15rem;
+
+ .tox-checkbox__icons {
+ display: none;
+ }
+
+ .tox-checkbox__label {
+ margin: 0;
+ }
+ }
+
+ .image-selector {
+ font-size: 1rem;
+ button {
+ .btn-secondary;
+ padding: .5rem .75rem;
+ line-height: 1.5;
+ }
+ }
+
+ // small fix for image dialog
+ .tox-form__controls-h-stack div:not(:last-child) {
+ flex: 1;
+ }
+
+ .tox-collection__item-label {
+ white-space: nowrap; // fix TinyMCE bug
+ }
+}
+
+@media screen and (max-width: @screen-width-xs) {
+ div.tox {
+ .tox-dialog {
+ margin: 0 !important;
+ width: 100% !important;
+ height: 100%;
+ left: 0 !important;
+ top: 0 !important;
+ border-width: 0 !important;
+ }
+
+ .tox-dialog__header {
+ background-color: @color-layout-mobile-header-background;
+
+ .tox-button {
+ display: none;
+ }
+ }
+
+ .tox-dialog__title {
+ font-size: 1rem;
+ text-align: center;
+ padding: 0 1rem;
+ }
+
+ .tox-dialog__footer {
+ background-color: @color-layout-mobile-footer-background;
+
+ .tox-button {
+ color: @color-font !important;
+ background: transparent !important;
+ padding: .45rem;
+ margin: 0 !important;
+ border: 0;
+ font-size: 90%;
+
+ &:before {
+ display: block;
+ float: none;
+ width: 100%;
+ margin: 0;
+ line-height: 1.75;
+ height: 1.75rem;
+ }
+
+ &:active,
+ &:focus,
+ &:hover {
+ background: transparent;
+ border: 0;
+ box-shadow: none;
color: @color-font;
}
}
- }
- }
- .mce-menu-item-sep,
- .mce-menu-shortcut {
- display: none !important;
- }
+ & > div {
+ justify-content: space-evenly;
+ display: flex;
+ width: 100%;
- .mce-charmap-dialog {
- position: unset !important;
-
- + .mce-container {
- display: none;
- }
- }
-
- .mce-charmap {
- display: block;
-
- tbody {
- display: block;
- }
-
- tr {
- display: flex;
- flex-wrap: wrap;
- }
-
- td {
- flex: 1;
- height: auto !important;
- min-width: 17%;
- padding: 0 !important;
- border: 0 !important;
- border-bottom: 1px solid @color-list-border !important;
-
- div {
- font-size: 3rem;
- line-height: 2;
+ &:empty {
+ display: none;
+ }
}
}
}
}
-html.touch .mce-grid td {
- padding: .5rem;
-}
-
-
/*** Media file selector for TinyMCE ***/
.image-selector {
- margin: 1rem 1rem 1rem 1rem !important;
padding: 1rem .5rem 10rem .5rem !important;
&.droptarget {
@@ -774,27 +351,17 @@ html.touch .mce-grid td {
}
}
- button {
- .btn-secondary;
- padding: .5rem .75rem;
- line-height: 1.5;
- position: relative;
-
- &:before {
- line-height: 1;
- }
- }
-
form {
position: absolute;
top: 0;
}
.attachmentslist {
- margin-left: 0;
+ margin: 0;
overflow-x: hidden;
overflow-y: auto;
height: 19.1em;
+ padding: 0 !important;
li {
padding: .25rem;
@@ -855,51 +422,41 @@ html.touch .mce-grid td {
.mce-i-html {
display: block;
- padding: 1px 5px;
- margin: 2px;
- width: 2rem;
- height: 24px;
- border: 1px solid transparent;
- color: #595959;
+ margin: 2px 2px 2px 4px;
+ width: 34px;
+ height: 28px;
+ border-radius: .25rem;
+ color: #222f3e; // from TinyMCE
&:focus,
&:hover {
text-decoration: none;
border-color: #e2e4e7;
- background-color: #fff;
+ background-color: #dee0e2; // from TinyMCE
+ }
+
+ &:before {
+ &:extend(.font-icon-class);
+ content: @fa-var-image;
+ margin: 0;
+ width: 34px;
+ line-height: 28px;
}
}
}
// hide toolbar in html mode and in mailvelope mode
&.mailvelope .editor-toolbar,
- .mce-tinymce + textarea + .editor-toolbar {
+ .tox-tinymce + .editor-toolbar {
display: none;
}
- .mce-i-html:before,
- .mce-i-plaintext:before {
- &:extend(.font-icon-class);
- margin: 0;
- width: 1em;
- font-size: 1.2rem;
- }
-
- .mce-i-html:before {
- content: @fa-var-image;
- line-height: 1.2em;
- }
-
- .mce-i-plaintext:before {
- content: @fa-var-window-close; //@fa-var-align-justify;
- }
-
& > .googie_edit_layer,
& > textarea {
font-family: monospace;
font-size: 13px;
width: 100% !important;
- padding-top: 2.5rem;
+ padding-top: 48px;
resize: none;
}
@@ -909,8 +466,9 @@ html.touch .mce-grid td {
min-height: 30em;
}
- #composebody_ifr {
- min-height: 30em;
+ & > .tox-tinymce.focused {
+ border-color: @color-input-border-focus;
+ box-shadow: 0 0 0 .2rem @color-input-border-focus-shadow !important;
}
}
diff --git a/skins/elastic/ui.js b/skins/elastic/ui.js
index c5acc5343..a8eba38e8 100644
--- a/skins/elastic/ui.js
+++ b/skins/elastic/ui.js
@@ -486,20 +486,6 @@ function rcube_elastic_ui()
.addEventListener('clonerow', pretty_checkbox_fix)
.addEventListener('init', init);
- // Add styling for TinyMCE editor popups
- // We need to use MutationObserver, as TinyMCE does not provide any events for this
- if (window.MutationObserver && window.tinymce) {
- var callback = function(list) {
- $.each(list, function() {
- $.each(this.addedNodes, function() {
- tinymce_style(this);
- });
- });
- };
-
- (new MutationObserver(callback)).observe(document.body, {childList: true});
- }
-
// Create floating action button(s)
if ((layout.list.length || layout.content.length) && is_mobile()) {
var fabuttons = [];
@@ -1150,86 +1136,6 @@ function rcube_elastic_ui()
$('select:not([multiple])', context).each(function() { pretty_select(this); });
};
- /**
- * Detects if the element is TinyMCE dialog/menu
- * and adds Elastic styling to it
- */
- function tinymce_style(elem)
- {
- // TinyMCE dialog widnows
- if ($(elem).is('.mce-window')) {
- var body = $(elem).find('.mce-window-body'),
- foot = $(elem).find('.mce-foot > .mce-container-body');
-
- // Apply basic forms style
- if (body.length) {
- bootstrap_style(body[0]);
- }
-
- body.find('button').filter(function() { return $(this).parent('.mce-btn').length > 0; }).removeClass('btn btn-secondary');
-
- // Fix icons in Find and Replace dialog footer
- if (foot.children('.mce-widget').length === 5) {
- foot.addClass('mce-search-foot');
- }
-
- // Apply some form structure fixes and helper classes
- $(elem).find('.mce-charmap').parent().parent().addClass('mce-charmap-dialog');
- $(elem).find('.mce-combobox').each(function() {
- if (!$(this).children('.mce-btn').length) {
- $(this).addClass('mce-combobox-fake');
- }
- });
- $(elem).find('.mce-form > .mce-container-body').each(function() {
- if ($(this).children('.mce-formitem').length > 4) {
- $(this).addClass('mce-form-split');
- }
- });
- $(elem).find('.mce-form').next(':not(.mce-formitem)').addClass('mce-form');
-
- // Fix dialog height (e.g. Table properties dialog)
- if (!is_mobile()) {
- var offset, max_height = 0, height = body.height();
- $(elem).find('.mce-form').each(function() {
- max_height = Math.max(max_height, $(this).height());
- });
-
- if (height < max_height) {
- max_height += (body.find('.mce-tabs').height() || 0) + 25;
- body.height(max_height);
- $(elem).height($(elem).height() + (max_height - height));
- $(elem).css('top', ($(window).height() - $(elem).height())/2 + 'px');
- }
- }
- }
- // TinyMCE menus on mobile
- else if ($(elem).is('.mce-menu')) {
- $(elem).prepend(
- $('