From caedb70f6047930a3e941a6263b97db7e3e0eac6 Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Sat, 24 Oct 2009 17:55:33 -0600 Subject: [PATCH] Switch IMP to use the new CKEditor driver. --- imp/compose.php | 8 +++-- imp/config/prefs.php.dist | 13 +++---- imp/docs/CHANGES | 1 + imp/docs/UPGRADING | 7 ++-- imp/js/compose-dimp.js | 89 ++++++++++++++++++++++------------------------- imp/js/compose.js | 43 +++++++---------------- imp/lib/Application.php | 32 ----------------- imp/lib/Auth.php | 2 +- imp/lib/UI/Compose.php | 47 +++++++++++++++---------- imp/lib/Views/Compose.php | 2 +- 10 files changed, 101 insertions(+), 143 deletions(-) diff --git a/imp/compose.php b/imp/compose.php index 66824d5d1..b29a21f4f 100644 --- a/imp/compose.php +++ b/imp/compose.php @@ -1223,6 +1223,11 @@ if ($redirect) { $template_output = $t->fetch(IMP_TEMPLATES . '/compose/compose.html'); } +if ($rtemode && !$redirect) { + $imp_ui->initRTE(); + Horde::addInlineScript('CKEDITOR.replace("composeMessage", IMP.ckeditor_config)', 'load'); +} + if ($showmenu) { IMP::prepareMenu(); } @@ -1233,7 +1238,4 @@ if ($showmenu) { IMP::menu(); } echo $template_output; -if ($rtemode && !$redirect) { - echo $imp_ui->initRTE(); -} require $registry->get('templates', 'horde') . '/common-footer.inc'; diff --git a/imp/config/prefs.php.dist b/imp/config/prefs.php.dist index a36e21dad..ff0961962 100644 --- a/imp/config/prefs.php.dist +++ b/imp/config/prefs.php.dist @@ -68,7 +68,7 @@ $prefGroups['compose'] = array( 'members' => array('stationery_link', 'mailto_handler', 'compose_cc', 'compose_bcc', 'compose_spellcheck', 'compose_confirm', 'set_priority', 'compose_popup', 'compose_html', - 'fckeditor_buttons', 'mail_domain', + 'ckeditor_buttons', 'mail_domain', 'compose_cursor', 'sending_charset', 'encryptselect', 'save_attachments') ); @@ -624,12 +624,13 @@ $_prefs['compose_html'] = array( 'desc' => _("Compose messages with an HTML GUI by default (if browser supports the feature)?") ); -// The list of buttons to show in FCKeditor -// See http://www.fckeditor.net/ for details on configuration -$_prefs['fckeditor_buttons'] = array( - 'value' => "[['Source','FitWindow','-','Templates'],['Cut','Copy','Paste','PasteText','PasteWord'],['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],'/',['OrderedList','UnorderedList','-','Outdent','Indent','Blockquote'],['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],['Link','Unlink'],['Image','Flash','Table','Rule','Smiley','SpecialChar'],'/',['Bold','Italic','Underline','StrikeThrough','-','Subscript','Superscript'],['TextColor','BGColor'],'/',['Style','FontFormat','FontName','FontSize']]", +// The list of buttons to show in CKeditor +// See http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Toolbar for +// details on configuration +$_prefs['ckeditor_buttons'] = array( + 'value' => "[['Source','Maximize','-','Templates'],['Cut','Copy','Paste','PasteText','PasteFromWord'],['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],'/',['NumberedList','BulletedList','-','Outdent','Indent','Blockquote'],['JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock'],['Link','Unlink'],['Image','Flash','Table','HorizontalRule','Smiley','SpecialChar'],'/',['Bold','Italic','Underline','Strike','-','Subscript','Superscript'],['TextColor','BGColor'],'/',['Styles','Format','Font','FontSize']]", // Use the following line for a very basic set of buttons: - // 'value' => "['Bold','Italic','-','OrderedList','UnorderedList','-','Link','Unlink']", + // 'value' => "['Bold','Italic','-','NumberedList','BulletedList','-','Link','Unlink']", // Locked by default 'locked' => true, 'shared' => false, diff --git a/imp/docs/CHANGES b/imp/docs/CHANGES index 004b95b83..f4719a055 100644 --- a/imp/docs/CHANGES +++ b/imp/docs/CHANGES @@ -2,6 +2,7 @@ v5.0-git -------- +[mms] Upgrade RTE to CKEditor v3. [mms] Sort by display name for to/from fields if supported on IMAP server. [mms] Add ability to quickly filter by flags in DIMP. [mms] Add ability to select sent-mail mailbox when composing in DIMP. diff --git a/imp/docs/UPGRADING b/imp/docs/UPGRADING index 88c3e83bf..87435429e 100644 --- a/imp/docs/UPGRADING +++ b/imp/docs/UPGRADING @@ -18,8 +18,11 @@ This is a non-exhaustive, quick explanation of what has changed between an IMP HTML GUI editor --------------- -IMP only supports the FCKeditor javscript HTML GUI editor. Xinha is no longer -supported. +IMP only supports the CKeditor javascript HTML rich text editor. Xinha is no +longer supported. + +Button configuration is now stored in the prefs value 'ckeditor_buttons'. The +old 'fckeditor_buttons' setting is no longer used and can be safely removed. Server Options diff --git a/imp/js/compose-dimp.js b/imp/js/compose-dimp.js index dc6ad60c2..9a972dece 100644 --- a/imp/js/compose-dimp.js +++ b/imp/js/compose-dimp.js @@ -11,10 +11,9 @@ var DimpCompose = { // Variables defaulting to empty/false: // auto_save_interval, button_pressed, compose_cursor, dbtext, // drafts_mbox, editor_on, is_popup, knl, mp_padding, resizebcc, - // resizecc, resizeto, row_height, sbtext, skip_spellcheck, spellcheck, - // uploading + // resizecc, resizeto, row_height, rte, sbtext, skip_spellcheck, + // spellcheck, uploading last_msg: '', - textarea_ready: true, confirmCancel: function() { @@ -84,7 +83,7 @@ var DimpCompose = { // Finally try and replace the signature. if (this.editor_on) { - msg = FCKeditorAPI.GetInstance('composeMessage').GetHTML().replace(/\r\n/g, '\n'); + msg = this.rte.getData().replace(/\r\n/g, '\n'); lastSignature = '

'; nextSignature = '

' + next.sig.replace(/^ ?
\n/, '').replace(/ +/g, ' ') + '

'; @@ -112,7 +111,7 @@ var DimpCompose = { msg = msg.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n'); if (this.editor_on) { - FCKeditorAPI.GetInstance('composeMessage').SetHTML(msg); + this.rte.setData(msg); } else { msgval.setValue(msg); } @@ -161,10 +160,6 @@ var DimpCompose = { DIMP.SpellCheckerObject.isActive()) { DIMP.SpellCheckerObject.resume(); this.skip_spellcheck = true; - if (!this.textarea_ready) { - this.uniqueSubmit.bind(this, action).defer(); - return; - } } if (action == 'send_message' || action == 'save_draft') { @@ -220,7 +215,7 @@ var DimpCompose = { } else { // Move HTML text to textarea field for submission. if (this.editor_on) { - FCKeditorAPI.GetInstance('composeMessage').UpdateLinkedField(); + this.rte.updateElement(); } // Use an AJAX submit here so that we can do javascript-y stuff @@ -340,14 +335,14 @@ var DimpCompose = { DIMP.SpellCheckerObject.resume(); } - var text; + var config, text; if (this.editor_on) { this.editor_on = false; - text = FCKeditorAPI.GetInstance('composeMessage').GetHTML(); + text = this.rte.getData(); $('composeMessageParent').childElements().invoke('hide'); - $('composeMessage').show(); + $('composeMessage').show().setStyle({ visibility: null }).focus(); DimpCore.doAction('Html2Text', { text: text }, null, this.setMessageText.bind(this), { asynchronous: false }); } else { @@ -356,32 +351,39 @@ var DimpCompose = { DimpCore.doAction('Text2Html', { text: $F('composeMessage') }, null, this.setMessageText.bind(this), { asynchronous: false }); } - oFCKeditor.Height = this.getMsgAreaHeight(); // Try to reuse the old fckeditor instance. try { - FCKeditorAPI.GetInstance('composeMessage').SetHTML($F('composeMessage')); + this.rte.setData($F('composeMessage')); $('composeMessageParent').childElements().invoke('show'); $('composeMessage').hide(); } catch (e) { + config = Object.clone(IMP.ckeditor_config); + if (!config.on) { + config.on = {}; + } + config.on.instanceReady = function(evt) { + this.resizeMsgArea(); + this.RTELoading('hide'); + this.rte.focus(); + }.bind(this); this.RTELoading('show'); - FCKeditor_OnComplete = this.RTELoading.curry('hide'); - oFCKeditor.ReplaceTextarea(); + this.rte = CKEDITOR.replace('composeMessage', config); } } $('htmlcheckbox').checked = this.editor_on; $('html').setValue(this.editor_on ? 1 : 0); }, - RTELoading: function(cmd) - { - var o, r; - if (!$('rteloading')) { - r = new Element('DIV', { id: 'rteloading' }).clonePosition($('composeMessageParent')); - $(document.body).insert(r); - o = r.viewportOffset(); - $(document.body).insert(new Element('SPAN', { id: 'rteloadingtxt' }).setStyle({ top: (o.top + 15) + 'px', left: (o.left + 15) + 'px' }).insert(DIMP.text.loading)); - } - $('rteloading', 'rteloadingtxt').invoke(cmd); + RTELoading: function(cmd) + { + var o, r; + if (!$('rteloading')) { + r = new Element('DIV', { id: 'rteloading' }).clonePosition($('composeMessageParent')); + $(document.body).insert(r); + o = r.viewportOffset(); + $(document.body).insert(new Element('SPAN', { id: 'rteloadingtxt' }).setStyle({ top: (o.top + 15) + 'px', left: (o.left + 15) + 'px' }).insert(DIMP.text.loading)); + } + $('rteloading', 'rteloadingtxt').invoke(cmd); }, getMsgAreaHeight: function() @@ -411,18 +413,16 @@ var DimpCompose = { return; } DIMP.SpellCheckerObject.htmlAreaParent = 'composeMessageParent'; - DIMP.SpellCheckerObject.htmlArea = $('composeMessage').adjacent('iframe[id*=message]').first(); - $('composeMessage').setValue(FCKeditorAPI.GetInstance('composeMessage').GetHTML()); - this.textarea_ready = false; + this.rte.updateElement(); + $('composeMessage').next().hide(); }.bind(this); DIMP.SpellCheckerObject.onAfterSpellCheck = function() { if (!this.editor_on) { return; } - DIMP.SpellCheckerObject.htmlArea = DIMP.SpellCheckerObject.htmlAreaParent = null; - var ed = FCKeditorAPI.GetInstance('composeMessage'); - ed.SetHTML($F('composeMessage')); - ed.Events.AttachEvent('OnAfterSetHTML', function() { this.textarea_ready = true; }.bind(this)); + DIMP.SpellCheckerObject.htmlAreaParent = null; + this.rte.setData($F('composeMessage')); + $('composeMessage').next().show(); }.bind(this); }, @@ -449,7 +449,7 @@ var DimpCompose = { return; } - var bcc_add, fo, + var bcc_add, identity = this.get_identity($F('last_identity')), msgval = $('composeMessage'); @@ -464,7 +464,7 @@ var DimpCompose = { !this.auto_save_interval) { this.auto_save_interval = new PeriodicalExecuter(function() { var cur_msg = this.editor_on - ? FCKeditorAPI.GetInstance('composeMessage').GetHTML() + ? this.rte.getData() : $F(msgval); cur_msg = cur_msg.replace(/\r/g, ''); if (!cur_msg.empty() && this.last_msg != cur_msg) { @@ -475,9 +475,8 @@ var DimpCompose = { } if (this.editor_on) { - fo = FCKeditorAPI.GetInstance('composeMessage'); - fo.SetHTML(msg); - this.last_msg = fo.GetHTML().replace(/\r/g, ''); + this.rte.setData(msg); + this.last_msg = this.rte.getData().replace(/\r/g, ''); } else { msgval.setValue(msg); this.setCursorPosition(msgval); @@ -526,7 +525,7 @@ var DimpCompose = { focusEditor: function() { try { - FCKeditorAPI.GetInstance('composeMessage').Focus(); + this.rte.focus(); } catch (e) { this.focusEditor.bind(this).defer(); } @@ -571,12 +570,7 @@ var DimpCompose = { } if (this.editor_on) { - m = $('composeMessageParent').select('iframe').last(); - if (m) { - m.setStyle({ height: this.getMsgAreaHeight() + 'px' }); - } else { - this.resizeMsgArea.bind(this).defer(); - } + this.rte.resize('100%', this.getMsgAreaHeight(), false); return; } @@ -783,7 +777,7 @@ var DimpCompose = { onChoose: this.setSentMailLabel.bind(this) }); this.knl.setSelected(this.get_identity($F('identity'))[3]); - $('sent_mail_folder_label').insert({ after: new Element('SPAN', { className: 'popdownImg', id: 'compose_flist_popdown' }).observe('click', function(e) { this.knl.show(); e.stop(); }.bindAsEventListener(this)) }); + $('sent_mail_folder_label').insert({ after: new Element('SPAN', { className: 'popdownImg', id: 'compose_flist_popdown' }).observe('click', function(e) { this.knl.show(); this.knl.ignoreClick(e); e.stop(); }.bindAsEventListener(this)) }); } $('dimpLoading').hide(); @@ -795,7 +789,6 @@ var DimpCompose = { if (Prototype.Browser.WebKit) { $('submit_frame').writeAttribute({ position: 'absolute', width: '1px', height: '1px' }).setStyle({ left: '-999px' }).show(); } - } }, diff --git a/imp/js/compose.js b/imp/js/compose.js index 28ddccb74..c8a1339fc 100644 --- a/imp/js/compose.js +++ b/imp/js/compose.js @@ -6,11 +6,10 @@ */ var ImpCompose = { - /* Variables defined in compose.php: - * cancel_url, spellcheck, cursor_pos, identities, max_attachments, - * popup, redirect, reloaded, rtemode, smf_check, skip_spellcheck */ + // Variables defined in compose.php: + // cancel_url, spellcheck, cursor_pos, identities, max_attachments, + // popup, redirect, reloaded, rtemode, smf_check, skip_spellcheck display_unload_warning: true, - textarea_ready: true, confirmCancel: function(e) { @@ -62,14 +61,12 @@ var ImpCompose = { bcc = $('bcc'), save = $('ssm'), smf = $('sent_mail_folder'), - ed, lastSignature, msg, nextSignature, pos, re; + lastSignature, msg, nextSignature, pos, re; // If the rich text editor is on, we'll use a regexp to find the // signature comment and replace its contents. if (this.rtemode) { - ed = FCKeditorAPI.GetInstance('composeMessage'); - - msg = ed.GetHTML.replace(/\r\n/g, '\n'); + msg = CKEDITOR.instances.composeMessage.getData().replace(/\r\n/g, '\n'); lastSignature = '

'; nextSignature = '

' + next[0].replace(/^ ?
\n/, '').replace(/ +/g, ' ') + '

'; @@ -103,7 +100,7 @@ var ImpCompose = { } if (this.rtemode) { - ed.SetHTML(msg); + CKEDITOR.instances.composeMessage.setData(msg); } else { $('composeMessage').setValue(msg); } @@ -211,16 +208,7 @@ var ImpCompose = { } this.display_unload_warning = false; - this._uniqSubmit(form); - }, - - _uniqSubmit: function(form) - { - if (this.textarea_ready) { - form.submit(); - } else { - this._uniqSubmit.bind(this, form).defer(); - } + form.submit(); }, onNoSpellError: function(actionID, e) @@ -280,22 +268,15 @@ var ImpCompose = { _beforeSpellCheck: function() { IMP.SpellCheckerObject.htmlAreaParent = 'composeMessageParent'; - IMP.SpellCheckerObject.htmlArea = $('composeMessage').adjacent('iframe[id*=message]').first(); - $('composeMessage').setValue(FCKeditorAPI.GetInstance('composeMessage').GetHTML()); - this.textarea_ready = false; + $('composeMessage').next().hide(); + CKEDITOR.instances.composeMessage.updateElement(); }, _afterSpellCheck: function() { - IMP.SpellCheckerObject.htmlArea = IMP.SpellCheckerObject.htmlAreaParent = null; - var ed = FCKeditorAPI.GetInstance('composeMessage'); - ed.SetHTML($('composeMessage').value); - ed.Events.AttachEvent('OnAfterSetHTML', this._afterSetHTML.bind(this)); - }, - - _afterSetHTML: function() - { - this.textarea_ready = true; + IMP.SpellCheckerObject.htmlAreaParent = null; + CKEDITOR.instances.composeMessage.setData($F('composeMessage')); + $('composeMessage').next().show(); }, clickHandler: function(e) diff --git a/imp/lib/Application.php b/imp/lib/Application.php index 50dc7a4a8..b53f67341 100644 --- a/imp/lib/Application.php +++ b/imp/lib/Application.php @@ -892,38 +892,6 @@ class IMP_Application extends Horde_Registry_Application ); } - /* horde/services/cache.php methods. */ - - /** - * Application-specific cache output driver. - * - * @param array $params A list of params needed (USED: 'id'). - * - * @return array See Horde::getCacheUrl(). - * @throws Horde_Exception - */ - public function cacheOutput($params) - { - try { - $this->init(array('authentication' => 'throw')); - } catch (Horde_Exception $e) { - throw new Horde_Exception('No cache data available'); - } - - switch ($params['id']) { - case 'fckeditor': - return array( - 'data' => - 'FCKConfig.ToolbarSets["ImpToolbar"] = ' . $GLOBALS['prefs']->getValue('fckeditor_buttons') . ";\n" . - /* To more closely match "normal" textarea behavior, send - * send
on enter instead of

. */ - "FCKConfig.EnterMode = 'br';\n" . - 'FCKConfig.ShiftEnterMode = \'p\';', - 'type' => 'text/javascript' - ); - } - } - /* Language change callback. */ /** diff --git a/imp/lib/Auth.php b/imp/lib/Auth.php index 7a07fed55..d3dd584be 100644 --- a/imp/lib/Auth.php +++ b/imp/lib/Auth.php @@ -457,7 +457,7 @@ class IMP_Auth /* Is the HTML editor available? */ $imp_ui = new IMP_UI_Compose(); - $editor = $imp_ui->initRTE(null, true); + $editor = Horde_Editor::singleton('Ckeditor', array('no_notify' => true)); $sess['rteavail'] = $editor->supportedByBrowser(); /* Set view in session/cookie. */ diff --git a/imp/lib/UI/Compose.php b/imp/lib/UI/Compose.php index 49bbb19ea..885ebbbff 100644 --- a/imp/lib/UI/Compose.php +++ b/imp/lib/UI/Compose.php @@ -169,30 +169,39 @@ class IMP_UI_Compose } /** + * Initialize the Rich Text Editor (RTE). + * + * @param boolean $mini Load the basic ckeditor stub? */ - public function initRTE($mode = 'imp', $editoronly = false) + public function initRTE($basic = false) { - $editor = Horde_Editor::singleton('Fckeditor', array('id' => 'composeMessage', 'no_notify' => true)); - if ($editoronly) { - return $editor; - } + $editor = Horde_Editor::singleton('Ckeditor', array('basic' => $basic)); - $fck_buttons = $GLOBALS['prefs']->getValue('fckeditor_buttons'); - if (!empty($fck_buttons)) { - $js_onload = array( - // This needs to work even if Horde_Cache is not available, - // so need to use app-specific cache output. - 'oFCKeditor.Config.CustomConfigurationsPath = "' . Horde::getCacheUrl('app', array('app' => 'imp', 'id' => 'fckeditor')) . '"', - 'oFCKeditor.ToolbarSet = "ImpToolbar"' - ); - if ($mode == 'imp') { - $js_onload[] = 'oFCKeditor.Height = $(\'composeMessage\').getHeight()'; - $js_onload[] = 'oFCKeditor.ReplaceTextarea()'; - } - Horde::addInlineScript($js_onload, 'load'); + $config = array( + /* To more closely match "normal" textarea behavior, send
on + * enter instead of

. */ + 'enterMode: CKEDITOR.ENTER_BR', + 'shiftEnterMode: CKEDITOR.ENTER_P', + + /* Don't load the config.js file. */ + 'customConfig: ""', + + /* Disable resize of the textarea. */ + 'resize_enabled: false', + + /* Use the old skin for now. */ + 'skin: "v2"' + ); + + $buttons = $GLOBALS['prefs']->getValue('ckeditor_buttons'); + if (!empty($buttons)) { + $config[] = 'toolbar: ' . $GLOBALS['prefs']->getValue('ckeditor_buttons'); } - return $editor->getJS(); + Horde::addInlineScript(array( + 'if (!window.IMP) { window.IMP = {}; }', + 'IMP.ckeditor_config = {' . implode(',', $config) . '}' + )); } } diff --git a/imp/lib/Views/Compose.php b/imp/lib/Views/Compose.php index 35e2b0eaa..478a3ea46 100644 --- a/imp/lib/Views/Compose.php +++ b/imp/lib/Views/Compose.php @@ -88,7 +88,7 @@ class IMP_Views_Compose $rte = true; $imp_ui = new IMP_UI_Compose(); - $result['jsappend'] .= $imp_ui->initRTE('dimp'); + $imp_ui->initRTE(!$compose_html); } /* Create list for sent-mail selection. */ -- 2.11.0