diff options
-rw-r--r-- | CHANGELOG | 1 | ||||
-rw-r--r-- | program/js/app.js | 76 | ||||
-rw-r--r-- | program/js/editor.js | 13 | ||||
-rw-r--r-- | program/steps/mail/compose.inc | 5 | ||||
-rw-r--r-- | skins/default/common.css | 14 | ||||
-rw-r--r-- | skins/default/functions.js | 38 | ||||
-rw-r--r-- | skins/default/images/messageicons.gif | bin | 1998 -> 2030 bytes | |||
-rw-r--r-- | skins/default/images/messageicons.png | bin | 4062 -> 4098 bytes | |||
-rw-r--r-- | skins/default/mail.css | 11 | ||||
-rw-r--r-- | skins/default/templates/compose.html | 12 | ||||
-rw-r--r-- | skins/larry/mail.css | 8 | ||||
-rw-r--r-- | skins/larry/styles.css | 10 | ||||
-rw-r--r-- | skins/larry/templates/compose.html | 12 | ||||
-rw-r--r-- | skins/larry/ui.js | 47 |
14 files changed, 194 insertions, 53 deletions
@@ -1,6 +1,7 @@ CHANGELOG Roundcube Webmail =========================== +- Unified (single) spellchecker button - Fix encoding of attachment with comma in name (#1488389) - Scroll long lists on drag&drop (#1485946) - Fix handling of % character in IMAP protocol (#1488382) diff --git a/program/js/app.js b/program/js/app.js index d406844ae..755f10725 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -261,11 +261,9 @@ function rcube_webmail() $.merge(this.env.compose_commands, ['add-recipient', 'firstpage', 'previouspage', 'nextpage', 'lastpage']); if (this.env.spellcheck) { - this.env.spellcheck.spelling_state_observer = function(s){ ref.set_spellcheck_state(s); }; + this.env.spellcheck.spelling_state_observer = function(s) { ref.spellcheck_state(); }; this.env.compose_commands.push('spellcheck') - this.set_spellcheck_state('ready'); - if ($("input[name='_is_html']").val() == '1') - this.display_spellcheck_controls(false); + this.enable_command('spellcheck', true); } document.onmouseup = function(e){ return p.doc_mouse_up(e); }; @@ -898,13 +896,18 @@ function rcube_webmail() break; case 'spellcheck': - if (window.tinyMCE && tinyMCE.get(this.env.composebody)) { - tinyMCE.execCommand('mceSpellCheck', true); + if (this.spellcheck_state()) { + this.stop_spellchecking(); } - else if (this.env.spellcheck && this.env.spellcheck.spellCheck && this.spellcheck_ready) { - this.env.spellcheck.spellCheck(); - this.set_spellcheck_state('checking'); + else { + if (window.tinyMCE && tinyMCE.get(this.env.composebody)) { + tinyMCE.execCommand('mceSpellCheck', true); + } + else if (this.env.spellcheck && this.env.spellcheck.spellCheck) { + this.env.spellcheck.spellCheck(); + } } + this.spellcheck_state(); break; case 'savedraft': @@ -3116,8 +3119,9 @@ function rcube_webmail() this.toggle_editor = function(props) { + this.stop_spellchecking(); + if (props.mode == 'html') { - this.display_spellcheck_controls(false); this.plain2html($('#'+props.id).val(), props.id); tinyMCE.execCommand('mceAddControl', false, props.id); @@ -3128,8 +3132,6 @@ function rcube_webmail() } else { var thisMCE = tinyMCE.get(props.id), existingHtml; - if (thisMCE.plugins.spellchecker && thisMCE.plugins.spellchecker.active) - thisMCE.execCommand('mceSpellCheck', false); if (existingHtml = thisMCE.getContent()) { if (!confirm(this.get_label('editorwarning'))) { @@ -3138,7 +3140,6 @@ function rcube_webmail() this.html2plain(existingHtml, props.id); } tinyMCE.execCommand('mceRemoveControl', false, props.id); - this.display_spellcheck_controls(true); } return true; @@ -3147,43 +3148,52 @@ function rcube_webmail() this.stop_spellchecking = function() { var ed; + if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody))) { if (ed.plugins.spellchecker && ed.plugins.spellchecker.active) ed.execCommand('mceSpellCheck'); } - else if ((ed = this.env.spellcheck) && !this.spellcheck_ready) { - $(ed.spell_span).trigger('click'); - this.set_spellcheck_state('ready'); + else if (ed = this.env.spellcheck) { + if (ed.state && ed.state != 'ready' && ed.state != 'no_error_found') + $(ed.spell_span).trigger('click'); } + + this.spellcheck_state(); }; - this.display_spellcheck_controls = function(vis) + this.spellcheck_state = function() { - if (this.env.spellcheck) { - // stop spellchecking process - if (!vis) - this.stop_spellchecking(); + var ed, active; - $(this.env.spellcheck.spell_container)[vis ? 'show' : 'hide'](); - } - }; + if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody)) && ed.plugins.spellchecker) + active = ed.plugins.spellchecker.active; + else if ((ed = this.env.spellcheck) && ed.state) + active = ed.state != 'ready' && ed.state != 'no_error_found'; - this.set_spellcheck_state = function(s) - { - this.spellcheck_ready = (s == 'ready' || s == 'no_error_found'); - this.enable_command('spellcheck', this.spellcheck_ready); + $('#'+rcmail.buttons.spellcheck[0].id)[active ? 'addClass' : 'removeClass']('selected'); + + return active; }; // get selected language this.spellcheck_lang = function() { var ed; - if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody)) && ed.plugins.spellchecker) { + + if (window.tinyMCE && (ed = tinyMCE.get(this.env.composebody)) && ed.plugins.spellchecker) return ed.plugins.spellchecker.selectedLang; - } - else if (this.env.spellcheck) { + else if (this.env.spellcheck) return GOOGIE_CUR_LANG; - } + }; + + this.spellcheck_lang_set = function(lang) + { + var editor; + + if (window.tinyMCE && (editor = tinyMCE.get(this.env.composebody))) + editor.plugins.spellchecker.selectedLang = lang; + else if (this.env.spellcheck) + this.env.spellcheck.setCurrentLanguage(lang); }; // resume spellchecking, highlight provided mispellings without new ajax request @@ -3202,6 +3212,8 @@ function rcube_webmail() sp.prepare(false, true); sp.processData(data); } + + this.spellcheck_state(); } this.set_draft_id = function(id) diff --git a/program/js/editor.js b/program/js/editor.js index e95ead16e..ce3b38c0e 100644 --- a/program/js/editor.js +++ b/program/js/editor.js @@ -44,11 +44,11 @@ function rcmail_editor_init(config) theme_advanced_buttons1: 'bold,italic,underline,strikethrough,justifyleft,justifycenter,justifyright,justifyfull,separator,outdent,indent,charmap,hr,link,unlink,code,forecolor', theme_advanced_buttons2: ',fontselect,fontsizeselect' }); - else // mail compose + else { // mail compose $.extend(conf, { plugins: 'paste,emotions,media,nonbreaking,table,searchreplace,visualchars,directionality,tabfocus' + (config.spellcheck ? ',spellchecker' : ''), theme_advanced_buttons1: 'bold,italic,underline,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,outdent,indent,ltr,rtl,blockquote,|,forecolor,backcolor,fontselect,fontsizeselect', - theme_advanced_buttons2: 'link,unlink,table,|,emotions,charmap,image,media,|,code,search' + (config.spellcheck ? ',spellchecker' : '') + ',undo,redo', + theme_advanced_buttons2: 'link,unlink,table,|,emotions,charmap,image,media,|,code,search,undo,redo', spellchecker_languages: (rcmail.env.spellcheck_langs ? rcmail.env.spellcheck_langs : 'Dansk=da,Deutsch=de,+English=en,Espanol=es,Francais=fr,Italiano=it,Nederlands=nl,Polski=pl,Portugues=pt,Suomi=fi,Svenska=sv'), spellchecker_rpc_url: '?_task=utils&_action=spell_html', spellchecker_enable_learn_rpc: config.spelldict, @@ -56,6 +56,15 @@ function rcmail_editor_init(config) oninit: 'rcmail_editor_callback' }); + // add handler for spellcheck button state update + conf.setup = function(ed) { + ed.onSetProgressState.add(function(ed, active) { + if (!active) + rcmail.spellcheck_state(); + }); + } + } + // support external configuration settings e.g. from skin if (window.rcmail_editor_settings) $.extend(conf, window.rcmail_editor_settings); diff --git a/program/steps/mail/compose.inc b/program/steps/mail/compose.inc index 8c3e61183..56abd2456 100644 --- a/program/steps/mail/compose.inc +++ b/program/steps/mail/compose.inc @@ -813,6 +813,9 @@ function rcmail_compose_body($attrib) if (!$spellcheck_langs[$lang]) $lang = 'en'; + $OUTPUT->set_env('spell_langs', $spellcheck_langs); + $OUTPUT->set_env('spell_lang', $lang); + $editor_lang_set = array(); foreach ($spellcheck_langs as $key => $name) { $editor_lang_set[] = ($key == $lang ? '+' : '') . JQ($name).'='.JQ($key); @@ -830,7 +833,7 @@ function rcmail_compose_body($attrib) "googie.lang_learn_word = \"%s\";\n". "googie.setLanguages(%s);\n". "googie.setCurrentLanguage('%s');\n". - "googie.setSpellContainer('spellcheck-control');\n". + "googie.setDecoration(false);\n". "googie.decorateTextarea('%s');\n". "%s.set_env('spellcheck', googie);", $RCMAIL->output->get_skin_path(), diff --git a/skins/default/common.css b/skins/default/common.css index 31ecbe905..57fc1275a 100644 --- a/skins/default/common.css +++ b/skins/default/common.css @@ -495,6 +495,7 @@ body.iframe .boxtitle padding: 2px 10px; text-decoration: none; min-height: 14px; + background: transparent; } .popupmenu li a.active, @@ -504,7 +505,8 @@ body.iframe .boxtitle color: #333; } -.popupmenu li a.active:hover +.popupmenu li a.active:hover, +.popupmenu.selectable li a.selected:hover { color: #fff; background-color: #c00; @@ -515,6 +517,16 @@ body.iframe .boxtitle float: left; } +.popupmenu.selectable li a.selected +{ + background: url(images/messageicons.png) 2px -372px no-repeat; +} + +.popupmenu.selectable li a +{ + padding-left: 20px; +} + .darkbg { background-color: #F2F2F2 !important; diff --git a/skins/default/functions.js b/skins/default/functions.js index aab386b5e..fb7a05d4b 100644 --- a/skins/default/functions.js +++ b/skins/default/functions.js @@ -102,6 +102,7 @@ function rcube_mail_ui() groupmenu: {id:'groupoptionsmenu', above:1}, mailboxmenu: {id:'mailboxoptionsmenu', above:1}, composemenu: {id:'composeoptionsmenu', editable:1, overlap:1}, + spellmenu: {id:'spellmenu'}, // toggle: #1486823, #1486930 uploadmenu: {id:'attachment-form', editable:1, above:1, toggle:!bw.ie&&!bw.linux }, uploadform: {id:'upload-form', editable:1, toggle:!bw.ie&&!bw.linux } @@ -351,6 +352,43 @@ save_listmenu: function() rcmail.set_list_options(cols, sort, ord, thread == 'thread' ? 1 : 0); }, +spellmenu: function(show) +{ + var link, li, + lang = rcmail.spellcheck_lang(), + menu = this.popups.spellmenu.obj, + ul = $('ul', menu); + + if (!ul.length) { + ul = $('<ul>'); + + for (i in rcmail.env.spell_langs) { + li = $('<li>'); + link = $('<a href="#">').text(rcmail.env.spell_langs[i]) + .addClass('active').data('lang', i) + .click(function() { + rcmail.spellcheck_lang_set($(this).data('lang')); + }); + + link.appendTo(li); + li.appendTo(ul); + } + + ul.appendTo(menu); + } + + // select current language + $('li', ul).each(function() { + var el = $('a', this); + if (el.data('lang') == lang) + el.addClass('selected'); + else if (el.hasClass('selected')) + el.removeClass('selected'); + }); + + this.show_popupmenu('spellmenu', show); +}, + body_mouseup: function(evt, p) { var i, target = rcube_event.get_target(evt); diff --git a/skins/default/images/messageicons.gif b/skins/default/images/messageicons.gif Binary files differindex 80423dd1e..5c681e354 100644 --- a/skins/default/images/messageicons.gif +++ b/skins/default/images/messageicons.gif diff --git a/skins/default/images/messageicons.png b/skins/default/images/messageicons.png Binary files differindex d45f065ea..99038c732 100644 --- a/skins/default/images/messageicons.png +++ b/skins/default/images/messageicons.png diff --git a/skins/default/mail.css b/skins/default/mail.css index 33ddc08c6..b884eda87 100644 --- a/skins/default/mail.css +++ b/skins/default/mail.css @@ -38,6 +38,17 @@ opacity: 0.35; } +#messagetoolbar a.button.selected { + background-color: #ddd; + margin-left: 4px; + margin-right: 4px; + margin-top: -1px; + border: 1px solid #ccc; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + #messagetoolbar a.checkmailSel { background-position: 0 -32px; } diff --git a/skins/default/templates/compose.html b/skins/default/templates/compose.html index 208c8263c..285a783a1 100644 --- a/skins/default/templates/compose.html +++ b/skins/default/templates/compose.html @@ -3,7 +3,9 @@ <head> <title><roundcube:object name="productname" /> :: <roundcube:label name="compose" /></title> <roundcube:include file="/includes/links.html" /> +<roundcube:if condition="config:enable_spellcheck" /> <link rel="stylesheet" type="text/css" href="/googiespell.css" /> +<roundcube:endif /> <script type="text/javascript" src="/functions.js"></script> <script type="text/javascript" src="/splitter.js"></script> <style type="text/css"> @@ -23,7 +25,12 @@ <div id="messagetoolbar"> <roundcube:button command="list" type="link" class="button back" classAct="button back" classSel="button backSel" title="backtolist" content=" " /> <roundcube:button command="send" type="link" class="buttonPas send" classAct="button send" classSel="button sendSel" title="sendmessage" content=" " /> - <roundcube:button command="spellcheck" type="link" class="buttonPas spellcheck" classAct="button spellcheck" classSel="button spellcheckSel" title="checkspelling" content=" " /> +<roundcube:if condition="config:enable_spellcheck" /> + <span class="dropbutton"> + <roundcube:button command="spellcheck" type="link" class="buttonPas spellcheck" classAct="button spellcheck" classSel="button spellcheckSel" title="checkspelling" content=" " /> + <span id="spellmenulink" onclick="rcmail_ui.show_popup('spellmenu');return false"></span> + </span> +<roundcube:endif /> <roundcube:button name="addattachment" type="link" class="button attach" classAct="button attach" classSel="button attachSel" title="addattachment" onclick="rcmail_ui.show_popup('uploadmenu', true);return false" content=" " /> <roundcube:button command="insert-sig" type="link" class="buttonPas insertsig" classAct="button insertsig" classSel="button insertsigSel" title="insertsignature" content=" " /> <roundcube:button command="savedraft" type="link" class="buttonPas savedraft" classAct="button savedraft" classSel="button savedraftSel" title="savemessage" content=" " /> @@ -111,7 +118,6 @@ <roundcube:button type="input" command="list" class="button" label="cancel" tabindex="11" /> </div> <div id="compose-editorfooter"> - <span id="spellcheck-control" style="margin-right:10px"></span> <roundcube:if condition="!in_array('htmleditor', (array)config:dont_override)" /> <span> <label><roundcube:label name="editortype" /></label> @@ -143,6 +149,8 @@ </table> </div> +<div id="spellmenu" class="popupmenu selectable"></div> + </form> <roundcube:object name="composeAttachmentForm" id="attachment-form" attachmentFieldSize="40" class="popupmenu" /> diff --git a/skins/larry/mail.css b/skins/larry/mail.css index a9deea6e1..f96827b27 100644 --- a/skins/larry/mail.css +++ b/skins/larry/mail.css @@ -1166,11 +1166,12 @@ div.message-part blockquote blockquote blockquote { #composebody { position: absolute; - top: 24px; + top: 1px; left: 0; bottom: 0; width: 99%; border: 0; + border-radius: 0; padding: 8px 0 8px 8px; box-shadow: none; resize: none; @@ -1195,11 +1196,6 @@ div.message-part blockquote blockquote blockquote { overflow: auto; } -#spellcheck-control { - margin: 6px 8px; - text-align: right; -} - .defaultSkin table.mceLayout, .defaultSkin table.mceLayout tr.mceLast td { border: 0 !important; diff --git a/skins/larry/styles.css b/skins/larry/styles.css index 4c242f56b..c9a4b0f67 100644 --- a/skins/larry/styles.css +++ b/skins/larry/styles.css @@ -1390,7 +1390,8 @@ ul.proplist li { } .toolbar a.button.spellcheck { - background-position: center -930px; + min-width: 64px; + background-position: left -930px; } .toolbar a.button.insertsig { @@ -1574,10 +1575,15 @@ select.decorated option[selected='selected'] { background: linear-gradient(top, #00aad6 0%, #008fc9 100%); } -ul.toolbarmenu.iconized li a { +ul.toolbarmenu.iconized li a, +ul.toolbarmenu.selectable li a { padding-left: 30px; } +ul.toolbarmenu.selectable li a.selected { + background: url(images/messages.png) 4px -27px no-repeat; +} + ul.toolbarmenu li label { display: block; color: #fff; diff --git a/skins/larry/templates/compose.html b/skins/larry/templates/compose.html index 20bead41c..0c1b81759 100644 --- a/skins/larry/templates/compose.html +++ b/skins/larry/templates/compose.html @@ -3,7 +3,9 @@ <head> <title><roundcube:object name="pagetitle" /></title> <roundcube:include file="/includes/links.html" /> +<roundcube:if condition="config:enable_spellcheck" /> <link rel="stylesheet" type="text/css" href="/googiespell.css" /> +<roundcube:endif /> </head> <body class="noscroll"> @@ -38,7 +40,12 @@ <!-- toolbar --> <div id="messagetoolbar" class="fullwidth"> <div id="mailtoolbar" class="toolbar"> - <roundcube:button command="spellcheck" type="link" class="button spellcheck disabled" classAct="button spellcheck" classSel="button spellcheck pressed" label="spellcheck" title="checkspelling" /> + <roundcube:if condition="config:enable_spellcheck" /> + <span class="dropbutton"> + <roundcube:button command="spellcheck" type="link" class="button spellcheck disabled" classAct="button spellcheck" classSel="button spellcheck pressed" label="spellcheck" title="checkspelling" /> + <span class="dropbuttontip" id="spellmenulink" onclick="UI.show_popup('spellmenu');return false"></span> + </span> + <roundcube:endif /> <roundcube:button name="addattachment" type="link" class="button attach" classAct="button attach" classSel="button attach pressed" label="attach" title="addattachment" onclick="UI.show_uploadform();return false" /> <roundcube:button command="insert-sig" type="link" class="button insertsig disabled" classAct="button insertsig" classSel="button insertsig pressed" label="signature" title="insertsignature" /> <roundcube:container name="toolbar" id="compose-toolbar" /> @@ -142,7 +149,6 @@ <!-- message compose body --> <div id="composeview-bottom"> <div id="composebodycontainer"> - <div id="spellcheck-control"></div> <roundcube:object name="composeBody" id="composebody" form="form" cols="70" rows="20" tabindex="9" /> </div> <div id="compose-attachments" class="rightcol"> @@ -171,6 +177,8 @@ </div> </div> +<div id="spellmenu" class="popupmenu"></div> + <roundcube:include file="/includes/footer.html" /> </body> diff --git a/skins/larry/ui.js b/skins/larry/ui.js index d6f945a6c..7f14c5ea9 100644 --- a/skins/larry/ui.js +++ b/skins/larry/ui.js @@ -24,6 +24,7 @@ function rcube_mail_ui() groupmenu: { above:1 }, mailboxmenu: { above:1 }, composeoptionsmenu: { editable:1, overlap:1 }, + spellmenu: { callback: spellmenu }, // toggle: #1486823, #1486930 'attachment-form': { editable:1, above:1, toggle:!bw.ie&&!bw.linux }, 'upload-form': { editable:1, toggle:!bw.ie&&!bw.linux } @@ -338,13 +339,13 @@ function rcube_mail_ui() bottom.css('height', (form.height() - bottom.position().top) + 'px'); - w = body.parent().width() - 6; - h = body.parent().height() - 36; + w = body.parent().width() - 5; + h = body.parent().height() - 16; body.width(w).height(h); if (window.tinyMCE && tinyMCE.get('composebody')) { - $('#composebody_tbl').width((w+10)+'px').height('').css('margin-top', '1px'); - $('#composebody_ifr').width((w+10)+'px').height((h-22)+'px'); + $('#composebody_tbl').width((w+8)+'px').height('').css('margin-top', '1px'); + $('#composebody_ifr').width((w+8)+'px').height((h-40)+'px'); } else { $('#googie_edit_layer').height(h+'px'); @@ -425,7 +426,7 @@ function rcube_mail_ui() $('select').css('visibility', show?'hidden':'inherit'); $('select', obj).css('visibility', 'inherit'); } - + return show; } @@ -554,6 +555,42 @@ function rcube_mail_ui() } + function spellmenu(show) + { + var link, li, + lang = rcmail.spellcheck_lang(), + menu = popups.spellmenu, + ul = $('ul', menu); + + if (!ul.length) { + ul = $('<ul class="toolbarmenu selectable">'); + + for (i in rcmail.env.spell_langs) { + li = $('<li>'); + link = $('<a href="#">').text(rcmail.env.spell_langs[i]) + .addClass('active').data('lang', i) + .click(function() { + rcmail.spellcheck_lang_set($(this).data('lang')); + }); + + link.appendTo(li); + li.appendTo(ul); + } + + ul.appendTo(menu); + } + + // select current language + $('li', ul).each(function() { + var el = $('a', this); + if (el.data('lang') == lang) + el.addClass('selected'); + else if (el.hasClass('selected')) + el.removeClass('selected'); + }); + } + + /** * */ |