From 23c00eee86f1a1af9fa74bc9daf30c8d33ba33f0 Mon Sep 17 00:00:00 2001
From: Thomas Bruederli <thomas@roundcube.net>
Date: Mon, 16 Jun 2014 08:46:31 -0400
Subject: [PATCH] Fix tab navigation with TinyMCE editor (#1489946)

---
 program/js/app.js |  126 ++++++++++++++++++++++++------------------
 1 files changed, 72 insertions(+), 54 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index d12dd81..82b69c4 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -46,12 +46,12 @@
   this.messages = {};
   this.group2expand = {};
   this.http_request_jobs = {};
-  this.menu_stack = new Array();
+  this.menu_stack = [];
 
   // webmail client settings
   this.dblclick_time = 500;
   this.message_time = 5000;
-  this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi');
+  this.identifier_expr = /[^0-9a-z_-]/gi;
 
   // environment defaults
   this.env = {
@@ -314,9 +314,9 @@
               });
 
             // avoid textarea loosing focus when hitting the save-response button/link
-            for (var i=0; this.buttons['save-response'] && i < this.buttons['save-response'].length; i++) {
-              $('#'+this.buttons['save-response'][i].id).mousedown(function(e){ return rcube_event.cancel(e); })
-            }
+            $.each(this.buttons['save-response'] || [], function (i, v) {
+              $('#' + v.id).mousedown(function(e){ return rcube_event.cancel(e); })
+            });
           }
 
           // init message compose form
@@ -403,9 +403,6 @@
             .addEventListener('dragend', function(e) { ref.drag_end(e); })
             .init();
 
-          if (this.env.cid)
-            this.contact_list.highlight_row(this.env.cid);
-
           this.gui_objects.contactslist.parentNode.onmousedown = function(e){ return ref.click_on_list(e); };
 
           $(this.gui_objects.qsearchbox).focusin(function() { ref.contact_list.blur(); });
@@ -471,9 +468,6 @@
             })
             .init()
             .focus();
-
-          if (this.env.iid)
-            this.identity_list.highlight_row(this.env.iid);
         }
         else if (this.gui_objects.sectionslist) {
           this.sections_list = new rcube_list_widget(this.gui_objects.sectionslist, {multiselect:false, draggable:false, keyboard:true});
@@ -1344,7 +1338,7 @@
   this.command_enabled = function(cmd)
   {
     return this.commands[cmd];
-  }
+  };
 
   // lock/unlock interface
   this.set_busy = function(a, message, id)
@@ -1386,10 +1380,11 @@
   // switch to another application task
   this.switch_task = function(task)
   {
-    if (this.task===task && task!='mail')
+    if (this.task === task && task != 'mail')
       return;
 
     var url = this.get_task_url(task);
+
     if (task == 'mail')
       url += '&_mbox=INBOX';
     else if (task == 'logout')
@@ -1444,10 +1439,10 @@
 
   this.save_pref = function(prop)
   {
-    var request = {'_name': prop.name, '_value': prop.value};
+    var request = {_name: prop.name, _value: prop.value};
 
     if (prop.session)
-      request['_session'] = prop.session;
+      request._session = prop.session;
     if (prop.env)
       this.env[prop.env] = prop.value;
 
@@ -1587,7 +1582,7 @@
 
       // select the folder if one of its childs is currently selected
       // don't select if it's virtual (#1488346)
-      if (this.env.mailbox && this.env.mailbox.startsWith(name + this.env.delimiter) && !node.virtual)
+      if (!node.virtual && this.env.mailbox && this.env.mailbox.startsWith(name + this.env.delimiter))
         this.command('list', name);
     }
     else {
@@ -1629,7 +1624,7 @@
     }
 
     // reset popup menus; delayed to have updated menu_stack data
-    window.setTimeout(function(e){
+    setTimeout(function(e){
       var obj, skip, config, id, i, parents = $(target).parents();
       for (i = ref.menu_stack.length - 1; i >= 0; i--) {
         id = ref.menu_stack[i];
@@ -1669,6 +1664,9 @@
     var target = e.target || {},
       keyCode = rcube_event.get_keycode(e);
 
+    // save global reference for keyboard detection on click events in IE
+    rcube_event._last_keyboard_event = e;
+
     if (e.keyCode != 27 && (!this.menu_keyboard_active || target.nodeName == 'TEXTAREA' || target.nodeName == 'SELECT')) {
       return true;
     }
@@ -1678,8 +1676,8 @@
       case 40:
       case 63232: // "up", in safari keypress
       case 63233: // "down", in safari keypress
-        focus_menu_item(mod = keyCode == 38 || keyCode == 63232 ? -1 : 1);
-        break;
+        focus_menu_item(keyCode == 38 || keyCode == 63232 ? -1 : 1);
+        return rcube_event.cancel(e);
 
       case 9:   // tab
         if (this.focused_menu) {
@@ -2428,6 +2426,9 @@
       url._framed = 1;
     }
 
+    if (this.env.uid)
+      url._uid = this.env.uid;
+
     // load message list to target frame/window
     if (mbox) {
       this.set_busy(true, 'loading');
@@ -2474,7 +2475,7 @@
         selection.push(selected[i]);
 
     this.message_list.selection = selection;
-  }
+  };
 
   // expand all threads with unread children
   this.expand_unread = function()
@@ -2487,8 +2488,10 @@
         this.message_list.expand_all(r);
         this.set_unread_children(r.uid);
       }
+
       new_row = new_row.nextSibling;
     }
+
     return false;
   };
 
@@ -2705,8 +2708,8 @@
     }
 
     // update unread_children for roots
-    for (var i=0; i<roots.length; i++)
-      this.set_unread_children(roots[i].uid);
+    for (r=0; r<roots.length; r++)
+      this.set_unread_children(roots[r].uid);
 
     return count;
   };
@@ -3595,6 +3598,11 @@
       $(e.target).filter('select').val(props.html ? 'plain' : 'html');
     }
 
+    if (result) {
+      // update internal format flag
+      $("input[name='_is_html']").val(props.html ? 1 : 0);
+    }
+
     return result;
   };
 
@@ -3701,8 +3709,9 @@
   {
     var active = this.editor.spellcheck_state();
 
-    if (this.buttons.spellcheck)
-      $('#'+this.buttons.spellcheck[0].id)[active ? 'addClass' : 'removeClass']('selected');
+    $.each(this.buttons.spellcheck || [], function(i, v) {
+      $('#' + v.id)[active ? 'addClass' : 'removeClass']('selected');
+    });
 
     return active;
   };
@@ -3900,7 +3909,7 @@
       }
       this.local_storage_remove_item('compose.index');
     }
-  }
+  };
 
 
   this.change_identity = function(obj, show_sig)
@@ -4114,7 +4123,7 @@
 
   this.upload_progress_update = function(param)
   {
-    var elem = $('#'+param.name + '> span');
+    var elem = $('#'+param.name + ' > span');
 
     if (!elem.length || !param.text)
       return;
@@ -4271,21 +4280,22 @@
     this.display_message(msg, type);
 
     if (this.env.extwin) {
-      var rc = this.opener();
       this.lock_form(this.gui_objects.messageform);
+
+      var rc = this.opener();
       if (rc) {
         rc.display_message(msg, type);
         // refresh the folder where sent message was saved or replied message comes from
         if (folders && rc.env.task == 'mail' && rc.env.action == '' && $.inArray(rc.env.mailbox, folders) >= 0) {
-          // @TODO: try with 'checkmail' here when #1485186 is fixed. See also #1489249.
-          rc.command('list');
+          rc.command('checkmail');
         }
       }
-      setTimeout(function(){ window.close() }, 1000);
+
+      setTimeout(function() { window.close(); }, 1000);
     }
     else {
       // before redirect we need to wait some time for Chrome (#1486177)
-      setTimeout(function(){ ref.list_mailbox(); }, 500);
+      setTimeout(function() { ref.list_mailbox(); }, 500);
     }
   };
 
@@ -4508,7 +4518,7 @@
 
       // register (delegate) event handlers
       ul.on('mouseover', 'li', function(e){ ref.ksearch_select(e.target); })
-        .on('onmouseup', 'li', function(e){ ref.ksearch_click(e.target); })
+        .on('mouseup', 'li', function(e){ ref.ksearch_click(e.target); })
     }
 
     ul = this.ksearch_pane.__ul;
@@ -4963,7 +4973,7 @@
   {
     var selection = this.contact_list ? this.contact_list.get_selection() : [];
 
-    // exit if no mailbox specified or if selection is empty
+    // exit if no contact specified or if selection is empty
     if (!selection.length && !this.env.cid)
       return;
 
@@ -7250,11 +7260,24 @@
           this.enable_command('expand-all', 'expand-unread', 'collapse-all', this.env.threading && this.env.messagecount && !is_multifolder);
 
           if ((response.action == 'list' || response.action == 'search') && this.message_list) {
+            var list = this.message_list, uid = this.env.list_uid;
+
+            // highlight message row when we're back from message page
+            if (uid) {
+              if (!list.rows[uid])
+                uid += '-' + this.env.mailbox;
+              if (list.rows[uid]) {
+                list.select(uid);
+              }
+              delete this.env.list_uid;
+            }
+
             this.enable_command('set-listmode', this.env.threads && !is_multifolder);
-            if (this.message_list.rowcount > 0)
-              this.message_list.focus();
-            this.msglist_select(this.message_list);
-            this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:this.message_list.rowcount });
+            if (list.rowcount > 0)
+              list.focus();
+            this.msglist_select(list);
+            this.triggerEvent('listupdate', { folder:this.env.mailbox, rowcount:list.rowcount });
+
           }
         }
         else if (this.task == 'addressbook') {
@@ -7475,8 +7498,10 @@
   // post the given form to a hidden iframe
   this.async_upload_form = function(form, action, onload)
   {
-    var frame, ts = new Date().getTime(),
-      frame_name = 'rcmupload'+ts;
+    // create hidden iframe
+    var ts = new Date().getTime(),
+      frame_name = 'rcmupload' + ts,
+      frame = this.async_upload_form_frame(frame_name);
 
     // upload progress support
     if (this.env.upload_progress_name) {
@@ -7491,21 +7516,7 @@
       field.val(ts);
     }
 
-    // have to do it this way for IE
-    // otherwise the form will be posted to a new window
-    if (document.all) {
-      document.body.insertAdjacentHTML('BeforeEnd', '<iframe name="'+frame_name+'"'
-        + ' src="program/resources/blank.gif" style="width:0;height:0;visibility:hidden;"></iframe>');
-      frame = $('iframe[name="'+frame_name+'"]');
-    }
-    // for standards-compliant browsers
-    else {
-      frame = $('<iframe>').attr('name', frame_name)
-        .css({border: 'none', width: 0, height: 0, visibility: 'hidden'})
-        .appendTo(document.body);
-    }
-
-    // handle upload errors, parsing iframe content in onload
+    // handle upload errors by parsing iframe content in onload
     frame.bind('load', {ts:ts}, onload);
 
     $(form).attr({
@@ -7518,6 +7529,13 @@
     return frame_name;
   };
 
+  // create iframe element for files upload
+  this.async_upload_form_frame = function(name)
+  {
+    return $('<iframe>').attr({name: name, style: 'border: none; width: 0; height: 0; visibility: hidden'})
+      .appendTo(document.body);
+  };
+
   // html5 file-drop API
   this.document_drag_hover = function(e, over)
   {

--
Gitblit v1.9.1