$imp_ui->attachAutoCompleter(array('to', 'cc', 'bcc', 'redirect_to'));
$imp_ui->attachSpellChecker();
- $sig = $identity->getSignature();
+ $sig = $identity->getSignature($show_editor ? 'html' : 'text');
if ($get_sig && !empty($sig)) {
- if ($show_editor) {
- $sig = '<p><!--begin_signature-->' . $imp_compose->text2html(trim($sig)) . '<!--end_signature--></p>';
+ if ($identity->getValue('sig_first')) {
+ $msg = $sig . $msg;
+ } else {
+ $msg .= $sig;
}
-
- $msg = ($identity->getValue('sig_first'))
- ? "\n" . $sig . $msg
- : $msg . "\n" . $sig;
}
if ($show_editor) {
$msg = "\n" . $msg;
}
-/* Get the current signature. */
-$sig = $identity->getSignature();
-
/* Convert from Text -> HTML or vice versa if RTE mode changed. */
if (!is_null($oldrtemode) && ($oldrtemode != $rtemode)) {
- if ($rtemode) {
- /* Try to find the signature, replace it with a placeholder,
- * HTML-ize the message, then replace the signature
- * placeholder with the HTML-ized signature, complete with
- * marker comment. */
- $msg = preg_replace('/' . preg_replace('/(?<!^)\s+/', '\\s+', preg_quote($sig, '/')) . '/', '##IMP_SIGNATURE##', $msg, 1);
- $msg = preg_replace('/\s+##IMP_SIGNATURE##/', '##IMP_SIGNATURE_WS####IMP_SIGNATURE##', $msg);
- $msg = $imp_compose->text2html($msg);
- $msg = str_replace(array('##IMP_SIGNATURE_WS##', '##IMP_SIGNATURE##'),
- array('<p> </p>', '<p><!--begin_signature-->' . $imp_compose->text2html($sig) . '<!--end_signature--></p>'),
- $msg);
- } else {
- $msg = Horde_Text_Filter::filter($msg, 'Html2text', array('charset' => Horde_Nls::getCharset(), 'wrap' => false));
+ $msg = $imp_ui->convertComposeText($msg, $rtemode ? 'html' : 'text', $identity->getDefault());
+} elseif ($get_sig) {
+ $sig = $identity->getSignature($rtemode ? 'html' : 'text');
+ if (!empty($sig)) {
+ if ($identity->getValue('sig_first')) {
+ $msg = $sig . $msg;
+ } else {
+ $msg .= "\n" . $sig;
+ }
}
}
}
}
-if ($get_sig && isset($msg) && !empty($sig)) {
- if ($rtemode) {
- $sig = '<p> </p><p><!--begin_signature-->' . $imp_compose->text2html(trim($sig)) . '<!--end_signature--></p>';
- }
-
- if ($identity->getValue('sig_first')) {
- $msg = "\n" . $sig . $msg;
- } else {
- $msg .= "\n" . $sig;
- }
-}
-
/* If PGP encryption is set by default, and we have a recipient list on first
* load, make sure we have public keys for all recipients. */
$encrypt_options = $prefs->isLocked('default_encrypt')
'desc' => _("Change the name, address, and signature that people see when they read and reply to your email."),
'members' => array(
'replyto_addr', 'alias_addr', 'tieto_addr', 'bcc_addr', 'signature',
- 'sig_dashes', 'sig_first', 'save_sent_mail', 'sent_mail_folder',
- 'sentmailselect'
+ 'signature_html_select', 'sig_dashes', 'sig_first', 'save_sent_mail',
+ 'sent_mail_folder', 'sentmailselect'
),
'type' => 'identities'
);
'desc' => _("Your signature:")
);
+// User's HTML signature - UI widget
+$_prefs['signature_html_select'] = array(
+ 'type' => 'special'
+);
+
+// User's HTML signature
+$_prefs['signature_html'] = array(
+ 'value' => ''
+);
+
// precede the signature with dashes ('-- ')?
$_prefs['sig_dashes'] = array(
'value' => 0,
v5.0-git
--------
+[mms] Added HTML signature support (Request #1406).
[mms] Simplified date sorting display (Ticket #8936).
[mms] Properly redirect messages pursuant to RFC 5322 [3.6.6].
[mms] Add redirect message capability to DIMP.
replaceSignature: function(id)
{
- var lastsig, msg, nextsig, oldmsg, pos,
- last = this.getIdentity($F('last_identity')),
+ var lastsig, msg, nextsig, pos, tmp, tmp2,
next = this.getIdentity(id);
// If the rich text editor is on, we'll use a regexp to find the
// signature comment and replace its contents.
if (this.editor_on) {
- msg = oldmsg = CKEDITOR.instances['composeMessage'].getData().replace(/\r\n/g, '\n');
-
- lastsig = '<p><!--begin_signature--><!--end_signature--></p>';
- nextsig = '<p><!--begin_signature-->' + next.sig.replace(/^ ?<br \/>\n/, '').replace(/ +/g, ' ') + '<!--end_signature--></p>';
-
- // Dot-all functionality achieved with [\s\S], see:
- // http://simonwillison.net/2004/Sep/20/newlines/
- msg = msg.replace(/<p>\s*<!--begin_signature-->[\s\S]*?<!--end_signature-->\s*<\/p>/, lastsig);
- if (msg == oldmsg) {
- msg = nextsig;
+ // Create a temporary element, import the data from the editor,
+ // search/replace the current imp signature data, and reinsert
+ // into the editor.
+ tmp = new Element('DIV').hide();
+ $(document.body).insert(tmp);
+ tmp.update(CKEDITOR.instances['composeMessage'].getData());
+ tmp2 = tmp.select('DIV.impComposeSignature');
+ if (tmp2.size()) {
+ msg = tmp2.last().update(next.sig);
+ } else {
+ msg = next.id.sig_loc
+ ? tmp.insert({ top: next.sig })
+ : tmp.insert({ bottom: next.sig });
}
+ CKEDITOR.instances['composeMessage'].setData(msg.innerHTML);
+ tmp.remove();
} else {
msg = $F('composeMessage').replace(/\r\n/g, '\n');
-
+ last = this.getIdentity($F('last_identity'));
lastsig = last.sig.replace(/^\n/, '');
nextsig = next.sig.replace(/^\n/, '');
- }
-
- pos = (last.id.sig_loc)
- ? msg.indexOf(lastsig)
- : msg.lastIndexOf(lastsig);
- if (pos != -1) {
- if (next.id.sig_loc == last.id.sig_loc) {
- msg = msg.substring(0, pos) + nextsig + msg.substring(pos + lastsig.length, msg.length);
- } else if (next.id.sig_loc) {
- msg = nextsig + msg.substring(0, pos) + msg.substring(pos + lastsig.length, msg.length);
- } else {
- msg = msg.substring(0, pos) + msg.substring(pos + lastsig.length, msg.length) + nextsig;
- }
+ pos = last.id.sig_loc
+ ? msg.indexOf(lastsig)
+ : msg.lastIndexOf(lastsig);
- msg = msg.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n');
- }
+ if (pos != -1) {
+ if (next.id.sig_loc == last.id.sig_loc) {
+ msg = msg.substring(0, pos) + nextsig + msg.substring(pos + lastsig.length, msg.length);
+ } else if (next.id.sig_loc) {
+ msg = nextsig + msg.substring(0, pos) + msg.substring(pos + lastsig.length, msg.length);
+ } else {
+ msg = msg.substring(0, pos) + msg.substring(pos + lastsig.length, msg.length) + nextsig;
+ }
- if (this.editor_on) {
- CKEDITOR.instances['composeMessage'].setData(msg);
- } else {
- $('composeMessage').setValue(msg);
+ $('composeMessage').setValue(msg.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n'));
+ }
}
$('last_identity').setValue(id);
this.rte.destroy();
this.RTELoading('show');
- DimpCore.doAction('html2Text', { text: text }, { callback: this.setMessageText.bind(this), ajaxopts: { asynchronous: false } });
+ DimpCore.doAction('html2Text', { identity: $F('identity'), text: text }, { callback: this.setMessageText.bind(this), ajaxopts: { asynchronous: false } });
this.RTELoading('hide');
} else {
if (!noupdate) {
- DimpCore.doAction('text2Html', { text: $F('composeMessage') }, { callback: this.setMessageText.bind(this), ajaxopts: { asynchronous: false } });
+ DimpCore.doAction('text2Html', { identity: $F('identity'), text: $F('composeMessage') }, { callback: this.setMessageText.bind(this), ajaxopts: { asynchronous: false } });
}
config = Object.clone(IMP.ckeditor_config);
--- /dev/null
+/**
+ * Provides the javascript for managing HTML signature in the preferences UI.
+ *
+ * See the enclosed file COPYING for license information (GPL). If you
+ * did not receive this file, see http://www.fsf.org/copyleft/gpl.html.
+ */
+
+var ImpHtmlSignaturePrefs = {
+
+ // Variables defined by other code: ready, sigs
+
+ changeIdentity: function(e)
+ {
+ switch (e.memo.pref) {
+ case 'signature_html_select':
+ if (this.ready) {
+ CKEDITOR.instances['signature_html'].setData(this.sigs[e.memo.i]);
+ } else {
+ this.changeIdentity.bind(this, e).defer();
+ }
+ break;
+ }
+ }
+
+};
+
+CKEDITOR.on('instanceReady', function(e) { ImpHtmlSignaturePrefs.ready = true; });
+document.observe('HordeIdentitySelect:change', ImpHtmlSignaturePrefs.changeIdentity.bindAsEventListener(ImpHtmlSignaturePrefs));
}
/**
- * AJAX action: Convert HTML to text.
+ * AJAX action: Convert HTML to text (compose data).
*
* Variables used:
* <pre>
+ * 'identity' - (integer) The current identity.
* 'text' - (string) The text to convert.
* </pre>
*
public function html2Text()
{
$result = new stdClass;
- // Need to replace line endings or else IE won't display line endings
- // properly.
- $result->text = str_replace("\n", "\r\n", Horde_Text_Filter::filter($this->_vars->text, 'Html2text', array('charset' => Horde_Nls::getCharset())));
+ $result->text = $GLOBALS['injector']->getInstance('IMP_Ui_Compose')->convertComposeText($this->_vars->text, 'text', intval($this->_vars->identity));
return $result;
}
/**
- * AJAX action: Convert text to HTML.
+ * AJAX action: Convert text to HTML (compose data).
*
* Variables used:
* <pre>
+ * 'identity' - (integer) The current identity.
* 'text' - (string) The text to convert.
* </pre>
*
public function text2Html()
{
$result = new stdClass;
- $result->text = Horde_Text_Filter::filter($this->_vars->text, 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO_LINKURL));
+ $result->text = $GLOBALS['injector']->getInstance('IMP_Ui_Compose')->convertComposeText($this->_vars->text, 'html', intval($this->_vars->identity));
return $result;
}
*
* @return string HTML text.
*/
- public function text2html($msg)
+ static public function text2html($msg)
{
return Horde_Text_Filter::filter($msg, 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO_LINKURL, 'class' => null, 'callback' => null));
}
'froms' => array(),
'names' => array(),
// 'own_addresses'
+ 'signatures' => array()
// 'tie_addresses'
);
/**
- * Cached signature list.
- *
- * @var array
- */
- protected $_signatures = array();
-
- /**
* Reads all the user's identities from the prefs object or builds
* a new identity from the standard values given in prefs.php.
*/
public function __construct()
{
parent::__construct();
+
$this->_properties = array_merge(
$this->_properties,
- array('replyto_addr', 'alias_addr', 'tieto_addr', 'bcc_addr',
- 'signature', 'sig_first', 'sig_dashes', 'save_sent_mail',
- 'sent_mail_folder')
+ array(
+ 'replyto_addr', 'alias_addr', 'tieto_addr', 'bcc_addr',
+ 'signature', 'signature_html', 'sig_first', 'sig_dashes',
+ 'save_sent_mail', 'sent_mail_folder'
+ )
);
}
*/
public function getFullname($ident = null)
{
- if (isset($this->_names[$ident])) {
- return $this->_names[$ident];
+ if (isset($this->_cached['names'][$ident])) {
+ return $this->_cached['names'][$ident];
}
- $this->_names[$ident] = $this->getValue('fullname', $ident);
+ $this->_cached['names'][$ident] = $this->getValue('fullname', $ident);
- return $this->_names[$ident];
+ return $this->_cached['names'][$ident];
}
/**
* Returns the full signature based on the current settings for the
* signature itself, the dashes and the position.
*
+ * @param string $type Either 'text' or 'html'.
* @param integer $ident The identity to retrieve the signature from.
*
* @return string The full signature.
* @throws Horde_Exception
*/
- public function getSignature($ident = null)
+ public function getSignature($type = 'text', $ident = null)
{
- if (isset($this->_signatures[$ident])) {
- return $this->_signatures[$ident];
+ $convert = false;
+ $key = $ident . '|' . $type;
+ $val = null;
+
+ if (isset($this->_cached['signatures'][$key])) {
+ return $this->_cached['signatures'][$key];
}
- $val = $this->getValue('signature', $ident);
- if (!empty($val)) {
- $sig_first = $this->getValue('sig_first', $ident);
- $sig_dashes = $this->getValue('sig_dashes', $ident);
- $val = str_replace("\r\n", "\n", $val);
- if ($sig_dashes) {
- $val = "-- \n$val";
+ if ($type == 'html') {
+ $val = $this->getValue('signature_html', $ident);
+ if (!strlen($val)) {
+ $convert = true;
+ $val = null;
}
- if (isset($sig_first) && $sig_first) {
- $val = "\n" . $val . "\n\n\n";
- } else {
- $val = "\n" . $val;
+ }
+
+ if (is_null($val)) {
+ $val = $this->getValue('signature', $ident);
+
+ if (!empty($val) && ($type == 'text')) {
+ $sig_first = $this->getValue('sig_first', $ident);
+ $sig_dashes = $this->getValue('sig_dashes', $ident);
+
+ $val = str_replace("\r\n", "\n", $val);
+
+ if ($sig_dashes) {
+ $val = "-- \n" . $val . "\n";
+ } else {
+ $val = "\n" . $val;
+ }
+
+ if ($sig_first) {
+ $val .= "\n\n\n";
+ }
+ }
+ }
+
+ if ($val && ($type == 'html')) {
+ if ($convert) {
+ $val = IMP_Compose::text2html(trim($val));
}
+
+ $val = '<div class="impComposeSignature">' . $val . '</div>';
}
try {
$val = Horde::callHook('prefs_hook_signature', array($val), 'imp');
} catch (Horde_Exception_HookNotSet $e) {}
- $this->_signatures[$ident] = $val;
+ $this->_cached['signatures'][$key] = $val;
return $val;
}
/**
* Returns an array with the signatures from all identities
*
+ * @param string $type Either 'text' or 'html'.
+ *
* @return array The array with all the signatures.
*/
- public function getAllSignatures()
+ public function getAllSignatures($type = 'text')
{
- static $list;
-
- if (isset($list)) {
- return $list;
- }
-
foreach ($this->_identities as $key => $identity) {
- $list[$key] = $this->getSignature($key);
+ $list[$key] = $this->getSignature($type, $key);
}
return $list;
} else {
Horde::addScriptFile('folderprefs.js', 'imp');
}
+
+ if ($prefs->isLocked('signature_html') ||
+ empty($_SESSION['imp']['rteavail'])) {
+ $ui->suppress[] = 'signature_html_select';
+ } else {
+ Horde::addScriptFile('signaturehtml.js', 'imp');
+ $GLOBALS['injector']->getInstance('Horde_Editor')->getEditor('Ckeditor', array('id' => 'signature_html'));
+ }
break;
case 'logintasks':
case 'smimepublickey':
return $this->_smimePublicKey($ui);
+ case 'signature_html_select':
+ return $this->_signatureHtml();
+
case 'soundselect':
return $this->_sound();
$this->_updateSmimePublicKey($ui);
return false;
+ case 'signature_html_select':
+ return Horde_Prefs_Identity::singleton(array('imp', 'imp'))->setValue('signature_html', $ui->vars->signature_html);
+
case 'soundselect':
return $prefs->setValue('nav_audio', $ui->vars->nav_audio);
}
}
+ /* HTML Signature editing. */
+
+ /**
+ * Create code for HTML Signature editing.
+ *
+ * @return string HTML UI code.
+ */
+ protected function _signatureHtml()
+ {
+ $identity = Horde_Prefs_Identity::singleton(array('imp', 'imp'));
+
+ $js = array();
+ foreach (array_keys($identity->getAll('id')) as $key) {
+ $js[$key] = $identity->getValue('signature_html', $key);
+ };
+
+ Horde::addInlineScript(array(
+ 'ImpHtmlSignaturePrefs.sigs = ' . Horde_Serialize::serialize($js, Horde_Serialize::JSON, Horde_Nls::getCharset())
+ ));
+
+ $t = $GLOBALS['injector']->createInstance('Horde_Template');
+ $t->setOption('gettext', true);
+
+ return $t->fetch(IMP_TEMPLATES . '/prefs/signaturehtml.html');
+ }
+
/* Sound selection. */
/**
$identities = array();
$identity = Horde_Prefs_Identity::singleton(array('imp', 'imp'));
+ $html_sigs = $identity->getAllSignatures('html');
+
foreach ($identity->getAllSignatures() as $ident => $sig) {
$identities[] = array(
// Plain text signature
'sig' => $sig,
// HTML signature
- 'sig_html' => str_replace(' target="_blank"', '', Horde_Text_Filter::filter($sig, 'text2html', array('parselevel' => Horde_Text_Filter_Text2html::MICRO_LINKURL, 'class' => null, 'callback' => null))),
+ 'sig_html' => $html_sigs[$ident],
// Signature location
'sig_loc' => (bool)$identity->getValue('sig_first', $ident),
// Sent mail folder name
return 'IMP_Compose_Base.identities = ' . Horde_Serialize::serialize($identities, Horde_Serialize::JSON);
}
+ /**
+ * Convert compose data to/from text/HTML.
+ *
+ * @param string $data The message text.
+ * @param string $to Either 'text' or 'html'.
+ * @param integer $identity The current identity.
+ *
+ * @return string The converted text
+ */
+ public function convertComposeText($data, $to, $identity)
+ {
+ $imp_identity = Horde_Prefs_Identity::singleton(array('imp', 'imp'));
+ $replaced = 0;
+
+ $html_sig = $imp_identity->getSignature('html', $identity);
+ $txt_sig = $imp_identity->getSignature('text', $identity);
+
+ /* Try to find the signature, replace it with a placeholder, convert
+ * the message, and then re-add the signature in the new format. */
+ switch ($to) {
+ case 'html':
+ if ($txt_sig) {
+ $data = preg_replace('/' . preg_replace('/(?<!^)\s+/', '\\s+', preg_quote($txt_sig, '/')) . '/', '###IMP_SIGNATURE###', $data, 1, $replaced);
+ }
+ $data = IMP_Compose::text2html($data);
+ $sig = $html_sig;
+ break;
+
+ case 'text':
+ if ($html_sig) {
+ /* Silence errors from parsing HTML. */
+ $old_error = libxml_use_internal_errors(true);
+ $doc = DOMDocument::loadHTML($data);
+ if (!$old_error) {
+ libxml_use_internal_errors(false);
+ }
+
+ $xpath = new DOMXPath($doc);
+ $entries = $xpath->query("//div[@class='impComposeSignature']");
+ $node = $entries->item(0);
+ $node->parentNode->replaceChild($doc->createTextNode('###IMP_SIGNATURE###'), $node);
+ $replaced = 1;
+
+ $data = '';
+ foreach ($doc->getElementsByTagName('body')->item(0)->childNodes as $node) {
+ $data .= $doc->saveXML($node);
+ }
+ }
+
+ $data = Horde_Text_Filter::filter($data, 'Html2text', array('charset' => Horde_Nls::getCharset(), 'wrap' => false));
+ $sig = $txt_sig;
+ break;
+ }
+
+ if ($replaced) {
+ return str_replace('###IMP_SIGNATURE###', $sig, $data);
+ } elseif ($imp_identity->getValue('sig_first', $identity)) {
+ return $sig . $data;
+ } else {
+ return $msg . "\n" . $sig;
+ }
+ }
}
--- /dev/null
+<div>
+ <gettext>Your signature to use when composing with the HTML editor (if empty, the text signature will be used):</gettext>
+</div>
+
+<div class="fixed">
+ <textarea id="signature_html" name="signature_html" rows="4" cols="80" class="fixed"></textarea>
+</div>