$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();
}
IMP::menu();
}
echo $template_output;
-if ($rtemode && !$redirect) {
- echo $imp_ui->initRTE();
-}
require $registry->get('templates', 'horde') . '/common-footer.inc';
'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')
);
'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,
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.
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
// 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()
{
// 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 = '<p><!--begin_signature--><!--end_signature--></p>';
nextSignature = '<p><!--begin_signature-->' + next.sig.replace(/^ ?<br \/>\n/, '').replace(/ +/g, ' ') + '<!--end_signature--></p>';
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);
}
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') {
} 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
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 {
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()
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);
},
return;
}
- var bcc_add, fo,
+ var bcc_add,
identity = this.get_identity($F('last_identity')),
msgval = $('composeMessage');
!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) {
}
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);
focusEditor: function()
{
try {
- FCKeditorAPI.GetInstance('composeMessage').Focus();
+ this.rte.focus();
} catch (e) {
this.focusEditor.bind(this).defer();
}
}
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;
}
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();
if (Prototype.Browser.WebKit) {
$('submit_frame').writeAttribute({ position: 'absolute', width: '1px', height: '1px' }).setStyle({ left: '-999px' }).show();
}
-
}
},
*/
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)
{
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 = '<p><!--begin_signature--><!--end_signature--></p>';
nextSignature = '<p><!--begin_signature-->' + next[0].replace(/^ ?<br \/>\n/, '').replace(/ +/g, ' ') + '<!--end_signature--></p>';
}
if (this.rtemode) {
- ed.SetHTML(msg);
+ CKEDITOR.instances.composeMessage.setData(msg);
} else {
$('composeMessage').setValue(msg);
}
}
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)
_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)
);
}
- /* 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 <BR> on enter instead of <P>. */
- "FCKConfig.EnterMode = 'br';\n" .
- 'FCKConfig.ShiftEnterMode = \'p\';',
- 'type' => 'text/javascript'
- );
- }
- }
-
/* Language change callback. */
/**
/* 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. */
}
/**
+ * 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 <BR> on
+ * enter instead of <P>. */
+ '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) . '}'
+ ));
}
}
$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. */