From 77de23fa939338546a3e049459ffd29edd9058c2 Mon Sep 17 00:00:00 2001
From: Aleksander Machniak <alec@alec.pl>
Date: Sun, 11 Nov 2012 04:32:05 -0500
Subject: [PATCH] Added cross-task 'refresh' request for system state updates

---
 program/js/app.js |  295 +++++++++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 207 insertions(+), 88 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index 8296400..25fddf1 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -176,10 +176,10 @@
     }
 
     // enable general commands
-    this.enable_command('logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', 'about', 'switch-task', true);
+    this.enable_command('close', 'logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', 'about', 'switch-task', true);
 
     if (this.env.permaurl)
-      this.enable_command('permaurl', true);
+      this.enable_command('permaurl', 'extwin', true);
 
     switch (this.task) {
 
@@ -249,7 +249,7 @@
           }
         }
         else if (this.env.action == 'compose') {
-          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses'];
+          this.env.compose_commands = ['send-attachment', 'remove-attachment', 'send', 'cancel', 'toggle-editor', 'list-adresses', 'extwin'];
 
           if (this.env.drafts_mailbox)
             this.env.compose_commands.push('savedraft')
@@ -424,12 +424,14 @@
           $('#rcmloginpwd').focus();
 
         // detect client timezone
-        var dt = new Date(),
-          tz = dt.getTimezoneOffset() / -60,
-          stdtz = dt.getStdTimezoneOffset() / -60;
-
-        $('#rcmlogintz').val(stdtz);
-        $('#rcmlogindst').val(tz > stdtz ? 1 : 0);
+        if (window.jstz && !bw.ie6) {
+          var timezone = jstz.determine();
+          if (timezone.name())
+            $('#rcmlogintz').val(timezone.name());
+        }
+        else {
+          $('#rcmlogintz').val(new Date().getStdTimezoneOffset() / -60);
+        }
 
         // display 'loading' message on form submit, lock submit button
         $('form').submit(function () {
@@ -480,7 +482,8 @@
         this.onloads[i]();
       }
 
-    // start keep-alive interval
+    // start keep-alive and refresh intervals
+    this.start_refresh();
     this.start_keepalive();
   };
 
@@ -570,6 +573,19 @@
           parent.location.href = this.env.permaurl;
         break;
 
+      case 'extwin':
+        if (this.env.action == 'compose') {
+          var prevstate = this.env.compose_extwin;
+          $("input[name='_action']", this.gui_objects.messageform).val('compose');
+          this.gui_objects.messageform.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 });
+          this.gui_objects.messageform.target = this.open_window('', 1150, 900);
+          this.gui_objects.messageform.submit();
+        }
+        else {
+          this.open_window(this.env.permaurl, 1000, 1200);
+        }
+        break;
+
       case 'menu-open':
       case 'menu-save':
         this.triggerEvent(command, {props:props});
@@ -582,10 +598,18 @@
         }
         break;
 
+      case 'close':
+        if (this.env.extwin)
+          window.close();
+        break;
+
       case 'list':
         if (props && props != '')
           this.reset_qsearch();
-        if (this.task == 'mail') {
+        if (this.env.action == 'compose' && this.env.extwin) {
+          window.close();
+        }
+        else if (this.task == 'mail') {
           this.list_mailbox(props);
           this.set_button_titles();
         }
@@ -640,7 +664,7 @@
           uid = this.get_single_uid();
           if (uid && (!this.env.uid || uid != this.env.uid)) {
             if (this.env.mailbox == this.env.drafts_mailbox)
-              this.goto_url('compose', { _draft_uid: uid, _mbox: this.env.mailbox }, true);
+              this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox });
             else
               this.show_message(uid);
           }
@@ -669,7 +693,7 @@
         else if (this.task == 'mail' && (cid = this.get_single_uid())) {
           url = { _mbox: this.env.mailbox };
           url[this.env.mailbox == this.env.drafts_mailbox && props != 'new' ? '_draft_uid' : '_uid'] = cid;
-          this.goto_url('compose', url, true);
+          this.open_compose_step(url);
         }
         break;
 
@@ -857,52 +881,47 @@
           this.show_message(this.env.first_uid);
         break;
 
-      case 'checkmail':
-        this.check_for_recent(true);
-        break;
-
       case 'compose':
-        url = this.url('mail/compose');
+        url = {};
 
         if (this.task == 'mail') {
-          url += '&_mbox='+urlencode(this.env.mailbox);
+          url._mbox = this.env.mailbox;
           if (props)
-             url += '&_to='+urlencode(props);
+             url._to = props;
           // also send search request so we can go back to search result after message is sent
           if (this.env.search_request)
-            url += '&_search='+this.env.search_request;
+            url._search = this.env.search_request;
         }
         // modify url if we're in addressbook
         else if (this.task == 'addressbook') {
           // switch to mail compose step directly
           if (props && props.indexOf('@') > 0) {
-            url = this.get_task_url('mail', url);
-            this.redirect(url + '&_to='+urlencode(props));
+            url._to = props;
+          }
+          else {
+            // use contact_id passed as command parameter
+            var n, len, a_cids = [];
+            if (props)
+              a_cids.push(props);
+            // get selected contacts
+            else if (this.contact_list) {
+              var selection = this.contact_list.get_selection();
+              for (n=0, len=selection.length; n<len; n++)
+                a_cids.push(selection[n]);
+            }
+
+            if (a_cids.length)
+              this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source }, true);
+            else if (this.env.group)
+              this.http_post('mailto', { _gid: this.env.group, _source: this.env.source }, true);
+
             break;
           }
-
-          // use contact_id passed as command parameter
-          var n, len, a_cids = [];
-          if (props)
-            a_cids.push(props);
-          // get selected contacts
-          else if (this.contact_list) {
-            var selection = this.contact_list.get_selection();
-            for (n=0, len=selection.length; n<len; n++)
-              a_cids.push(selection[n]);
-          }
-
-          if (a_cids.length)
-            this.http_post('mailto', { _cid: a_cids.join(','), _source: this.env.source}, true);
-          else if (this.env.group)
-            this.http_post('mailto', { _gid: this.env.group, _source: this.env.source}, true);
-
-          break;
         }
         else if (props)
-          url += '&_to='+urlencode(props);
+          url._to = props;
 
-        this.redirect(url);
+        this.open_compose_step(url);
         break;
 
       case 'spellcheck':
@@ -929,9 +948,6 @@
           this.auto_save_start();
           break;
         }
-
-        // re-set keep-alive timeout
-        this.start_keepalive();
 
         this.submit_messageform(true);
         break;
@@ -977,7 +993,7 @@
           else if (command == 'reply-list')
             url._all = 'list';
 
-          this.goto_url('compose', url, true);
+          this.open_compose_step(url);
         }
         break;
 
@@ -987,7 +1003,7 @@
           url = { _forward_uid: uid, _mbox: this.env.mailbox };
           if (command == 'forward-attachment' || (!props && this.env.forward_attachment))
             url._attachment = 1;
-          this.goto_url('compose', url, true);
+          this.open_compose_step(url);
         }
         break;
 
@@ -1561,7 +1577,7 @@
 
     var uid = list.get_single_selection();
     if (uid && this.env.mailbox == this.env.drafts_mailbox)
-      this.goto_url('compose', { _draft_uid: uid, _mbox: this.env.mailbox }, true);
+      this.open_compose_step({ _draft_uid: uid, _mbox: this.env.mailbox });
     else if (uid)
       this.show_message(uid, false, false);
   };
@@ -1641,6 +1657,28 @@
     }
 
     return allow ? (copy ? 2 : 1) : 0;
+  };
+
+  this.open_window = function(url, width, height)
+  {
+    var w = Math.min(width, screen.width - 10),
+      h = Math.min(height, screen.height - 100),
+      l = (screen.width - w) / 2 + (screen.left || 0),
+      t = Math.max(0, (screen.height - h) / 2 + (screen.top || 0) - 20);
+
+    var wname = 'rcmextwin' + new Date().getTime(),
+      extwin = window.open(url + '&_extwin=1', wname, 'width='+w+',height='+h+',top='+t+',left='+l+',resizable=yes,toolbar=no,status=no');
+    extwin.moveTo(l,t);
+
+    // write loading... message to empty windows
+    if (!url && extwin.document) {
+      extwin.document.write('<html><body>' + this.get_label('loading') + '</body></html>');
+    }
+
+    // focus window, delayed to bring to front
+    window.setTimeout(function(){ extwin.focus(); }, 10);
+
+    return wname;
   };
 
 
@@ -1906,7 +1944,7 @@
       this.list_mailbox('', '', sort_col+'_'+sort_order, post_data);
   };
 
-  // when user doble-clicks on a row
+  // when user double-clicks on a row
   this.show_message = function(id, safe, preview)
   {
     if (!id)
@@ -1931,10 +1969,17 @@
     // add browser capabilities, so we can properly handle attachments
     url += '&_caps='+urlencode(this.browser_capabilities());
 
-    if (preview && String(target.location.href).indexOf(url) >= 0)
+    if (this.env.extwin)
+      url += '&_extwin=1';
+
+    if (preview && String(target.location.href).indexOf(url) >= 0) {
       this.show_contentframe(true);
+    }
     else {
-      this.location_href(this.env.comm_path+url, target, true);
+      if (!preview && this.env.message_extwin && !this.env.extwin)
+        this.open_window(this.env.comm_path+url, 1000, 1200);
+      else
+        this.location_href(this.env.comm_path+url, target, true);
 
       // mark as read and change mbox unread counter
       if (preview && this.message_list && this.message_list.rows[id] && this.message_list.rows[id].unread && this.env.preview_pane_mark_read >= 0) {
@@ -2011,6 +2056,15 @@
       else if (this.task == 'mail')
         this.list_mailbox(this.env.mailbox, page);
     }
+  };
+
+  // sends request to check for recent messages
+  this.checkmail = function()
+  {
+    var lock = this.set_busy(true, 'checkingmail'),
+      params = this.check_recent_params();
+
+    this.http_request('check-recent', params, lock);
   };
 
   // list messages of a specific mailbox using filter
@@ -2962,6 +3016,20 @@
   /*********        message compose methods        *********/
   /*********************************************************/
 
+  this.open_compose_step = function(p)
+  {
+    var url = this.url('mail/compose', p);
+
+    // open new compose window
+    if (this.env.compose_extwin && !this.env.extwin) {
+      this.open_window(url, 1150, 900);
+    }
+    else {
+      this.redirect(url);
+      window.resizeTo(Math.max(1150, $(window).width()), Math.max(900, $(window).height()));
+    }
+  };
+
   // init message compose form: set focus and eventhandlers
   this.init_messageform = function()
   {
@@ -2975,6 +3043,12 @@
       html_mode = $("input[name='_is_html']").val() == '1',
       ac_fields = ['cc', 'bcc', 'replyto', 'followupto'],
       ac_props;
+
+    // close compose step in opener
+    if (window.opener && opener.rcmail && opener.rcmail.env.action == 'compose') {
+      setTimeout(function(){ opener.history.back(); }, 100);
+      this.env.opened_extwin = true;
+    }
 
     // configure parallel autocompletion
     if (this.env.autocomplete_threads > 0) {
@@ -2994,7 +3068,7 @@
       this.set_caret_pos(input_message, this.env.top_posting ? 0 : $(input_message).val().length);
       // add signature according to selected identity
       // if we have HTML editor, signature is added in callback
-      if (input_from.prop('type') == 'select-one') {
+      if (input_from.prop('type') == 'select-one' && !this.env.opened_extwin) {
         this.change_identity(input_from[0]);
       }
     }
@@ -3630,8 +3704,16 @@
   this.sent_successfully = function(type, msg)
   {
     this.display_message(msg, type);
-    // before redirect we need to wait some time for Chrome (#1486177)
-    setTimeout(function(){ ref.list_mailbox(); }, 500);
+
+    if (this.env.extwin && window.opener && opener.rcmail) {
+      this.lock_form(this.gui_objects.messageform);
+      opener.rcmail.display_message(msg, type);
+      setTimeout(function(){ window.close() }, 1000);
+    }
+    else {
+      // before redirect we need to wait some time for Chrome (#1486177)
+      setTimeout(function(){ ref.list_mailbox(); }, 500);
+    }
   };
 
 
@@ -5966,10 +6048,18 @@
     if (lock || lock === null)
       this.set_busy(true);
 
-    if (this.is_framed())
+    if (this.is_framed()) {
       parent.rcmail.redirect(url, lock);
-    else
+    }
+    else {
+      if (this.env.extwin) {
+        if (typeof url == 'string')
+          url += (url.indexOf('?') < 0 ? '?' : '&') + '_extwin=1';
+        else
+          url._extwin = 1;
+      }
       this.location_href(url, window);
+    }
   };
 
   this.goto_url = function(action, query, lock)
@@ -5990,6 +6080,9 @@
       $('<a>').attr('href', url).appendTo(document.body).get(0).click();
     else
       target.location.href = url;
+
+    // reset keep-alive interval
+    this.start_keepalive();
   };
 
   // send a http request to the server
@@ -6018,6 +6111,9 @@
       success: function(data){ ref.http_response(data); },
       error: function(o, status, err) { ref.http_error(o, status, err, lock, action); }
     });
+
+    // reset keep-alive interval
+    this.start_keepalive();
   };
 
   // send a http POST request to the server
@@ -6035,7 +6131,7 @@
     // trigger plugin hook
     var result = this.triggerEvent('request'+action, postdata);
     if (result !== undefined) {
-      // abort if one the handlers returned false
+      // abort if one of the handlers returned false
       if (result === false)
         return false;
       else
@@ -6050,6 +6146,9 @@
       success: function(data){ ref.http_response(data); },
       error: function(o, status, err) { ref.http_error(o, status, err, lock, action); }
     });
+
+    // reset keep-alive interval
+    this.start_keepalive();
   };
 
   // aborts ajax request
@@ -6144,6 +6243,7 @@
         }
         break;
 
+      case 'refresh':
       case 'check-recent':
       case 'getunread':
       case 'search':
@@ -6177,6 +6277,9 @@
 
     this.triggerEvent('responseafter', {response: response});
     this.triggerEvent('responseafter'+response.action, {response: response});
+
+    // reset keep-alive interval
+    this.start_keepalive();
   };
 
   // handle HTTP request errors
@@ -6200,9 +6303,7 @@
 
     // re-send keep-alive requests after 30 seconds
     if (action == 'keep-alive')
-      setTimeout(function(){ ref.keep_alive(); }, 30000);
-    else if (action == 'check-recent')
-      setTimeout(function(){ ref.check_for_recent(false); }, 30000);
+      setTimeout(function(){ ref.keep_alive(); ref.start_keepalive(); }, 30000);
   };
 
   // post the given form to a hidden iframe
@@ -6372,20 +6473,28 @@
     }
   };
 
-
-  // starts interval for keep-alive/check-recent signal
+  // starts interval for keep-alive signal
   this.start_keepalive = function()
   {
-    if (!this.env.keep_alive || this.env.framed)
+    if (!this.env.session_lifetime || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print')
       return;
 
-    if (this._int)
-      clearInterval(this._int);
+    if (this._keepalive)
+      clearInterval(this._keepalive);
 
-    if (this.task == 'mail' && this.gui_objects.mailboxlist)
-      this._int = setInterval(function(){ ref.check_for_recent(false); }, this.env.keep_alive * 1000);
-    else if (this.task != 'login' && this.env.action != 'print')
-      this._int = setInterval(function(){ ref.keep_alive(); }, this.env.keep_alive * 1000);
+    this._keepalive = setInterval(function(){ ref.keep_alive(); }, this.env.session_lifetime * 0.5 * 1000);
+  };
+
+  // starts interval for refresh signal
+  this.start_refresh = function()
+  {
+    if (!this.env.keep_alive || this.env.framed || this.env.extwin || this.task == 'login' || this.env.action == 'print')
+      return;
+
+    if (this._refresh)
+      clearInterval(this._refresh);
+
+    this._refresh = setInterval(function(){ ref.refresh(); }, this.env.keep_alive * 1000);
   };
 
   // sends keep-alive signal
@@ -6395,29 +6504,39 @@
       this.http_request('keep-alive');
   };
 
-  // sends request to check for recent messages
-  this.check_for_recent = function(refresh)
+  // sends refresh signal
+  this.refresh = function()
   {
-    if (this.busy)
+    if (this.busy) {
+      // try again after 10 seconds
+      setTimeout(function(){ ref.refresh(); ref.start_refresh(); }, 10000);
       return;
-
-    var lock, url = {_mbox: this.env.mailbox};
-
-    if (refresh) {
-      lock = this.set_busy(true, 'checkingmail');
-      url._refresh = 1;
-      // reset check-recent interval
-      this.start_keepalive();
     }
 
-    if (this.gui_objects.messagelist)
-      url._list = 1;
-    if (this.gui_objects.quotadisplay)
-      url._quota = 1;
-    if (this.env.search_request)
-      url._search = this.env.search_request;
+    var params = {}, lock = this.set_busy(true, 'refreshing');
 
-    this.http_request('check-recent', url, lock);
+    if (this.task == 'mail' && this.gui_objects.mailboxlist)
+      params = this.check_recent_params();
+
+    // plugins should bind to 'requestrefresh' event to add own params
+    this.http_request('refresh', params, lock);
+  };
+
+  // returns check-recent request parameters
+  this.check_recent_params = function()
+  {
+    var params = {_mbox: this.env.mailbox};
+
+    if (this.gui_objects.mailboxlist)
+      params._folderlist = 1;
+    if (this.gui_objects.messagelist)
+      params._list = 1;
+    if (this.gui_objects.quotadisplay)
+      params._quota = 1;
+    if (this.env.search_request)
+      params._search = this.env.search_request;
+
+    return params;
   };
 
 

--
Gitblit v1.9.1