Update to TinyMCE 4.7.13, refactor image selector dialog, add style for Elastic skin

pull/6273/head^2
Aleksander Machniak 6 years ago
parent fd7d7faabd
commit 00acb46411

@ -12,6 +12,7 @@ CHANGELOG Roundcube Webmail
- Support for IMAP folders that cannot contain both folders and messages (#5057)
- Update to jQuery-3.3.1
- Update to jQuery-minicolors 2.2.6
- Update to TinyMCE 4.7.13
- Remove sample PHP configuration from .htaccess and .user.ini files (#5850)
- Use Masterminds/HTML5 parser for better HTML5 support (#5761)
- Add More actions button in Contacts toolbar with Copy/Move actions (#6081)

@ -36,10 +36,10 @@
},
{
"lib": "tinymce",
"version": "4.5.8",
"version": "4.7.13",
"url": "http://download.ephox.com/tinymce/community/tinymce_$v.zip",
"dest": "program/js",
"sha1": "08b0757264adb86066940bbafb7aa9ec0c7c6685",
"sha1": "7f988f3899aebee6d49bd55e981331da07eee6c5",
"license": "LGPL",
"copyright": "Copyright (c) 1999-2015 Ephox Corp. All rights reserved",
"rm": "program/js/tinymce",
@ -56,7 +56,7 @@
},
{
"lib": "tinymce-langs",
"version": "4.5.8",
"version": "4.7.13",
"url": "https://tinymce-services.azurewebsites.net/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",
"dest": "program/js/tinymce"
},

@ -1998,7 +1998,13 @@ class rcmail extends rcube
$this->output->add_label('selectimage', 'addimage', 'selectmedia', 'addmedia');
$this->output->set_env('editor_config', $config);
$this->output->include_css('program/resources/tinymce/browser.css');
if ($path = $this->config->get('media_browser_css_location', 'program/resources/tinymce/browser.css')) {
if ($path != 'none') {
$this->output->include_css($path);
}
}
$this->output->include_script('tinymce/tinymce.min.js');
$this->output->include_script('editor.js');
}

@ -39,7 +39,7 @@ 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=4050800',
cache_suffix: 's=4071300',
theme: 'modern',
language: config.lang,
content_css: rcmail.assets_path('program/resources/tinymce/content.css'),
@ -55,7 +55,9 @@ function rcube_text_editor(config, id)
image_description: false,
paste_webkit_style: "color font-size font-family",
paste_data_images: true,
browser_spellcheck: true
browser_spellcheck: true,
anchor_bottom: false,
anchor_top: false
};
// register spellchecker for plain text editor
@ -146,6 +148,9 @@ function rcube_text_editor(config, id)
return false;
}
});
ed.on('focus blur', function(e) {
$(ed.getContainer()).toggleClass('focused');
});
};
rcmail.triggerEvent('editor-init', {config: conf, ref: ref});
@ -648,21 +653,27 @@ function rcube_text_editor(config, id)
// image selector
this.file_browser_callback = function(field_name, url, type)
{
var i, elem, cancel, dialog, fn, list = [];
var i, button, elem, cancel, dialog, fn, hint, list = [],
form = $('.upload-form').clone();
// open image selector dialog
dialog = this.editor.windowManager.open({
this.editor.windowManager.open({
title: rcmail.get_label('select' + type),
width: 500,
height: 300,
html: '<div id="image-selector-list"><ul></ul></div>'
+ '<div id="image-selector-form"><div id="image-upload-button" class="mce-widget mce-btn" role="button" tabindex="0"></div></div>',
html: '<div id="image-selector" class="image-selector file-upload"><ul id="image-selector-list" class="attachmentslist"></ul></div>',
buttons: [{text: 'Cancel', onclick: function() { ref.file_browser_close(); }}]
});
rcmail.env.file_browser_field = field_name;
rcmail.env.file_browser_type = type;
dialog = $('#image-selector');
if (form.length)
button = dialog.prepend(form).find('button,a.button')
.text(rcmail.get_label('add' + type))
.focus();
// fill images list with available images
for (i in rcmail.env.attachments) {
if (elem = ref.file_browser_entry(i, rcmail.env.attachments[i])) {
@ -670,47 +681,44 @@ function rcube_text_editor(config, id)
}
}
if (list.length) {
$('#image-selector-list > ul').append(list).find('li:first').focus();
}
cancel = dialog.parent().parent().find('button:last').parent();
// add hint about max file size (in dialog footer)
$('div.mce-abs-end', dialog.getEl()).append($('<div class="hint">')
.text($('div.hint', rcmail.gui_objects.uploadform).text()));
// Add custom Tab key handlers, tabindex does not work
list = $('#image-selector-list').append(list).on('keydown', 'li', function(e) {
if (e.which == 9) {
if (rcube_event.get_modifier(e) == SHIFT_KEY) {
if (!$(this).prev().focus().length) {
button.focus();
}
}
else if (!$(this).next().focus().length) {
cancel.focus();
}
// init upload button
elem = $('#image-upload-button').append($('<span>').text(rcmail.get_label('add' + type)));
cancel = elem.parents('.mce-panel').find('button:last').parent();
return false;
}
});
// we need custom Tab key handlers, until we find out why
// tabindex do not work here as expected
elem.keydown(function(e) {
button.keydown(function(e) {
if (e.which == 9) {
// on Tab + Shift focus first file
if (rcube_event.get_modifier(e) == SHIFT_KEY)
$('#image-selector-list li:last').focus();
// on Tab focus Cancel button
else
if (rcube_event.get_modifier(e) == SHIFT_KEY || !list.find('li:first').focus().length) {
cancel.focus();
}
return false;
}
});
cancel.keydown(function(e) {
if (e.which == 9) {
// on Tab + Shift focus upload button
if (rcube_event.get_modifier(e) == SHIFT_KEY)
elem.focus();
else
$('#image-selector-list li:first').focus();
if (rcube_event.get_modifier(e) != SHIFT_KEY || !list.find('li:last').focus().length) {
button.focus();
}
return false;
}
});
// enable (smart) upload button
this.hack_file_input(elem, rcmail.gui_objects.uploadform);
// enable drag-n-drop area
if ((window.XMLHttpRequest && XMLHttpRequest.prototype && XMLHttpRequest.prototype.sendAsBinary) || window.FormData) {
if (!rcmail.env.filedrop) {
@ -720,7 +728,7 @@ function rcube_text_editor(config, id)
rcmail.env.old_file_drop = rcmail.gui_objects.filedrop;
}
rcmail.gui_objects.filedrop = $('#image-selector-form');
rcmail.gui_objects.filedrop = $('#image-selector');
rcmail.gui_objects.filedrop.addClass('droptarget')
.on('dragover dragleave', function(e) {
e.preventDefault();
@ -736,7 +744,7 @@ function rcube_text_editor(config, id)
rcmail.addEventListener('fileuploaded', function(attr) {
var elem;
if (elem = ref.file_browser_entry(attr.name, attr.attachment)) {
$('#image-selector-list > ul').prepend(elem);
list.prepend(elem);
elem.focus();
}
});
@ -781,7 +789,7 @@ function rcube_text_editor(config, id)
case 'media':
rx = /^video\//i;
img_src = 'program/resources/tinymce/video.png';
img_src = rcmail.assets_path('program/resources/tinymce/video.png');
break;
default:
@ -803,82 +811,7 @@ function rcube_text_editor(config, id)
if (e.which == 13) {
ref.file_browser_close($(this).data('url'));
}
// we need custom Tab key handlers, until we find out why
// tabindex do not work here as expected
else if (e.which == 9) {
if (rcube_event.get_modifier(e) == SHIFT_KEY) {
if (!$(this).prev().focus().length)
$('#image-upload-button').parents('.mce-panel').find('button:last').parent().focus();
}
else {
if (!$(this).next().focus().length)
$('#image-upload-button').focus();
}
return false;
}
});
}
};
// create smart files upload button
this.hack_file_input = function(elem, clone_form)
{
var offset, link = $(elem),
file = $('<input>').attr('name', '_file[]'),
form = $('<form>').attr({method: 'post', enctype: 'multipart/form-data'});
// clone existing upload form
if (clone_form) {
file.attr('name', $('input[type="file"]', clone_form).attr('name'));
form.attr('action', $(clone_form).attr('action'))
.append($('<input>').attr({type: 'hidden', name: '_token', value: rcmail.env.request_token}));
}
function move_file_input(e) {
if (!offset) offset = link.offset();
file.css({top: (e.pageY - offset.top - 10) + 'px', left: (e.pageX - offset.left - 10) + 'px'});
}
file.attr({type: 'file', multiple: 'multiple', size: 5, title: '', tabindex: -1})
.change(function() { rcmail.upload_file(form, 'upload'); })
.click(function() { setTimeout(function() { link.mouseleave(); }, 20); })
// opacity:0 does the trick, display/visibility doesn't work
.css({opacity: 0, cursor: 'pointer', position: 'relative', outline: 'none'})
.appendTo(form);
// In FF and IE we need to move the browser file-input's button under the cursor
// Thanks to the size attribute above we know the length of the input field
if (navigator.userAgent.match(/Firefox|MSIE/))
file.css({marginLeft: '-80px'});
// Note: now, I observe problem with cursor style on FF < 4 only
link.css({overflow: 'hidden', cursor: 'pointer'})
.mouseenter(function() { this.__active = true; })
// place button under the cursor
.mousemove(function(e) {
if (this.__active)
move_file_input(e);
// move the input away if button is disabled
else
$(this).mouseleave();
})
.mouseleave(function() {
file.css({top: '-10000px', left: '-10000px'});
this.__active = false;
})
.click(function(e) {
// forward click if mouse-enter event was missed
if (!this.__active) {
this.__active = true;
move_file_input(e);
file.trigger(e);
}
})
.keydown(function(e) {
if (e.which == 13) file.trigger('click');
})
.mouseleave()
.append(form);
};
}

@ -1,45 +1,54 @@
/* This file contains the CSS data for media file selector of TinyMCE */
#image-selector-list {
position: absolute;
top: 0;
left: 0;
right: 152px;
height: 100%;
overflow-x: hidden;
overflow-y: auto;
#image-selector {
margin: 10px;
margin-bottom: 30px;
padding-bottom: 85px;
}
#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 {
#image-selector form {
position: absolute;
top: 0;
bottom: 0;
right: 0;
width: 150px;
border: 0;
border: 1px solid #FFF;
border-left: 1px solid #DDD;
}
#image-selector .hint {
line-height: 25px;
color: #666;
font-size: 11px;
text-align: center;
padding-top: 10px;
}
#image-upload-button {
width: 80%;
height: 30px;
#image-selector a.button {
color: #525252;
text-decoration: none;
font-size: 11px;
}
#image-upload-button span {
position: absolute;
width: 100%;
text-align: center;
line-height: 30px;
#image-selector-list {
overflow-x: hidden;
overflow-y: auto;
margin-left: 0;
height: 250px;
}
#image-selector-list li {
line-height: 80px;
padding: 2px 0 2px 3px;
padding: 2px;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
background: none;
}
#image-selector-list li:hover,
@ -47,18 +56,18 @@
background-color: #F0F0F0;
}
#image-selector-list ul li img {
#image-selector-list li img {
vertical-align: middle;
max-height: 80px;
}
#image-selector-list ul li span.name {
#image-selector-list li span.name {
vertical-align: middle;
font-weight: bold;
padding-left: 10px;
}
#image-selector-list ul li span.img {
#image-selector-list li span.img {
height: 80px;
width: 80px;
text-align: center;
@ -66,25 +75,3 @@
overflow: hidden;
line-height: 80px;
}
#image-selector-form.droptarget.hover,
#image-selector-form.droptarget.active {
border: 1px solid #019bc6;
box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
-moz-box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
-webkit-box-shadow: 0 0 3px 2px rgba(71,135,177, 0.5);
}
#image-selector-form.droptarget.hover {
background-color: #d9ecf4;
box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
-moz-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
-webkit-box-shadow: 0 0 5px 2px rgba(71,135,177, 0.9);
}
div.mce-abs-end div.hint {
line-height: 50px;
padding-left: 10px;
color: #999;
text-shadow: 0 1px 1px #FFF;
}

@ -1416,6 +1416,11 @@ div.hide-headers
#compose-body-div .mce-tinymce {
border: 0 !important;
width: 100% !important;
}
.mce-top-part::before {
box-shadow: none !important;
}
#compose-div .boxlistcontent
@ -1759,6 +1764,10 @@ input.from_address
position: absolute;
}
#image-selector {
padding-bottom: 0 !important;
}
/**** Styles for widescreen (3-column) view ****/
.widescreen #mailview-top {

@ -6,6 +6,7 @@
"config": {
"layout": "widescreen",
"jquery_ui_colors_theme": "bootstrap",
"embed_css_location": "/styles/embed.css"
"embed_css_location": "/styles/embed.css",
"media_browser_css_location": "none"
}
}

@ -127,6 +127,7 @@ a {
@import "widgets/searchbar";
@import "widgets/lists";
@import "widgets/forms";
@import "widgets/editor";
@import "widgets/mail";

@ -0,0 +1,700 @@
/**
* Roundcube webmail styles for the Elastic skin
*
* Copyright (c) 2017-2018, The Roundcube Dev Team
*
* The contents are subject to the Creative Commons Attribution-ShareAlike
* License. It is allowed to copy, distribute, transmit and to adapt the work
* by keeping credits to the original authors in the README.md file.
* See http://creativecommons.org/licenses/by-sa/3.0/ for details.
*/
/*** Text Editor widget (and TinyMCE editor) ***/
.mce-tinymce {
&.mce-container.mce-panel {
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;
}
}
.mce-top-part::before,
.mce-tinymce,
.mce-window {
box-shadow: none !important;
}
.mce-window {
&.mce-container {
border: 0;
& :not(.mce-ico) {
.font-family;
}
}
.mce-container-body {
&.mce-abs-layout {
overflow: unset;
}
.mce-abs-end {
display: none;
}
}
.mce-window-head {
height: @layout-header-height;
border-bottom: 1px solid @color-dialog-header-border;
padding: 0;
.mce-title {
line-height: @layout-header-height;
font-size: 1.25rem;
padding: 0 3rem 0 1rem;
color: @color-dialog-header;
}
.mce-close {
border: 0;
color: @color-dialog-header;
background: transparent;
right: 0;
top: 0;
position: absolute;
height: (@layout-header-height - .7rem);
width: 1.25em;
margin: .25rem;
padding: .1rem .75rem;
cursor: pointer;
&:before {
&:extend(.font-icon-class);
content: @fa-var-times;
margin: 0;
}
i {
display: none;
}
}
}
.mce-foot {
border: 0;
height: @layout-header-height !important;
position: relative;
@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: end;
.mce-btn {
position: initial;
margin-right: .5rem;
line-height: 1;
width: auto !important;
.mce-txt {
line-height: 1.5;
vertical-align: unset;
}
button:before {
&:extend(.font-icon-class);
display: inline;
float: none;
}
}
.mce-abs-end {
position: initial;
width: 1rem;
order: 9;
}
}
.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-check;
}
div:nth-of-type(6) button:before {
content: @fa-var-chevron-left;
}
div:nth-of-type(7) button:before {
content: @fa-var-chevron-right;
}
}
}
// Form elements, let's keep'em in .mce-window to make overwriting simpler
.mce-textbox {
padding: .375rem .75rem;
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-formitem {
.mce-widget {
border-radius: .25rem;
}
}
.mce-checkbox {
line-height: 1.5;
i.mce-i-checkbox {
border: 0;
width: auto;
color: @color-checkbox;
text-indent: 0;
&: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;
color: @color-checkbox-focus;
}
}
}
.mce-combobox {
display: flex;
input {
border-radius: .3rem 0 0 .3rem;
flex: 1;
&:focus {
z-index: 1;
}
}
button {
padding: .4rem .6rem;
}
.mce-btn {
border-radius: 0 .3rem .3rem 0;
background: @color-input-addon-background;
&:focus {
border-color: @color-input-border-focus;
box-shadow: 0 0 0 .2rem @color-input-border-focus-shadow;
}
}
}
.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;
}
&:not(.mce-active):hover {
border: 1px solid @color-list-border;
border-bottom-color: transparent;
border-bottom: 0;
}
}
}
.mce-label {
text-shadow: none;
color: @color-font;
}
.mce-form {
.mce-container {
height: auto !important;
.mce-container-body {
display: flex;
& > label {
position: relative;
}
& > input:not([size="5"]) {
position: relative;
left: 0 !important;
flex: 1;
}
}
}
}
}
.mce-btn {
&.mce-active {
background: @color-btn-secondary-background !important;
}
.mce-window .mce-foot & {
.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;
}
}
}
// 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-toolbarmenu-hover;
background-color: @color-toolbarmenu-hover-background;
}
}
#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-foot {
.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;
}
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-menu {
width: auto !important;
right: 0;
left: 0 !important;
margin: 0 1rem !important;
.mce-container-body {
width: 100% !important;
}
}
div.mce-menubtn.mce-opened {
z-index: 65530 !important;
}
.mce-container.mce-abs-layout-item.mce-first + .mce-container.mce-abs-layout-item.mce-last:not(.mce-formitem),
.mce-menu-item-sep,
.mce-menu-shortcut {
display: none !important;
}
.mce-charmap-dialog {
position: unset;
}
.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;
}
}
}
.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-form + .mce-container, // for Embed tab in Media dialog
.mce-form {
& > .mce-container-body {
display: flex;
flex-direction: column;
padding: 0 1rem;
left: 0;
right: 0;
box-sizing: border-box;
& > .mce-container {
position: unset;
}
}
.mce-container-body {
height: auto !important;
flex-direction: column;
& > label {
position: unset !important;
width: 100% !important;
margin-top: 1rem;
}
& > label + * {
position: unset !important;
margin-top: .5rem;
width: auto !important;
flex: 1;
}
& > .mce-checkbox {
position: absolute;
left: 0 !important;
top: 3rem !important;
}
}
}
// FIXME: How to fix the input width in less hacky way?
.mce-window .mce-combobox input {
max-width: ~"calc(100% - 4rem)";
}
}
/*** Media file selector for TinyMCE ***/
.image-selector {
margin: 1rem 1rem 1rem 1rem !important;
padding: 1rem .5rem 10rem .5rem !important;
&.droptarget {
border: .2rem dashed @color-table-border;
}
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;
overflow-x: hidden;
overflow-y: auto;
height: 18em;
li {
padding: .25rem;
cursor: pointer;
&:before {
display: none;
}
&:hover,
&:focus {
background: @color-list-selected-background;
}
span.name {
flex: 1;
margin: auto;
padding-left: 1rem;
.overflow-ellipsis;
}
span.img {
height: 80px;
width: 80px;
display: flex;
border: 1px solid @color-list-border;
background: white;
border-radius: .75rem;
overflow: hidden;
}
img {
margin: auto;
}
}
}
@media screen and (max-width: @screen-width-small) {
.attachmentslist {
height: auto;
}
}
}
/*** HTML editor widget ***/
.html-editor {
position: relative;
display: flex;
margin-bottom: .25rem;
& > .nav {
border-color: transparent;
z-index: 1;
position: absolute;
top: 1px;
right: 1rem;
a.active {
border-color: @color-input-border !important;
&.mode-html {
background-color: @color-input-addon-background;
border-bottom-color: @color-input-addon-background !important;
}
&.mode-plain {
border-bottom-color: #fff !important;
}
}
a:hover {
border-bottom-color: transparent;
}
}
& > iframe, // e.g. mailvelope frame
& > .googie_edit_layer,
& > .mce-tinymce,
& > textarea {
margin-top: 2.55rem;
font-family: monospace;
width: 100% !important;
}
& > iframe { // e.g. mailvelope frame
border-radius: .3rem;
border: 1px solid @color-input-border;
min-height: 30em;
}
#composebody_ifr {
min-height: 30em;
}
& > .mce-tinymce.focused {
border-color: @color-input-border-focus;
box-shadow: 0 0 0 .2rem @color-input-border-focus-shadow !important;
}
}
/*** GoogieSpell widget ***/
.googie_window {
width: 16rem;
}
.googie_edit_layer {
font-family: monospace;
// from Bootstrap's textarea
padding: .5rem .75rem;
border: 1px solid @color-input-border;
border-radius: .3rem;
line-height: 1.25;
}
.googie_link {
color: @color-spellcheck-link;
text-decoration: underline;
cursor: pointer;
}
.googie_list {
td {
min-width: 8rem;
width: auto;
&.googie_list_onhover {
color: @color-toolbarmenu-hover;
background-color: @color-toolbarmenu-hover-background;
}
.googie_list_revert:before {
&:extend(.font-icon-class);
content: @fa-var-plus-square;
}
.googie_add_to_dict:before {
&:extend(.font-icon-class);
content: @fa-var-plus-square;
}
}
input {
display: inline-block;
margin: .5rem .5rem .5rem 0 !important;
padding: .5rem .75rem !important;
}
}

@ -833,6 +833,7 @@ html.touch .popupmenu.form {
.hint {
margin-bottom: .5rem;
color: @color-form-hint;
text-align: center;
}
.attachmentslist {
@ -1083,7 +1084,6 @@ html.touch .popupmenu.form {
/*** Percent input with jQuery-UI slider ***/
// Structure: <input><span.label><div.ui-slider>
.input-percent-slider {
display: flex;
@ -1104,6 +1104,7 @@ html.touch .popupmenu.form {
}
}
/*** Image upload widget ***/
.image-upload {
@ -1204,119 +1205,6 @@ html.touch input.icon-checkbox + label {
}
/*** HTML editor widget (and TinyMCE editor) ***/
.mce-tinymce {
&.mce-container.mce-panel {
border-radius: .25rem;
border-color: @color-input-border;
overflow: hidden;
}
.mce-btn,
.mce-panel {
background-color: @color-input-addon-background;
}
}
.html-editor {
position: relative;
display: flex;
margin-bottom: .25rem;
& > .nav {
border-color: transparent;
z-index: 1;
position: absolute;
top: 1px;
right: 1rem;
a.active {
border-color: @color-input-border !important;
&.mode-html {
background-color: @color-input-addon-background;
border-bottom-color: @color-input-addon-background !important;
}
&.mode-plain {
border-bottom-color: #fff !important;
}
}
a:hover {
border-bottom-color: transparent;
}
}
& > iframe, // e.g. mailvelope frame
& > .googie_edit_layer,
& > .mce-tinymce,
& > textarea {
margin-top: 2.55rem;
font-family: monospace;
width: 100% !important;
}
& > iframe { // e.g. mailvelope frame
border-radius: .3rem;
border: 1px solid @color-input-border;
min-height: 35em;
}
}
/*** GoogieSpell widget ***/
.googie_window {
width: 16rem;
}
.googie_edit_layer {
font-family: monospace;
// from Bootstrap's textarea
padding: .5rem .75rem;
border: 1px solid @color-input-border;
border-radius: .3rem;
line-height: 1.25;
}
.googie_link {
color: @color-spellcheck-link;
text-decoration: underline;
cursor: pointer;
}
.googie_list {
td {
min-width: 8rem;
width: auto;
&.googie_list_onhover {
color: @color-toolbarmenu-hover;
background-color: @color-toolbarmenu-hover-background;
}
.googie_list_revert:before {
&:extend(.font-icon-class);
content: @fa-var-plus-square;
}
.googie_add_to_dict:before {
&:extend(.font-icon-class);
content: @fa-var-plus-square;
}
}
input {
display: inline-block;
margin: .5rem .5rem .5rem 0 !important;
padding: .5rem .75rem !important;
}
}
/*** General browser hacks ***/
// Remove outline on selects in Firefox

@ -321,7 +321,9 @@ function rcube_elastic_ui()
$(list)[$('.treetoggle', list).length > 0 ? 'removeClass' : 'addClass']('notree');
};
(new MutationObserver(callback)).observe(list, {childList: true, subtree: true});
if (window.MutationObserver) {
(new MutationObserver(callback)).observe(list, {childList: true, subtree: true});
}
callback();
});
};
@ -444,6 +446,20 @@ function rcube_elastic_ui()
.addEventListener('setquota', update_quota)
.addEventListener('enable-command', enable_command_handler)
.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});
}
};
/**
@ -914,6 +930,32 @@ function rcube_elastic_ui()
$('select:not([multiple])', context).each(function() { pretty_select(this); });
};
/**
* Detects if the element is TinyMCE dialog window
* and adds Elastic styling to it
*/
function tinymce_style(elem)
{
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');
}
$(elem).find('.mce-charmap').parent().parent().addClass('mce-charmap-dialog');
}
};
/**
* Initializes popup menus
*/

@ -1305,6 +1305,7 @@ body.status-flagged .flag-icon {
overflow: auto;
}
#image-selector.droptarget,
#compose-attachments.droptarget {
background-image: url(images/filedrop.png);
background-position: center bottom;
@ -1345,7 +1346,7 @@ body.status-flagged .flag-icon {
}
#composebodycontainer .mce-panel {
border-color: #ccc !important;
border-color: #ddd !important;
background: #f0f0f0;
}

@ -3060,6 +3060,14 @@ ul.toolbarmenu li span.copy {
}
/** Common TinyMCE fixes **/
.mce-btn:not(.mce-active) {
background: transparent !important;
}
.mce-btn:not(.mce-active):hover {
background: white !important;
}
.mce-btn-small .mce-ico {
display: inline; /* for old Firefox */
}
@ -3073,6 +3081,10 @@ _:not(), _:-moz-handler-blocked, .mozilla .mce-btn-small i {
line-height: 20px !important;
}
.mce-top-part::before {
box-shadow: none !important;
}
.mce-textbox {
border-radius: 0;
box-shadow: none;

@ -178,7 +178,7 @@
</div>
<div id="compose-attachments" class="rightcol" role="region" aria-labelledby="aria-label-composeattachments">
<h2 id="aria-label-composeattachments" class="voice"><roundcube:label name="attachments" /></h2>
<div style="text-align:center; margin-bottom:10px">
<div class="upload-form" style="text-align:center; margin-bottom:10px">
<roundcube:object name="composeAttachmentForm" mode="hint" />
<a class="button" tabindex="1" href="#" onclick="rcmail.upload_input('uploadform')"><roundcube:label name="addattachment" /></a>
</div>

Loading…
Cancel
Save