From: Michael M Slusarz Date: Thu, 2 Sep 2010 20:35:27 +0000 (-0600) Subject: Use alternate text part to generate reply/forward text when switching compose modes... X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=7ce7ed91b17089d0468c00ae9f743b58516d9bef;p=horde.git Use alternate text part to generate reply/forward text when switching compose modes if user has not altered message text (DIMP) This does a much better job of trying to conserve format (especially from HTML -> Text) since the alternative display part should (theoretically) be a better representation of the original data than message text created via our Text -> HTML or HTML -> Text conversion. --- diff --git a/imp/docs/CHANGES b/imp/docs/CHANGES index e6a7984c4..8bb6244a5 100644 --- a/imp/docs/CHANGES +++ b/imp/docs/CHANGES @@ -2,6 +2,8 @@ v5.0-git -------- +[mms] Use alternate text part to generate reply/forward text when switching + compose modes if user has not altered message text (DIMP). [mms] Improved login error reporting/logging in IMP (Request #9211). [mms] Add hook to skip MDN prompt based on content of message headers. [mms] Allow expand/collapse of folders in MIMP. diff --git a/imp/js/compose-dimp.js b/imp/js/compose-dimp.js index e8f05b223..515b068fd 100644 --- a/imp/js/compose-dimp.js +++ b/imp/js/compose-dimp.js @@ -10,8 +10,9 @@ var DimpCompose = { // Variables defaulting to empty/false: // auto_save_interval, compose_cursor, disabled, drafts_mbox, - // editor_wait, is_popup, knl, last_msg, old_action, old_identity, - // resizing, rte, skip_spellcheck, spellcheck, sc_submit, uploading + // editor_wait, is_popup, knl, md5_hdrs, md5_msg, md5_msgOrig, + // old_action, old_identity, resizing, rte, rte_loaded, skip_spellcheck, + // spellcheck, sc_submit, uploading knl: {}, @@ -52,7 +53,7 @@ var DimpCompose = { closeQReply: function() { var al = $('attach_list').childElements(); - this.last_msg = ''; + this.md5_hdrs = this.md5_msg = this.md5_msgOrig = ''; if (al.size()) { this.removeAttach(al); @@ -364,18 +365,36 @@ var DimpCompose = { DIMP.SpellChecker.resume(); } - var config, text; + var changed, config, text; if (IMP_Compose_Base.editor_on) { + changed = (this.msgHash() != this.md5_msgOrig); text = this.rte.getData(); this.rte.destroy(); + this.rte_loaded = false; this.RTELoading('show'); - DimpCore.doAction('html2Text', { identity: $F('identity'), text: text }, { callback: this.setMessageText.bind(this), ajaxopts: { asynchronous: false } }); + DimpCore.doAction('html2Text', { + changed: Number(changed), + identity: $F('identity'), + imp_compose: $F('composeCache'), + text: text + }, { + ajaxopts: { asynchronous: false }, + callback: this.setMessageText.bind(this) + }); this.RTELoading('hide'); } else { if (!noupdate) { - DimpCore.doAction('text2Html', { identity: $F('identity'), text: $F('composeMessage') }, { callback: this.setMessageText.bind(this), ajaxopts: { asynchronous: false } }); + DimpCore.doAction('text2Html', { + changed: Number(this.msgHash() != this.md5_msgOrig), + identity: $F('identity'), + imp_compose: $F('composeCache'), + text: $F('composeMessage') + }, { + ajaxopts: { asynchronous: false }, + callback: this.setMessageText.bind(this) + }); } config = Object.clone(IMP.ckeditor_config); @@ -386,6 +405,7 @@ var DimpCompose = { this.resizeMsgArea(); this.RTELoading('hide'); this.rte.focus(); + this.rte_loaded = true; }.bind(this); this.RTELoading('show'); this.rte = CKEDITOR.replace('composeMessage', config); @@ -477,22 +497,6 @@ var DimpCompose = { identity = IMP_Compose_Base.getIdentity($F('last_identity')); opts = opts || {}; - // Set auto-save-drafts now if not already active. - if (DIMP.conf_compose.auto_save_interval_val && - !this.auto_save_interval) { - this.auto_save_interval = new PeriodicalExecuter(function() { - if ($('compose').visible()) { - var curr_hash = MD5.hash($('to', 'cc', 'bcc', 'subject').invoke('getValue').join('\0') + (IMP_Compose_Base.editor_on ? this.rte.getData() : $F('composeMessage'))); - if (this.last_msg && curr_hash != this.last_msg) { - this.uniqueSubmit('autoSaveDraft'); - } - this.last_msg = curr_hash; - } - }.bind(this), DIMP.conf_compose.auto_save_interval_val * 60); - /* Immediately execute to get MD5 hash of empty message. */ - this.auto_save_interval.execute(); - } - $('to').setValue(header.to); if (header.cc) { $('cc').setValue(header.cc); @@ -551,6 +555,48 @@ var DimpCompose = { this.focusEditor(); } } + + this.fillFormHash(); + }, + + fillFormHash: function() + { + if (IMP_Compose_Base.editor_on && !this.rte_loaded) { + this.fillFormHash.bind(this).defer(); + return; + } + + // This value is used to determine if the text has changed when + // swapping compose modes. + this.md5_msgOrig = this.msgHash(); + + // Set auto-save-drafts now if not already active. + if (DIMP.conf_compose.auto_save_interval_val && + !this.auto_save_interval) { + this.auto_save_interval = new PeriodicalExecuter(function() { + if ($('compose').visible()) { + var hdrs = MD5.hash($('to', 'cc', 'bcc', 'subject').invoke('getValue').join('\0')), msg; + if (this.md5_hdrs) { + msg = this.msgHash(); + if (this.md5_hdrs != hdrs || this.md5_msg != msg) { + this.uniqueSubmit('autoSaveDraft'); + } + } else { + msg = this.md5_msgOrig; + } + this.md5_hdrs = hdrs; + this.md5_msg = msg; + } + }.bind(this), DIMP.conf_compose.auto_save_interval_val * 60); + + /* Immediately execute to get MD5 hash of headers. */ + this.auto_save_interval.execute(); + } + }, + + msgHash: function() + { + return MD5.hash(IMP_Compose_Base.editor_on ? this.rte.getData() : $F('composeMessage')); }, fadeNotice: function(elt) diff --git a/imp/lib/Ajax/Application.php b/imp/lib/Ajax/Application.php index a5d956d81..ef8576aa6 100644 --- a/imp/lib/Ajax/Application.php +++ b/imp/lib/Ajax/Application.php @@ -941,7 +941,9 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application * * Variables used: *
+     * 'changed' - (integer) Has the text changed from the original?
      * 'identity' - (integer) The current identity.
+     * 'imp_compose' - (string) The IMP_Compose cache identifier.
      * 'text' - (string) The text to convert.
      * 
* @@ -953,6 +955,34 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application public function html2Text() { $result = new stdClass; + + if (!$this->_vars->changed) { + list($imp_compose, $imp_contents) = $this->_initCompose(); + + switch ($imp_compose->getMetadata('reply_type')) { + case 'forward': + switch ($imp_compose->getMetadata('forward_type')) { + case 'forward_body': + case 'forward_both': + $data = $imp_compose->forwardMessageText($imp_contents, array( + 'format' => 'text' + )); + $result->text = $data['body']; + return $result; + } + break; + + case 'reply': + case 'reply_all': + case 'reply_list': + $data = $imp_compose->replyMessageText($imp_contents, array( + 'format' => 'text' + )); + $result->text = $data['body']; + return $result; + } + } + $result->text = $GLOBALS['injector']->getInstance('IMP_Ui_Compose')->convertComposeText($this->_vars->text, 'text', intval($this->_vars->identity)); return $result; @@ -963,7 +993,9 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application * * Variables used: *
+     * 'changed' - (integer) Has the text changed from the original?
      * 'identity' - (integer) The current identity.
+     * 'imp_compose' - (string) The IMP_Compose cache identifier.
      * 'text' - (string) The text to convert.
      * 
* @@ -975,6 +1007,34 @@ class IMP_Ajax_Application extends Horde_Core_Ajax_Application public function text2Html() { $result = new stdClass; + + if (!$this->_vars->changed) { + list($imp_compose, $imp_contents) = $this->_initCompose(); + + switch ($imp_compose->getMetadata('reply_type')) { + case 'forward': + switch ($imp_compose->getMetadata('forward_type')) { + case 'forward_body': + case 'forward_both': + $data = $imp_compose->forwardMessageText($imp_contents, array( + 'format' => 'html' + )); + $result->text = $data['body']; + return $result; + } + break; + + case 'reply': + case 'reply_all': + case 'reply_list': + $data = $imp_compose->replyMessageText($imp_contents, array( + 'format' => 'html' + )); + $result->text = $data['body']; + return $result; + } + } + $result->text = $GLOBALS['injector']->getInstance('IMP_Ui_Compose')->convertComposeText($this->_vars->text, 'html', intval($this->_vars->identity)); return $result; diff --git a/imp/lib/Compose.php b/imp/lib/Compose.php index 62e7727e7..cdc9b63fd 100644 --- a/imp/lib/Compose.php +++ b/imp/lib/Compose.php @@ -1460,16 +1460,45 @@ class IMP_Compose $this->_modified = true; } + return array_merge(array( + 'headers' => $header, + 'identity' => $match_identity, + 'type' => $reply_type + ), $this->replyMessageText($contents)); + } + + /** + * Returns the reply text for a message. + * + * @param IMP_Contents $contents An IMP_Contents object. + * @param array $opts Additional options: + *
+     * 'format' - (string) Force to this format.
+     *            DEFAULT: Auto-determine.
+     * 
+ * + * @return array An array with the following keys: + *
+     * 'body'     - The text of the body part
+     * 'encoding' - The guessed charset to use for the reply
+     * 'format'   - The format of the body message
+     * 
+ */ + public function replyMessageText($contents, array $opts = array()) + { + global $prefs; + if (!$prefs->getValue('reply_quote')) { return array( 'body' => '', - 'format' => 'text', - 'headers' => $header, - 'identity' => $match_identity, - 'type' => $reply_type + 'encoding' => '', + 'format' => 'text' ); } + $charset = $GLOBALS['registry']->getCharset(); + $h = $contents->getHeaderOb(); + $from = Horde_Mime_Address::addrArray2String($h->getOb('from'), array('charset' => $charset)); if ($prefs->getValue('reply_headers') && !empty($h)) { @@ -1487,17 +1516,24 @@ class IMP_Compose $msg_post = ''; } - $compose_html = (($_SESSION['imp']['view'] != 'mimp') && $GLOBALS['prefs']->getValue('compose_html')); + if ($_SESSION['imp']['view'] == 'mimp') { + $compose_html = false; + } elseif (!empty($opts['format'])) { + $compose_html = ($opts['format'] == 'html'); + } else { + $compose_html = ($prefs->getValue('compose_html') || $prefs->getValue('reply_format')); + } $msg_text = $this->_getMessageText($contents, array( - 'html' => ($GLOBALS['prefs']->getValue('reply_format') || $compose_html), + 'html' => $compose_html, 'replylimit' => true, 'toflowed' => true, 'type' => 'reply' )); if (!empty($msg_text) && - ($compose_html || ($msg_text['mode'] == 'html'))) { + ($prefs->getValue('compose_html') || + ($msg_text['mode'] == 'html'))) { $msg = '

' . $this->text2html(trim($msg_pre)) . '

' . '
' . (($msg_text['mode'] == 'text') ? $this->text2html($msg_text['text']) : $msg_text['text']) . @@ -1508,15 +1544,13 @@ class IMP_Compose $msg = empty($msg_text['text']) ? '[' . _("No message body text") . ']' : $msg_pre . $msg_text['text'] . $msg_post; + $msg_text['mode'] = 'text'; } return array( 'body' => $msg . "\n", 'encoding' => $msg_text['encoding'], - 'format' => $msg_text['mode'], - 'headers' => $header, - 'identity' => $match_identity, - 'type' => $reply_type + 'format' => $msg_text['mode'] ); } @@ -1569,6 +1603,7 @@ class IMP_Compose * added to the outgoing messages. */ $this->_metadata['in_reply_to'] = trim($h->getValue('message-id')); $this->_metadata['reply_type'] = 'forward'; + $this->_metadata['forward_type'] = $type; $this->_modified = true; $header['subject'] = $h->getValue('subject'); @@ -1581,44 +1616,89 @@ class IMP_Compose $header['subject'] = 'Fwd:'; } + if ($attach && + in_array($type, array('forward_attach', 'forward_both'))) { + $this->attachIMAPMessage(new IMP_Indices($contents)); + } + if (in_array($type, array('forward_body', 'forward_both'))) { - $from = Horde_Mime_Address::addrArray2String($h->getOb('from'), array('charset' => $GLOBALS['registry']->getCharset())); + $ret = $this->forwardMessageText($contents); + } else { + $ret = array( + 'body' => '', + 'encoding' => '', + 'format' => 'text' + ); + } - $msg_pre = "\n----- " . - ($from ? sprintf(_("Forwarded message from %s"), $from) : _("Forwarded message")) . - " -----\n" . $this->_getMsgHeaders($h) . "\n"; - $msg_post = "\n\n----- " . _("End forwarded message") . " -----\n"; + return array_merge(array( + 'headers' => $header, + 'identity' => $this->_getMatchingIdentity($h), + 'type' => $type + ), $ret); + } - $compose_html = (($_SESSION['imp']['view'] != 'mimp') && $GLOBALS['prefs']->getValue('compose_html')); + /** + * Returns the forward text for a message. + * + * @param IMP_Contents $contents An IMP_Contents object. + * @param array $opts Additional options: + *
+     * 'format' - (string) Force to this format.
+     *            DEFAULT: Auto-determine.
+     * 
+ * + * @return array An array with the following keys: + *
+     * 'body'     - The text of the body part
+     * 'encoding' - The guessed charset to use for the reply
+     * 'format'   - The format of the body message
+     * 
+ */ + public function forwardMessageText($contents, array $opts = array()) + { + global $prefs; - $msg_text = $this->_getMessageText($contents, array( - 'html' => ($GLOBALS['prefs']->getValue('forward_format') || $compose_html), - 'type' => 'forward' - )); + $h = $contents->getHeaderOb(); - if (!empty($msg_text) && - ($compose_html || ($msg_text['mode'] == 'html'))) { - $msg = $this->text2html($msg_pre) . - (($msg_text['mode'] == 'text') ? $this->text2html($msg_text['text']) : $msg_text['text']) . - $this->text2html($msg_post); - $format = 'html'; - } else { - $msg = $msg_pre . $msg_text['text'] . $msg_post; - } + $from = Horde_Mime_Address::addrArray2String($h->getOb('from'), array( + 'charset' => $GLOBALS['registry']->getCharset() + )); + + $msg_pre = "\n----- " . + ($from ? sprintf(_("Forwarded message from %s"), $from) : _("Forwarded message")) . + " -----\n" . $this->_getMsgHeaders($h) . "\n"; + $msg_post = "\n\n----- " . _("End forwarded message") . " -----\n"; + + if ($_SESSION['imp']['view'] == 'mimp') { + $compose_html = false; + } elseif (!empty($opts['format'])) { + $compose_html = ($opts['format'] == 'html'); + } else { + $compose_html = ($prefs->getValue('compose_html') || $prefs->getValue('forward_format')); } - if ($attach && - in_array($type, array('forward_attach', 'forward_both'))) { - $this->attachIMAPMessage(new IMP_Indices($contents)); + $msg_text = $this->_getMessageText($contents, array( + 'html' => $compose_html, + 'type' => 'forward' + )); + + if (!empty($msg_text) && + ($prefs->getValue('compose_html') || + ($msg_text['mode'] == 'html'))) { + $msg = $this->text2html($msg_pre) . + (($msg_text['mode'] == 'text') ? $this->text2html($msg_text['text']) : $msg_text['text']) . + $this->text2html($msg_post); + $format = 'html'; + } else { + $msg = $msg_pre . $msg_text['text'] . $msg_post; + $format = 'text'; } return array( 'body' => $msg, - 'encoding' => isset($msg_text) ? $msg_text['encoding'] : $GLOBALS['registry']->getCharset(), - 'format' => $format, - 'headers' => $header, - 'identity' => $this->_getMatchingIdentity($h), - 'type' => $type + 'encoding' => $msg_text['encoding'], + 'format' => $format ); }