Improvements to Draft handling
| | |
| | | CHANGELOG RoundCube Webmail |
| | | --------------------------- |
| | | |
| | | 2006/07/24 (richs) |
| | | ---------- |
| | | - Draft window no longer reloads. It saves to an iframe in the background instead (fixes bug #1483869) |
| | | - Draft timer now part of program/js/app.js instead of skins/default/templates/compose.inc |
| | | - Draft saving now properly returns an error when saving fails |
| | | - Draft timer stops and resets properly when attachments are uploaded, or when saving manually |
| | | - Old compose session/attachments are now cleaned up when a new/forward/reply/draft is made/opened |
| | | |
| | | |
| | | 2006/07/19 (thomasb) |
| | | ---------- |
| | | - Correct entity encoding of link urls (HTML validity) |
| | |
| | | include('program/steps/mail/rss.inc'); |
| | | |
| | | // kill compose entry from session |
| | | if (isset($_SESSION['compose'])) |
| | | rcmail_compose_cleanup(); |
| | | // if (isset($_SESSION['compose'])) |
| | | // rcmail_compose_cleanup(); |
| | | |
| | | // make sure the message count is refreshed |
| | | $IMAP->messagecount($_SESSION['mbox'], 'ALL', TRUE); |
| | |
| | | var CONTROL_KEY = 1; |
| | | var SHIFT_KEY = 2; |
| | | var CONTROL_SHIFT_KEY = 3; |
| | | var DRAFT_AUTOSAVE = 10; // Minutes |
| | | |
| | | var rcube_webmail_client; |
| | | var rcube_save_timer; |
| | | |
| | | function rcube_webmail() |
| | | { |
| | |
| | | this.dblclick_time = 600; |
| | | this.message_time = 5000; |
| | | this.request_timeout = 180000; |
| | | this.kepp_alive_interval = 60000; |
| | | this._interval = 60000; |
| | | this.mbox_expression = new RegExp('[^0-9a-z\-_]', 'gi'); |
| | | this.env.blank_img = 'skins/default/images/blank.gif'; |
| | | |
| | |
| | | this.display_message(this.pending_message[0], this.pending_message[1]); |
| | | |
| | | // start interval for keep-alive/recent_check signal |
| | | if (this.kepp_alive_interval && this.task=='mail' && this.gui_objects.messagelist) |
| | | this.kepp_alive_int = setInterval(this.ref+'.check_for_recent()', this.kepp_alive_interval); |
| | | if (this._interval && this.task=='mail' && this.gui_objects.messagelist) |
| | | this._int = setInterval(this.ref+'.check_for_recent()', this.keep_alive_interval); |
| | | else if (this.task!='login') |
| | | this.kepp_alive_int = setInterval(this.ref+'.send_keep_alive()', this.kepp_alive_interval); |
| | | this._int = setInterval(this.ref+'.send_keep_alive()', this.keep_alive_interval); |
| | | }; |
| | | |
| | | // reset last clicked if user clicks on anything other than the message table |
| | |
| | | |
| | | // get summary of all field values |
| | | this.cmp_hash = this.compose_field_hash(); |
| | | |
| | | // start the auto-save timer |
| | | this.auto_save_start(); |
| | | |
| | | }; |
| | | |
| | | |
| | | this.init_address_input_events = function(obj) |
| | | { |
| | |
| | | break; |
| | | |
| | | case 'savedraft': |
| | | // Reset the auto-save timer |
| | | self.clearTimeout(rcube_save_timer); |
| | | |
| | | if (!this.gui_objects.messageform) |
| | | break; |
| | | |
| | | |
| | | // if saving Drafts is disabled in main.inc.php |
| | | if (!this.env.drafts_mailbox) |
| | | break; |
| | | |
| | | |
| | | this.set_busy(true, 'savingmessage'); |
| | | var form = this.gui_objects.messageform; |
| | | form.target = "savetarget"; |
| | | form.submit(); |
| | | break; |
| | | |
| | |
| | | this.show_attachment_form(true); |
| | | |
| | | case 'send-attachment': |
| | | // Reset the auto-save timer |
| | | self.clearTimeout(rcube_save_timer); |
| | | |
| | | this.upload_file(props) |
| | | break; |
| | | |
| | |
| | | return true; |
| | | }; |
| | | |
| | | |
| | | this.auto_save_start = function() |
| | | { |
| | | rcube_save_timer = self.setTimeout('rcmail.command("savedraft","",this)',DRAFT_AUTOSAVE * 60000); |
| | | } |
| | | |
| | | this.compose_field_hash = function() |
| | | { |
| | | // check input fields |
| | |
| | | // upload attachment file |
| | | this.upload_file = function(form) |
| | | { |
| | | |
| | | if (!form) |
| | | return false; |
| | | |
| | |
| | | // display a system message |
| | | this.display_message = function(msg, type, hold) |
| | | { |
| | | this.set_busy(false); |
| | | if (!this.loaded) // save message in order to display after page loaded |
| | | { |
| | | this.pending_message = new Array(msg, type); |
| | | return true; |
| | | } |
| | | |
| | | |
| | | if (!this.gui_objects.message) |
| | | return false; |
| | | |
| | | |
| | | if (this.message_timer) |
| | | clearTimeout(this.message_timer); |
| | | |
| | |
| | | this.gui_objects.message._rcube = this; |
| | | this.gui_objects.message.innerHTML = cont; |
| | | this.gui_objects.message.style.display = 'block'; |
| | | |
| | | |
| | | if (type!='loading') |
| | | this.gui_objects.message.onmousedown = function(){ this._rcube.hide_message(); return true; }; |
| | | |
| | |
| | | |
| | | require_once('Mail/mimeDecode.php'); |
| | | |
| | | |
| | | $MESSAGE_FORM = NULL; |
| | | $REPLY_MESSAGE = NULL; |
| | | $FORWARD_MESSAGE = NULL; |
| | | $DRAFT_MESSAGE = NULL; |
| | | |
| | | |
| | | if (!is_array($_SESSION['compose'])) |
| | | $_SESSION['compose'] = array('id' => uniqid(rand())); |
| | | |
| | | // remove an attachment |
| | | if ($_action=='remove-attachment' && !empty($_GET['_filename'])) |
| | | { |
| | |
| | | exit; |
| | | } |
| | | } |
| | | |
| | | $MESSAGE_FORM = NULL; |
| | | $REPLY_MESSAGE = NULL; |
| | | $FORWARD_MESSAGE = NULL; |
| | | $DRAFT_MESSAGE = NULL; |
| | | |
| | | // nothing below is called during message composition, only at "new/forward/reply/draft" initialization |
| | | // since there are many ways to leave the compose page improperly, it seems necessary to clean-up an old |
| | | // compose when a "new/forward/reply/draft" is called - otherwise the old session attachments will appear |
| | | |
| | | rcmail_compose_cleanup(); |
| | | $_SESSION['compose'] = array('id' => uniqid(rand())); |
| | | |
| | | // add some labels to client |
| | | rcube_add_label('nosubject', 'norecipientwarning', 'nosubjectwarning', 'nobodywarning', 'notsentwarning', 'savingmessage', 'savingmessage', 'messagesaved'); |
| | |
| | | |
| | | $out = $form_start ? "$form_start\n" : ''; |
| | | |
| | | // Check if a previous save was done so we can delete it upon the next save |
| | | if (!empty($_POST['_draft_newsaveid'])) |
| | | $saveid = new hiddenfield(array('name' => '_draft_saveid', 'value' => $_POST['_draft_newsaveid'])); |
| | | else if (strlen($DRAFT_MESSAGE['headers']->messageID) > 6) |
| | | $saveid = new hiddenfield(array('name' => '_draft_saveid', 'value' => str_replace(array('<','>'),"",$DRAFT_MESSAGE['headers']->messageID) )); |
| | | $saveid = new hiddenfield(array('name' => '_draft_saveid', 'value' => str_replace(array('<','>'),"",$DRAFT_MESSAGE['headers']->messageID) )); |
| | | $out .= $saveid->show(); |
| | | |
| | | if ($saveid) |
| | | $out .= $saveid->show(); |
| | | |
| | | $newsaveid = new hiddenfield(array('name' => '_draft_newsaveid', 'value' => sprintf('%s@%s', md5(uniqid('rcmail'.rand(),true)), $_SESSION['imap_host']) )); |
| | | $out .= $newsaveid->show(); |
| | | |
| | | $drafttoggle = new hiddenfield(array('name' => '_draft', 'value' => 'yes')); |
| | | $out .= $drafttoggle->show(); |
| | | |
| | |
| | | |
| | | rcube_add_label('checking'); |
| | | } |
| | | |
| | | |
| | | $out .= '<iframe name="savetarget" src="program/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>'; |
| | | |
| | | return $out; |
| | | } |
| | | |
| | |
| | | if (strlen($_POST['_draft_saveid']) > 3) |
| | | $olddraftmessageid = get_input_value('_draft_saveid', RCUBE_INPUT_POST); |
| | | |
| | | if (strlen($_POST['_draft_newsaveid']) > 3) |
| | | $newdraftmessageid = get_input_value('_draft_newsaveid', RCUBE_INPUT_POST); |
| | | $message_id = sprintf('<%s@%s>', md5(uniqid('rcmail'.rand(),true)), $_SESSION['imap_host']); |
| | | |
| | | $savedraft = !empty($_POST['_draft']) ? TRUE : FALSE; |
| | | |
| | | |
| | | /****** check submission and compose message ********/ |
| | | |
| | | |
| | |
| | | $to_address_arr = $IMAP->decode_address_list($mailto); |
| | | $identity_arr = rcmail_get_identity(get_input_value('_from', RCUBE_INPUT_POST)); |
| | | |
| | | |
| | | $from = $identity_arr['mailto']; |
| | | $first_to = is_array($to_address_arr[0]) ? $to_address_arr[0]['mailto'] : $mailto; |
| | | |
| | | |
| | | // try the message-id submitted by the compose form |
| | | if ($newdraftmessageid) |
| | | $message_id = sprintf('<%s>',$newdraftmessageid); |
| | | else |
| | | $message_id = sprintf('<%s@%s>', md5(uniqid('rcmail'.rand(),true)), $_SESSION['imap_host']); |
| | | |
| | | if (empty($identity_arr['string'])) |
| | | $identity_arr['string'] = $from; |
| | | |
| | | |
| | | // compose headers array |
| | | $headers = array('Date' => date('D, j M Y G:i:s O'), |
| | |
| | | |
| | | // raise error if saving failed |
| | | if (!$saved) |
| | | { |
| | | // clear the "saving message" busy status, and display failure |
| | | $errorout = sprintf("parent.%s.display_message('%s', '%s');", |
| | | $JS_OBJECT_NAME, |
| | | addslashes(rep_specialchars_output(rcube_label(array('name' => 'errorsaving', 'vars' => NULL)))), |
| | | 'error'); |
| | | print "<html><script type=\"text/javascript\">$errorout</script></html>"; |
| | | raise_error(array('code' => 800, |
| | | 'type' => 'imap', |
| | | 'file' => __FILE__, |
| | | 'message' => "Could not save message in $CONFIG[$store_target]"), TRUE, FALSE); |
| | | exit; |
| | | } |
| | | |
| | | if ($olddraftmessageid) |
| | | { |
| | |
| | | $a_deleteid = $IMAP->search($CONFIG['drafts_mbox'],'HEADER Message-ID',$olddraftmessageid); |
| | | $deleted = $IMAP->delete_message($IMAP->get_uid($a_deleteid[0],$CONFIG['drafts_mbox']),$CONFIG['drafts_mbox']); |
| | | |
| | | // raise error if deletion of old draft failed |
| | | if (!$deleted) |
| | | raise_error(array('code' => 800, |
| | | 'type' => 'imap', |
| | |
| | | |
| | | if ($savedraft) |
| | | { |
| | | show_message('messagesaved', 'confirmation'); |
| | | rcmail_overwrite_action('compose'); |
| | | // clear the "saving message" busy status, and display success |
| | | $frameout = sprintf("parent.%s.display_message('%s', '%s');", |
| | | $JS_OBJECT_NAME, |
| | | addslashes(rep_specialchars_output(rcube_label(array('name' => 'messagesaved', 'vars' => NULL)))), |
| | | 'confirmation'); |
| | | |
| | | // update "_draft_saveid" on the page, which is used to delete a previous draft |
| | | $frameout .= 'var foundid = parent.rcube_find_object("_draft_saveid",parent.document);'; |
| | | $frameout .= sprintf('foundid.value = "%s";',str_replace(array('<','>'),"",$message_id)); |
| | | |
| | | // update the "cmp_hash" to prevent "Unsaved changes" warning |
| | | $frameout .= sprintf("parent.%s.cmp_hash = parent.%s.compose_field_hash();",$JS_OBJECT_NAME,$JS_OBJECT_NAME); |
| | | |
| | | // start the auto-save timer again |
| | | $frameout .= sprintf("parent.%s.auto_save_start();",$JS_OBJECT_NAME); |
| | | |
| | | // send html page with JS calls as response |
| | | print "<html><script type=\"text/javascript\">$frameout</script></html>"; |
| | | exit; |
| | | } |
| | | else |
| | | { |
| | |
| | | { |
| | | $response |
| | | parent.$JS_OBJECT_NAME.show_attachment_form(false); |
| | | parent.$JS_OBJECT_NAME.auto_save_start(); |
| | | } |
| | | </script> |
| | | </html> |
| | |
| | | return false; |
| | | } |
| | | |
| | | function rcmail_auto_save() |
| | | { |
| | | rcmail.command('savedraft','',this); |
| | | self.setTimeout('rcmail_auto_save()',300000); |
| | | } |
| | | self.setTimeout('rcmail_auto_save()',300000); |
| | | |
| | | //--> |
| | | </script> |
| | | </head> |