program/include/rcmail.php | ●●●●● patch | view | raw | blame | history | |
program/js/app.js | ●●●●● patch | view | raw | blame | history | |
program/js/editor.js | ●●●●● patch | view | raw | blame | history | |
program/localization/en_US/labels.inc | ●●●●● patch | view | raw | blame | history | |
program/steps/mail/attachments.inc | ●●●●● patch | view | raw | blame | history | |
skins/classic/common.css | ●●●●● patch | view | raw | blame | history | |
skins/classic/images/filedrop.png | patch | view | raw | blame | history | |
skins/classic/mail.css | ●●●●● patch | view | raw | blame | history | |
skins/larry/mail.css | ●●●●● patch | view | raw | blame | history | |
skins/larry/styles.css | ●●●●● patch | view | raw | blame | history | |
skins/larry/ui.js | ●●●●● patch | view | raw | blame | history |
program/include/rcmail.php
@@ -1799,6 +1799,7 @@ 'spelldict' => intval($this->config->get('spellcheck_dictionary')) )); $this->output->add_label('selectimage', 'addimage'); $this->output->include_script('tinymce/tinymce.min.js'); $this->output->include_script('editor.js'); $this->output->add_script("rcmail_editor_init($script)", 'docready'); program/js/app.js
@@ -539,11 +539,11 @@ // execute all foreign onload scripts // @deprecated for (var i in this.onloads) { if (typeof this.onloads[i] === 'string') eval(this.onloads[i]); else if (typeof this.onloads[i] === 'function') this.onloads[i](); for (n in this.onloads) { if (typeof this.onloads[n] === 'string') eval(this.onloads[n]); else if (typeof this.onloads[n] === 'function') this.onloads[n](); } // start keep-alive and refresh intervals @@ -4010,6 +4010,9 @@ // called from upload page this.add2attachment_list = function(name, att, upload_id) { if (upload_id) this.triggerEvent('fileuploaded', {name: name, attachment: att, id: upload_id}); if (!this.gui_objects.attachmentlist) return false; program/js/editor.js
@@ -29,7 +29,6 @@ relative_urls: false, remove_script_host: false, convert_urls: false, // #1486944 image_list: window.rcmail_editor_images, image_description: false, paste_webkit_style: "color font-size font-family", paste_data_images: true @@ -52,7 +51,10 @@ spellchecker_rpc_url: '../../../../../?_task=utils&_action=spell_html&_remote=1', spellchecker_enable_learn_rpc: config.spelldict, //TODO spellchecker_language: rcmail.env.spell_lang, accessibility_focus: false accessibility_focus: false, file_browser_callback: rcmail_file_browser_callback, // @todo: support more than image (types: file, image, media) file_browser_callback_types: 'image' }); conf.setup = function(ed) { @@ -150,17 +152,151 @@ } } // editor callback for images listing function rcmail_editor_images(callback) // image selector function rcmail_file_browser_callback(field_name, url, type, win) { var i, file, list = []; var i, elem, dialog, list = [], editor = tinyMCE.activeEditor; // open image selector dialog dialog = editor.windowManager.open({ title: rcmail.gettext('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"></div></div>', buttons: [{text: 'Cancel', onclick: function() { rcmail_file_browser_close(); }}] }); rcmail.env.file_browser_field = field_name; rcmail.env.file_browser_type = type; // fill images list with available images for (i in rcmail.env.attachments) { file = rcmail.env.attachments[i]; if (file.complete && file.mimetype.startsWith('image/')) { list.push({title: file.name, value: rcmail.env.comm_path+'&_id='+rcmail.env.compose_id+'&_action=display-attachment&_file='+i}); if (elem = rcmail_file_browser_entry(i, rcmail.env.attachments[i])) { list.push(elem); } } callback(list); if (list.length) { $('#image-selector-list > ul').append(list); } // add hint about max file size (in dialog footer) $('div.mce-abs-end', dialog.getEl()).append($('<div class="hint">').text($('#uploadform div.hint').text())); // enable (smart) upload button elem = $('#image-upload-button').append($('<span>').text(rcmail.gettext('add' + type))); hack_file_input(elem, rcmail.gui_objects.uploadform); // enable drag-n-drop area if (rcmail.gui_objects.filedrop && rcmail.env.filedrop && ((window.XMLHttpRequest && XMLHttpRequest.prototype && XMLHttpRequest.prototype.sendAsBinary) || window.FormData)) { rcmail.env.old_file_drop = rcmail.gui_objects.filedrop; rcmail.gui_objects.filedrop = $('#image-selector-form'); rcmail.gui_objects.filedrop.addClass('droptarget') .bind('dragover dragleave', function(e) { e.preventDefault(); e.stopPropagation(); $(this)[(e.type == 'dragover' ? 'addClass' : 'removeClass')]('hover'); }) .get(0).addEventListener('drop', function(e) { return rcmail.file_dropped(e); }, false); } // register handler for successful file upload if (!rcmail.env.file_dialog_event) { rcmail.env.file_dialog_event = true; rcmail.addEventListener('fileuploaded', function(attr) { var elem; if (elem = rcmail_file_browser_entry(attr.name, attr.attachment)) { $('#image-selector-list > ul').prepend(elem); } }); } } // close file browser window function rcmail_file_browser_close(url) { if (url) $('#' + rcmail.env.file_browser_field).val(url); tinyMCE.activeEditor.windowManager.close(); if (rcmail.env.old_file_drop) rcmail.gui_objects.filedrop = rcmail.env.old_file_drop; } // creates file browser entry function rcmail_file_browser_entry(file_id, file) { if (!file.complete || !file.mimetype) { return; } if (file.mimetype.startsWith('image/')) { var href = rcmail.env.comm_path+'&_id='+rcmail.env.compose_id+'&_action=display-attachment&_file='+file_id, img = $('<img>').attr({title: file.name, src: href + '&_thumbnail=1'}); return $('<li>').data('url', href) .append($('<span class="img">').append(img)) .append($('<span class="name">').text(file.name)) .click(function() { rcmail_file_browser_close($(this).data('url')); }); } } // create smart files upload button function hack_file_input(elem, clone_form) { var link = $(elem), file = $('<input>'), form = $('<form>').attr({method: 'post', enctype: 'multipart/form-data'}), offset = link.offset(); // 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) { 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: ''}) .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); } }) .mouseleave() .append(form); } program/localization/en_US/labels.inc
@@ -226,6 +226,8 @@ $labels['dsn'] = 'Delivery status notification'; $labels['mailreplyintro'] = 'On $date, $sender wrote:'; $labels['originalmessage'] = 'Original Message'; $labels['selectimage'] = 'Select image'; $labels['addimage'] = 'Add image'; $labels['editidents'] = 'Edit identities'; $labels['spellcheck'] = 'Spell'; program/steps/mail/attachments.inc
@@ -74,6 +74,47 @@ if ($attachment['status']) { if (empty($attachment['size'])) { $attachment['size'] = $attachment['data'] ? strlen($attachment['data']) : @filesize($attachment['path']); } // generate image thumbnail for file browser in HTML editor if (!empty($_GET['_thumbnail'])) { $temp_dir = $RCMAIL->config->get('temp_dir'); $thumbnail_size = 80; list(,$ext) = explode('/', $attachment['mimetype']); $mimetype = $attachment['mimetype']; $file_ident = $attachment['id'] . ':' . $attachment['mimetype'] . ':' . $attachment['size']; $cache_basename = $temp_dir . '/' . md5($file_ident . ':' . $RCMAIL->user->ID . ':' . $thumbnail_size); $cache_file = $cache_basename . '.' . $ext; // render thumbnail image if not done yet if (!is_file($cache_file)) { if (!$attachment['path']) { $orig_name = $filename = $cache_basename . '.orig.' . $ext; file_put_contents($orig_name, $attachment['data']); } else { $filename = $attachment['path']; } $image = new rcube_image($filename); if ($imgtype = $image->resize($thumbnail_size, $cache_file, true)) { $mimetype = 'image/' . $imgtype; if ($orig_name) { unlink($orig_name); } } } if (is_file($cache_file)) { // cache for 1h $RCMAIL->output->future_expire_header(3600); header('Content-Type: ' . $mimetype); header('Content-Length: ' . filesize($cache_file)); readfile($cache_file); exit; } } header('Content-Type: ' . $attachment['mimetype']); skins/classic/common.css
@@ -597,14 +597,6 @@ height: 16px; } .mce-btn-small button { height: 22px; } .mce-btn-small i { line-height: 16px !important; vertical-align: text-top !important; } /***** common table settings ******/ @@ -1122,3 +1114,122 @@ .quota_text_high { color: white; } .quota_text_mid { color: #666; } .quota_text_low { color: #666; } /********** TinyMCE styles **********/ .mce-btn-small button { height: 22px; } .mce-btn-small i { line-height: 16px !important; vertical-align: text-top !important; } .mce-combobox button { padding: 6px 8px !important; } .mce-tinymce, .mce-panel.mce-toolbar-grp { border: 0 !important; } #image-selector-list { position: absolute; top: 0; left: 0; right: 152px; height: 100%; overflow-x: hidden; overflow-y: auto; } #image-selector-form { position: absolute; top: 0; bottom: 0; right: 0; width: 150px; border: 0; border: 1px solid #FFF; border-left: 1px solid #DDD; background: url(images/filedrop.png) center bottom no-repeat; text-align: center; padding-top: 10px; } #image-upload-button { width: 80%; height: 30px; } #image-upload-button span { position: absolute; width: 100%; text-align: center; line-height: 30px; } #image-selector-list li { line-height: 80px; padding: 2px 0 2px 3px; cursor: pointer; overflow: hidden; text-overflow: ellipsis; } #image-selector-list li:hover { background-color: #F0F0F0; } #image-selector-list ul li img { vertical-align: middle; max-height: 80px; } #image-selector-list ul li span.name { vertical-align: middle; font-weight: bold; padding-left: 10px; line-height: 80px; vertical-align: middle; } #image-selector-list ul li span.img { width: 80px; text-align: center; display: inline-block; overflow: hidden; line-height: 80px; vertical-align: middle; } #image-selector-form.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; } div.mce-abs-end div.hint { line-height: 50px; padding-left: 10px; color: #999; text-shadow: 0 1px 1px #FFF; } skins/classic/images/filedrop.png
skins/classic/mail.css
@@ -1520,13 +1520,6 @@ outline: none; } .mce-container.mce-panel { border: none; border-bottom: 1px solid #ccc; background-image: none; } #compose-headers { width: 100%; skins/larry/mail.css
@@ -1550,6 +1550,7 @@ #composebodycontainer .mce-tinymce { border: 0 !important; margin-top: 1px; } #composebodycontainer .mce-panel { skins/larry/styles.css
@@ -2599,3 +2599,96 @@ padding: 0; margin-left: 0; } /*** image selector in HTML editor ***/ #image-selector-list { position: absolute; top: 0; left: 0; right: 152px; height: 100%; overflow-x: hidden; overflow-y: auto; } #image-selector-form { position: absolute; top: 0; bottom: 0; right: 0; width: 150px; border: 0; border: 1px solid #FFF; border-left: 1px solid #DDD; background: url(images/filedrop.png) center bottom no-repeat; text-align: center; padding-top: 10px; } #image-upload-button { width: 80%; height: 30px; } #image-upload-button span { position: absolute; width: 100%; text-align: center; line-height: 30px; } #image-selector-list li { line-height: 80px; padding: 2px 0 2px 3px; cursor: pointer; overflow: hidden; text-overflow: ellipsis; } #image-selector-list li:hover { background-color: #F0F0F0; } #image-selector-list ul li img { vertical-align: middle; max-height: 80px; } #image-selector-list ul li span.name { vertical-align: middle; font-weight: bold; padding-left: 10px; } #image-selector-list ul li span.img { height: 80px; width: 80px; text-align: center; display: inline-block; 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); -o-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); -o-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; } skins/larry/ui.js
@@ -527,7 +527,7 @@ h = body.parent().height() - 8; body.width(w).height(h); $('#composebodycontainer > div').width(w+8).css('margin-top', '1px'); $('#composebodycontainer > div').width(w+8); $('#composebody_ifr').height(h + 4 - $('div.mce-toolbar').height()); $('#googie_edit_layer').height(h - 8); // $('#composebodycontainer')[(btns ? 'addClass' : 'removeClass')]('buttons');