From 50077da8e6daab205f8ee9512b2f37b5378f9938 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Mon, 19 Sep 2011 16:45:55 -0400
Subject: [PATCH] Numbers are also allowed in action names

---
 program/js/app.js |  454 ++++++++++++++++++++++++++++++++++++++------------------
 1 files changed, 304 insertions(+), 150 deletions(-)

diff --git a/program/js/app.js b/program/js/app.js
index 66cae80..44d5823 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -3,7 +3,8 @@
  | Roundcube Webmail Client Script                                       |
  |                                                                       |
  | This file is part of the Roundcube Webmail client                     |
- | Copyright (C) 2005-2010, The Roundcube Dev Team                       |
+ | Copyright (C) 2005-2011, The Roundcube Dev Team                       |
+ | Copyright (C) 2011, Kolab Systems AG                                  |
  | Licensed under the GNU GPL                                            |
  |                                                                       |
  +-----------------------------------------------------------------------+
@@ -39,11 +40,6 @@
   this.message_time = 2000;
 
   this.identifier_expr = new RegExp('[^0-9a-z\-_]', 'gi');
-
-  // mimetypes supported by the browser (default settings)
-  this.mimetypes = new Array('text/plain', 'text/html', 'text/xml',
-    'image/jpeg', 'image/gif', 'image/png',
-    'application/x-javascript', 'application/pdf', 'application/x-shockwave-flash');
 
   // default environment vars
   this.env.keep_alive = 60;        // seconds
@@ -90,12 +86,15 @@
     if (over) button_prop.over = over;
 
     this.buttons[command].push(button_prop);
+
+    if (this.loaded)
+      init_button(command, button_prop);
   };
 
   // register a specific gui object
   this.gui_object = function(name, id)
   {
-    this.gui_objects[name] = id;
+    this.gui_objects[name] = this.loaded ? rcube_find_object(id) : id;
   };
 
   // register a container object
@@ -156,7 +155,7 @@
     }
 
     // enable general commands
-    this.enable_command('logout', 'mail', 'addressbook', 'settings', 'save-pref', 'undo', true);
+    this.enable_command('logout', 'mail', 'addressbook', 'settings', 'save-pref', 'compose', 'undo', true);
 
     if (this.env.permaurl)
       this.enable_command('permaurl', true);
@@ -165,7 +164,7 @@
 
       case 'mail':
         // enable mail commands
-        this.enable_command('list', 'checkmail', 'compose', 'add-contact', 'search', 'reset-search', 'collapse-folder', true);
+        this.enable_command('list', 'checkmail', 'add-contact', 'search', 'reset-search', 'collapse-folder', true);
 
         if (this.gui_objects.messagelist) {
 
@@ -322,14 +321,13 @@
         }
         if (this.gui_objects.qsearchbox) {
           this.enable_command('search', 'reset-search', 'moveto', true);
-          $(this.gui_objects.qsearchbox).select();
         }
 
         if (this.contact_list && this.contact_list.rowcount > 0)
           this.enable_command('export', true);
 
         this.enable_command('add', 'import', this.env.writable_source);
-        this.enable_command('list', 'listgroup', 'advanced-search', true);
+        this.enable_command('list', 'listgroup', 'listsearch', 'advanced-search', true);
 
         // load contacts of selected source
         if (!this.env.action)
@@ -401,6 +399,10 @@
       default:
         break;
       }
+
+    // prevent from form submit with Enter key in file input fields
+    if (bw.ie)
+      $('input[type=file]').keydown(function(e) { if (e.keyCode == '13') e.preventDefault(); });
 
     // flag object as complete
     this.loaded = true;
@@ -521,21 +523,15 @@
         break;
 
       case 'list':
-        if (this.task=='mail') {
-          if (!this.env.search_request || (props && props != this.env.mailbox))
-            this.reset_qsearch();
-
+        this.reset_qsearch();
+        if (this.task == 'mail') {
           this.list_mailbox(props);
 
           if (this.env.trash_mailbox && !this.env.flag_for_deletion)
             this.set_alttext('delete', this.env.mailbox != this.env.trash_mailbox ? 'movemessagetotrash' : 'deletemessage');
         }
         else if (this.task == 'addressbook') {
-          if (!this.env.search_request || (props != this.env.source))
-            this.reset_qsearch();
-
           this.list_contacts(props);
-          this.enable_command('add', 'import', this.env.writable_source);
         }
         break;
 
@@ -642,11 +638,6 @@
             if (props == 'reload') {
               form.action += '?_reload=1';
             }
-            else if ((input = $("input[name='_name']", form)) &&input.length && input.val() == '') {
-              alert(this.get_label('nonamewarning'));
-              input.focus();
-              break;
-            }
             else if (this.task == 'settings' && (this.env.identities_level % 2) == 0  &&
               (input = $("input[name='_email']", form)) && input.length && !rcube_check_email(input.val())
             ) {
@@ -749,7 +740,7 @@
         var qstring = '_mbox='+urlencode(this.env.mailbox)+'&_uid='+this.env.uid+'&_part='+props.part;
 
         // open attachment in frame if it's of a supported mimetype
-        if (this.env.uid && props.mimetype && $.inArray(props.mimetype, this.mimetypes)>=0) {
+        if (this.env.uid && props.mimetype && this.env.mimetypes && $.inArray(props.mimetype, this.env.mimetypes)>=0) {
           if (props.mimetype == 'text/html')
             qstring += '&_safe=1';
           this.attachment_win = window.open(this.env.comm_path+'&_action=get&'+qstring+'&_frame=1', 'rcubemailattachment');
@@ -818,7 +809,7 @@
         break;
 
       case 'compose':
-        var url = this.env.comm_path+'&_action=compose';
+        var url = this.url('mail/compose');
 
         if (this.task == 'mail') {
           url += '&_mbox='+urlencode(this.env.mailbox);
@@ -993,21 +984,24 @@
       // reset quicksearch
       case 'reset-search':
         var n, s = this.env.search_request || this.env.qsearch;
+
         this.reset_qsearch();
+        this.select_all_mode = false;
 
         if (s && this.env.mailbox)
-          this.list_mailbox(this.env.mailbox);
+          this.list_mailbox(this.env.mailbox, 1);
         else if (s && this.task == 'addressbook') {
           if (this.env.source == '') {
             for (n in this.env.address_sources) break;
             this.env.source = n;
             this.env.group = '';
           }
-          this.list_contacts(this.env.source, this.env.group);
+          this.list_contacts(this.env.source, this.env.group, 1);
         }
         break;
 
       case 'listgroup':
+        this.reset_qsearch();
         this.list_contacts(props.source, props.id);
         break;
 
@@ -1215,12 +1209,12 @@
   this.drag_menu = function(e, target)
   {
     var modkey = rcube_event.get_modifier(e),
-      menu = $('#'+this.gui_objects.message_dragmenu);
+      menu = this.gui_objects.message_dragmenu;
 
     if (menu && modkey == SHIFT_KEY && this.commands['copy']) {
       var pos = rcube_event.get_mouse_pos(e);
       this.env.drag_target = target;
-      menu.css({top: (pos.y-10)+'px', left: (pos.x-10)+'px'}).show();
+      $(menu).css({top: (pos.y-10)+'px', left: (pos.x-10)+'px'}).show();
       return true;
     }
 
@@ -1229,9 +1223,9 @@
 
   this.drag_menu_action = function(action)
   {
-    var menu = $('#'+this.gui_objects.message_dragmenu);
+    var menu = this.gui_objects.message_dragmenu;
     if (menu) {
-      menu.hide();
+      $(menu).hide();
     }
     this.command(action, this.env.drag_target);
     this.env.drag_target = null;
@@ -1378,12 +1372,12 @@
       ul.show();
       div.removeClass('collapsed').addClass('expanded');
       var reg = new RegExp('&'+urlencode(id)+'&');
-      this.set_env('collapsed_folders', this.env.collapsed_folders.replace(reg, ''));
+      this.env.collapsed_folders = this.env.collapsed_folders.replace(reg, '');
     }
     else {
       ul.hide();
       div.removeClass('expanded').addClass('collapsed');
-      this.set_env('collapsed_folders', this.env.collapsed_folders+'&'+urlencode(id)+'&');
+      this.env.collapsed_folders = this.env.collapsed_folders+'&'+urlencode(id)+'&';
 
       // select parent folder if one of its childs is currently selected
       if (this.env.mailbox.indexOf(id + this.env.delimiter) == 0)
@@ -1528,11 +1522,12 @@
 
   this.msglist_keypress = function(list)
   {
+    if (list.modkey == CONTROL_KEY)
+      return;
+
     if (list.key_pressed == list.ENTER_KEY)
       this.command('show');
-    else if (list.key_pressed == list.DELETE_KEY)
-      this.command('delete');
-    else if (list.key_pressed == list.BACKSPACE_KEY)
+    else if (list.key_pressed == list.DELETE_KEY || list.key_pressed == list.BACKSPACE_KEY)
       this.command('delete');
     else if (list.key_pressed == 33)
       this.command('previouspage');
@@ -1568,10 +1563,10 @@
       }
 
     if ((found = $.inArray('flag', this.env.coltypes)) >= 0)
-      this.set_env('flagged_col', found);
+      this.env.flagged_col = found;
 
     if ((found = $.inArray('subject', this.env.coltypes)) >= 0)
-      this.set_env('subject_col', found);
+      this.env.subject_col = found;
 
     this.command('save-pref', { name: 'list_cols', value: this.env.coltypes, session: 'list_attrib/columns' });
   };
@@ -1652,8 +1647,8 @@
     // merge flags over local message object
     $.extend(this.env.messages[uid], {
       deleted: flags.deleted?1:0,
-      replied: flags.replied?1:0,
-      unread: flags.unread?1:0,
+      replied: flags.answered?1:0,
+      unread: !flags.seen?1:0,
       forwarded: flags.forwarded?1:0,
       flagged: flags.flagged?1:0,
       has_children: flags.has_children?1:0,
@@ -1676,10 +1671,10 @@
       message = this.env.messages[uid],
       css_class = 'message'
         + (even ? ' even' : ' odd')
-        + (flags.unread ? ' unread' : '')
+        + (!flags.seen ? ' unread' : '')
         + (flags.deleted ? ' deleted' : '')
         + (flags.flagged ? ' flagged' : '')
-        + (flags.unread_children && !flags.unread && !this.env.autoexpand_threads ? ' unroot' : '')
+        + (flags.unread_children && flags.seen && !this.env.autoexpand_threads ? ' unroot' : '')
         + (message.selected ? ' selected' : ''),
       // for performance use DOM instead of jQuery here
       row = document.createElement('tr'),
@@ -1694,12 +1689,12 @@
       css_class += ' status';
       if (flags.deleted)
         css_class += ' deleted';
-      else if (flags.unread)
+      else if (!flags.seen)
         css_class += ' unread';
       else if (flags.unread_children > 0)
         css_class += ' unreadchildren';
     }
-    if (flags.replied)
+    if (flags.answered)
       css_class += ' replied';
     if (flags.forwarded)
       css_class += ' forwarded';
@@ -1767,7 +1762,7 @@
       else if (c == 'status') {
         if (flags.deleted)
           css_class = 'deleted';
-        else if (flags.unread)
+        else if (!flags.seen)
           css_class = 'unread';
         else if (flags.unread_children > 0)
           css_class = 'unreadchildren';
@@ -1777,8 +1772,17 @@
       }
       else if (c == 'threads')
         html = expando;
-      else if (c == 'subject')
+      else if (c == 'subject') {
+        if (bw.ie)
+          col.onmouseover = function() { rcube_webmail.long_subject_title_ie(this, message.depth+1); };
         html = tree + cols[c];
+      }
+      else if (c == 'priority') {
+        if (flags.prio > 0 && flags.prio < 6)
+          html = '<span class="prio'+flags.prio+'">&nbsp;</span>';
+        else
+          html = '&nbsp;';
+      }
       else
         html = cols[c];
 
@@ -1988,7 +1992,7 @@
     if (mbox != this.env.mailbox || (mbox == this.env.mailbox && !page && !sort))
       url += '&_refresh=1';
 
-    this.select_folder(mbox, this.env.mailbox);
+    this.select_folder(mbox);
     this.env.mailbox = mbox;
 
     // load message list remotely
@@ -2052,8 +2056,7 @@
       new_row = tbody.firstChild;
 
     while (new_row) {
-      if (new_row.nodeType == 1 && (r = this.message_list.rows[new_row.uid])
-	    && r.unread_children) {
+      if (new_row.nodeType == 1 && (r = this.message_list.rows[new_row.uid]) && r.unread_children) {
 	    this.message_list.expand_all(r);
 	    this.set_unread_children(r.uid);
       }
@@ -2493,7 +2496,7 @@
     // if there is a trash mailbox defined and we're not currently in it
     else {
       // if shift was pressed delete it immediately
-      if (list && list.shiftkey) {
+      if (list && list.modkey == SHIFT_KEY) {
         if (confirm(this.get_label('deletemessagesconfirm')))
           this.permanently_remove_messages();
       }
@@ -2796,14 +2799,15 @@
 
   this.expunge_mailbox = function(mbox)
   {
-    var lock = false,
-      url = '_mbox='+urlencode(mbox);
+    var lock, url = '_mbox='+urlencode(mbox);
 
     // lock interface if it's the active mailbox
     if (mbox == this.env.mailbox) {
-       lock = this.set_busy(true, 'loading');
-       url += '&_reload=1';
-     }
+      lock = this.set_busy(true, 'loading');
+      url += '&_reload=1';
+      if (this.env.search_request)
+        url += '&_search='+this.env.search_request;
+    }
 
     // send request to server
     this.http_post('expunge', url, lock);
@@ -3258,11 +3262,21 @@
       return false;
 
     // get file input field, count files on capable browser
-    var field = $('input[type=file]', form).get(0),
+    var i, size = 0, field = $('input[type=file]', form).get(0),
       files = field.files ? field.files.length : field.value ? 1 : 0;
 
     // create hidden iframe and post upload form
     if (files) {
+      // check file size
+      if (field.files && this.env.max_filesize && this.env.filesizeerror) {
+        for (i=0; i<files; i++)
+          size += field.files[i].size;
+        if (size && size > this.env.max_filesize) {
+          this.display_message(this.env.filesizeerror, 'error');
+          return;
+        }
+      }
+
       var frame_name = this.async_upload_form(form, 'upload', function(e) {
         var d, content = '';
         try {
@@ -3434,13 +3448,12 @@
     if (this.gui_objects.qsearchbox)
       this.gui_objects.qsearchbox.value = '';
 
-    if (this.env.qsearch) {
-      this.set_busy(this.env.qsearch.lock, false);
-      this.env.qsearch.request.abort();
-    }
+    if (this.env.qsearch)
+      this.abort_request(this.env.qsearch);
 
     this.env.qsearch = null;
     this.env.search_request = null;
+    this.env.search_id = null;
   };
 
   this.sent_successfully = function(type, msg)
@@ -3498,7 +3511,7 @@
 
       case 27:  // escape
         this.ksearch_hide();
-        break;
+        return;
 
       case 37:  // left
       case 39:  // right
@@ -3528,7 +3541,7 @@
 
   this.insert_recipient = function(id)
   {
-    if (!this.env.contacts[id] || !this.ksearch_input)
+    if (id === null || !this.env.contacts[id] || !this.ksearch_input)
       return;
 
     // get cursor pos
@@ -3613,6 +3626,8 @@
     var old_value = this.ksearch_value;
     this.ksearch_value = q;
 
+    this.ksearch_destroy();
+
     // ...string is empty
     if (!q.length)
       return;
@@ -3620,8 +3635,6 @@
     // ...new search value contains old one and previous search result was empty
     if (old_value && old_value.length && this.env.contacts && !this.env.contacts.length && q.indexOf(old_value) == 0)
       return;
-
-    this.ksearch_destroy();
 
     var i, lock, source, xhr, reqid = new Date().getTime(),
       threads = props && props.threads ? props.threads : 1,
@@ -3691,7 +3704,7 @@
         li.innerHTML = text.replace(new RegExp('('+RegExp.escape(s_val)+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>');
         li.onmouseover = function(){ ref.ksearch_select(this); };
         li.onmouseup = function(){ ref.ksearch_click(this) };
-        li._rcm_id = i;
+        li._rcm_id = this.env.contacts.length + i;
         ul.appendChild(li);
         maxlen -= 1;
       }
@@ -3760,10 +3773,8 @@
     if (!ac)
       return;
 
-    for (i=0, len=ac.locks.length; i<len; i++) {
-      this.hide_message(ac.locks[i]); // hide loading message
-      ac.requests[i].abort(); // abort ajax request
-    }
+    for (i=0, len=ac.locks.length; i<len; i++)
+      this.abort_request({request: ac.requests[i], lock: ac.locks[i]});
 
     this.ksearch_data = null;
   }
@@ -3817,7 +3828,7 @@
 
   this.list_contacts = function(src, group, page)
   {
-    var add_url = '',
+    var folder, add_url = '',
       target = window;
 
     if (!src)
@@ -3833,7 +3844,12 @@
     else if (group != this.env.group)
       page = this.env.current_page = 1;
 
-    this.select_folder((group ? 'G'+src+group : src), (this.env.group ? 'G'+this.env.source+this.env.group : this.env.source));
+    if (this.env.search_id)
+      folder = 'S'+this.env.search_id;
+    else
+      folder = group ? 'G'+src+group : src;
+
+    this.select_folder(folder);
 
     this.env.source = src;
     this.env.group = group;
@@ -3878,8 +3894,8 @@
     if (group)
       url += '&_gid='+group;
 
-    // also send search request to get the right messages 
-    if (this.env.search_request) 
+    // also send search request to get the right messages
+    if (this.env.search_request)
       url += '&_search='+this.env.search_request;
 
     this.http_request('list', url, lock);
@@ -3996,11 +4012,18 @@
   };
 
   // update a contact record in the list
-  this.update_contact_row = function(cid, cols_arr, newcid)
+  this.update_contact_row = function(cid, cols_arr, newcid, source)
   {
     var c, row, list = this.contact_list;
 
     cid = String(cid).replace(this.identifier_expr, '_');
+
+    // when in searching mode, concat cid with the source name
+    if (!list.rows[cid]) {
+      cid = cid+'-'+source;
+      if (newcid)
+        newcid = newcid+'-'+source;
+    }
 
     if (list.rows[cid] && (row = list.rows[cid].obj)) {
       for (c=0; c<cols_arr.length; c++)
@@ -4073,19 +4096,7 @@
 
   this.group_create = function()
   {
-    if (!this.gui_objects.folderlist)
-      return;
-
-    if (!this.name_input) {
-      this.name_input = $('<input>').attr('type', 'text');
-      this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); });
-      this.name_input_li = $('<li>').addClass('contactgroup').append(this.name_input);
-
-      var li = this.get_folder_li(this.env.source)
-      this.name_input_li.insertAfter(li);
-    }
-
-    this.name_input.select().focus();
+    this.add_input_row('contactgroup');
   };
 
   this.group_rename = function()
@@ -4131,18 +4142,40 @@
     this.list_contacts(prop.source, 0);
   };
 
+  // @TODO: maybe it would be better to use popup instead of inserting input to the list?
+  this.add_input_row = function(type)
+  {
+    if (!this.gui_objects.folderlist)
+      return;
+
+    if (!this.name_input) {
+      this.name_input = $('<input>').attr('type', 'text').data('tt', type);
+      this.name_input.bind('keydown', function(e){ return rcmail.add_input_keydown(e); });
+      this.name_input_li = $('<li>').addClass(type).append(this.name_input);
+
+      var li = type == 'contactsearch' ? $('li:last', this.gui_objects.folderlist) : this.get_folder_li(this.env.source);
+      this.name_input_li.insertAfter(li);
+    }
+
+    this.name_input.select().focus();
+  };
+
   // handler for keyboard events on the input field
   this.add_input_keydown = function(e)
   {
-    var key = rcube_event.get_keycode(e);
+    var key = rcube_event.get_keycode(e),
+      input = $(e.target), itype = input.data('tt');
 
     // enter
     if (key == 13) {
-      var newname = this.name_input.val();
+      var newname = input.val();
 
       if (newname) {
         var lock = this.set_busy(true, 'loading');
-        if (this.env.group_renaming)
+
+        if (itype == 'contactsearch')
+          this.http_post('search-create', '_search='+urlencode(this.env.search_request)+'&_name='+urlencode(newname), lock);
+        else if (this.env.group_renaming)
           this.http_post('group-rename', '_source='+urlencode(this.env.source)+'&_gid='+urlencode(this.env.group)+'&_name='+urlencode(newname), lock);
         else
           this.http_post('group-create', '_source='+urlencode(this.env.source)+'&_name='+urlencode(newname), lock);
@@ -4431,7 +4464,7 @@
   this.set_photo_actions = function(id)
   {
     var n, buttons = this.buttons['upload-photo'];
-    for (n=0; n < buttons.length; n++)
+    for (n=0; buttons && n < buttons.length; n++)
       $('#'+buttons[n].id).html(this.get_label(id == '-del-' ? 'addphoto' : 'replacephoto'));
 
     $('#ff_photo').val(id);
@@ -4458,11 +4491,106 @@
   // unselect directory/group
   this.unselect_directory = function()
   {
-    if (this.env.address_sources.length > 1 || this.env.group != '') {
-      this.select_folder('', (this.env.group ? 'G'+this.env.source+this.env.group : this.env.source));
-      this.env.group = '';
-      this.env.source = '';
+    this.select_folder('');
+    this.enable_command('search-delete', false);
+  };
+
+  // callback for creating a new saved search record
+  this.insert_saved_search = function(name, id)
+  {
+    this.reset_add_input();
+
+    var key = 'S'+id,
+      link = $('<a>').attr('href', '#')
+        .attr('rel', id)
+        .click(function() { return rcmail.command('listsearch', id, this); })
+        .html(name),
+      li = $('<li>').attr({id: 'rcmli'+key.replace(this.identifier_expr, '_'), 'class': 'contactsearch'})
+        .append(link),
+      prop = {name:name, id:id, li:li[0]};
+
+    this.add_saved_search_row(prop, li);
+    this.select_folder('S'+id);
+    this.enable_command('search-delete', true);
+    this.env.search_id = id;
+
+    this.triggerEvent('abook_search_insert', prop);
+  };
+
+  // add saved search row to the list, with sorting
+  this.add_saved_search_row = function(prop, li, reloc)
+  {
+    var row, sibling, name = prop.name.toUpperCase();
+
+    // When renaming groups, we need to remove it from DOM and insert it in the proper place
+    if (reloc) {
+      row = li.clone(true);
+      li.remove();
     }
+    else
+      row = li;
+
+    $('li[class~="contactsearch"]', this.gui_objects.folderlist).each(function(i, elem) {
+      if (!sibling)
+        sibling = this.previousSibling;
+
+      if (name >= $(this).text().toUpperCase())
+        sibling = elem;
+      else
+        return false;
+    });
+
+    if (sibling)
+      row.insertAfter(sibling);
+    else
+      row.appendTo(this.gui_objects.folderlist);
+  };
+
+  // creates an input for saved search name
+  this.search_create = function()
+  {
+    this.add_input_row('contactsearch');
+  };
+
+  this.search_delete = function()
+  {
+    if (this.env.search_request) {
+      var lock = this.set_busy(true, 'savedsearchdeleting');
+      this.http_post('search-delete', '_sid='+urlencode(this.env.search_id), lock);
+    }
+  };
+
+  // callback from server upon search-delete command
+  this.remove_search_item = function(id)
+  {
+    var li, key = 'S'+id;
+    if ((li = this.get_folder_li(key))) {
+      this.triggerEvent('search_delete', { id:id, li:li });
+
+      li.parentNode.removeChild(li);
+    }
+
+    this.env.search_id = null;
+    this.env.search_request = null;
+    this.list_contacts_clear();
+    this.reset_qsearch();
+    this.enable_command('search-delete', 'search-create', false);
+  };
+
+  this.listsearch = function(id)
+  {
+    var folder, lock = this.set_busy(true, 'searching');
+
+    if (this.contact_list) {
+      this.list_contacts_clear();
+    }
+
+    this.reset_qsearch();
+    this.select_folder('S'+id);
+
+    // reset vars
+    this.env.current_page = 1;
+    this.http_request('search', '_sid='+urlencode(id), lock);
   };
 
 
@@ -4552,7 +4680,6 @@
     $('#mailboxroot')
       .mouseover(function(){ p.focus_subscription(this.id); })
       .mouseout(function(){ p.unfocus_subscription(this.id); })
-      .mouseup(function(){ if (p.drag_active) p.subscription_move_folder(); });
   };
 
   this.focus_subscription = function(id)
@@ -4563,22 +4690,16 @@
 
     if (this.drag_active && this.env.mailbox && (row = document.getElementById(id)))
       if (this.env.subscriptionrows[id] &&
-          (folder = this.env.subscriptionrows[id][0])) {
+          (folder = this.env.subscriptionrows[id][0]) !== null
+      ) {
         if (this.check_droptarget(folder) &&
             !this.env.subscriptionrows[this.get_folder_row_id(this.env.mailbox)][2] &&
             (folder != this.env.mailbox.replace(reg, '')) &&
-            (!folder.match(new RegExp('^'+RegExp.escape(this.env.mailbox+this.env.delimiter))))) {
-          this.set_env('dstfolder', folder);
+            (!folder.match(new RegExp('^'+RegExp.escape(this.env.mailbox+this.env.delimiter))))
+        ) {
+          this.env.dstfolder = folder;
           $(row).addClass('droptarget');
         }
-      }
-      else if (id == 'mailboxroot') {
-        this.set_env('dstfolder', '');
-        $(row).addClass('droptarget');
-      }
-      else if (this.env.mailbox.match(new RegExp(delim))) {
-        this.set_env('dstfolder', this.env.delimiter);
-        $(this.subscription_list.frame).addClass('droptarget');
       }
   };
 
@@ -4586,7 +4707,7 @@
   {
     var row = $('#'+id);
 
-    this.set_env('dstfolder', null);
+    this.env.dstfolder = null;
     if (this.env.subscriptionrows[id] && row[0])
       row.removeClass('droptarget');
     else
@@ -4600,7 +4721,7 @@
     if (list && (id = list.get_single_selection()) &&
         (folder = this.env.subscriptionrows['rcmrow'+id])
     ) {
-      this.set_env('mailbox', folder[0]);
+      this.env.mailbox = folder[0];
       this.show_folder(folder[0]);
       this.enable_command('delete-folder', !folder[2]);
     }
@@ -4616,12 +4737,12 @@
     var delim = RegExp.escape(this.env.delimiter),
       reg = RegExp('['+delim+']?[^'+delim+']+$');
 
-    if (this.env.mailbox && this.env.dstfolder && (this.env.dstfolder != this.env.mailbox) &&
+    if (this.env.mailbox && this.env.dstfolder !== null && (this.env.dstfolder != this.env.mailbox) &&
         (this.env.dstfolder != this.env.mailbox.replace(reg, ''))
     ) {
       reg = new RegExp('[^'+delim+']*['+delim+']', 'g');
       var basename = this.env.mailbox.replace(reg, ''),
-        newname = this.env.dstfolder==this.env.delimiter ? basename : this.env.dstfolder+this.env.delimiter+basename;
+        newname = this.env.dstfolder === '' ? basename : this.env.dstfolder+this.env.delimiter+basename;
 
       if (newname != this.env.mailbox) {
         this.http_post('rename-folder', '_folder_oldname='+urlencode(this.env.mailbox)+'&_folder_newname='+urlencode(newname), this.set_busy(true, 'foldermoving'));
@@ -4909,6 +5030,34 @@
   /*********           GUI functionality           *********/
   /*********************************************************/
 
+  var init_button = function(cmd, prop)
+  {
+    var elm = document.getElementById(prop.id);
+    if (!elm)
+      return;
+
+    var preload = false;
+    if (prop.type == 'image') {
+      elm = elm.parentNode;
+      preload = true;
+    }
+
+    elm._command = cmd;
+    elm._id = prop.id;
+    if (prop.sel) {
+      elm.onmousedown = function(e){ return rcmail.button_sel(this._command, this._id); };
+      elm.onmouseup = function(e){ return rcmail.button_out(this._command, this._id); };
+      if (preload)
+        new Image().src = prop.sel;
+    }
+    if (prop.over) {
+      elm.onmouseover = function(e){ return rcmail.button_over(this._command, this._id); };
+      elm.onmouseout = function(e){ return rcmail.button_out(this._command, this._id); };
+      if (preload)
+        new Image().src = prop.over;
+    }
+  };
+
   // enable/disable buttons for page shifting
   this.set_page_buttons = function()
   {
@@ -4924,31 +5073,7 @@
         continue;
 
       for (var i=0; i< this.buttons[cmd].length; i++) {
-        var prop = this.buttons[cmd][i];
-        var elm = document.getElementById(prop.id);
-        if (!elm)
-          continue;
-
-        var preload = false;
-        if (prop.type == 'image') {
-          elm = elm.parentNode;
-          preload = true;
-        }
-
-        elm._command = cmd;
-        elm._id = prop.id;
-        if (prop.sel) {
-          elm.onmousedown = function(e){ return rcmail.button_sel(this._command, this._id); };
-          elm.onmouseup = function(e){ return rcmail.button_out(this._command, this._id); };
-          if (preload)
-            new Image().src = prop.sel;
-        }
-        if (prop.over) {
-          elm.onmouseover = function(e){ return rcmail.button_over(this._command, this._id); };
-          elm.onmouseout = function(e){ return rcmail.button_out(this._command, this._id); };
-          if (preload)
-            new Image().src = prop.over;
-        }
+        init_button(cmd, this.buttons[cmd][i]);
       }
     }
   };
@@ -5215,20 +5340,20 @@
   };
 
   // mark a mailbox as selected and set environment variable
-  this.select_folder = function(name, old, prefix)
+  this.select_folder = function(name, prefix)
   {
     if (this.gui_objects.folderlist) {
       var current_li, target_li;
 
-      if ((current_li = this.get_folder_li(old, prefix))) {
-        $(current_li).removeClass('selected').addClass('unfocused');
+      if ((current_li = $('li.selected', this.gui_objects.folderlist))) {
+        current_li.removeClass('selected').addClass('unfocused');
       }
       if ((target_li = this.get_folder_li(name, prefix))) {
         $(target_li).removeClass('unfocused').addClass('selected');
       }
 
       // trigger event hook
-      this.triggerEvent('selectfolder', { folder:name, old:old, prefix:prefix });
+      this.triggerEvent('selectfolder', { folder:name, prefix:prefix });
     }
   };
 
@@ -5294,14 +5419,14 @@
     this.env.status_col = null;
 
     if ((n = $.inArray('subject', this.env.coltypes)) >= 0) {
-      this.set_env('subject_col', n);
+      this.env.subject_col = n;
       if (list)
         list.subject_col = n;
     }
     if ((n = $.inArray('flag', this.env.coltypes)) >= 0)
-      this.set_env('flagged_col', n);
+      this.env.flagged_col = n;
     if ((n = $.inArray('status', this.env.coltypes)) >= 0)
-      this.set_env('status_col', n);
+      this.env.status_col = n;
 
     if (list)
       list.init_header();
@@ -5561,7 +5686,7 @@
     var base = this.env.comm_path;
 
     // overwrite task name
-    if (query._action.match(/([a-z]+)\/([a-z-_]+)/)) {
+    if (query._action.match(/([a-z]+)\/([a-z0-9-_.]+)/)) {
       query._action = RegExp.$2;
       base = base.replace(/\_task=[a-z]+/, '_task='+RegExp.$1);
     }
@@ -5662,6 +5787,15 @@
       success: function(data){ ref.http_response(data); },
       error: function(o, status, err) { rcmail.http_error(o, status, err, lock); }
     });
+  };
+
+  // aborts ajax request
+  this.abort_request = function(r)
+  {
+    if (r.request)
+      r.request.abort();
+    if (r.lock)
+      this.set_busy(false, null, r.lock);
   };
 
   // handle HTTP response
@@ -5766,6 +5900,8 @@
           this.enable_command('export', (this.contact_list && this.contact_list.rowcount > 0));
 
           if (response.action == 'list' || response.action == 'search') {
+            this.enable_command('search-create', this.env.source == '');
+            this.enable_command('search-delete', this.env.search_id);
             this.update_group_commands();
             this.triggerEvent('listupdate', { folder:this.env.source, rowcount:this.contact_list.rowcount });
           }
@@ -5830,11 +5966,12 @@
     // handle upload errors, parsing iframe content in onload
     $(frame_name).bind('load', {ts:ts}, onload);
 
-    form.target = frame_name;
-    form.action = this.url(action, { _id:this.env.compose_id||'', _uploadid:ts });
-    form.setAttribute('method', 'POST');
-    form.setAttribute('enctype', 'multipart/form-data');
-    form.submit();
+    $(form).attr({
+        target: frame_name,
+        action: this.url(action, { _id:this.env.compose_id||'', _uploadid:ts }),
+        method: 'POST'})
+      .attr(form.encoding ? 'encoding' : 'enctype', 'multipart/form-data')
+      .submit();
 
     return frame_name;
   };
@@ -5979,6 +6116,23 @@
   }
 };
 
+rcube_webmail.long_subject_title_ie = function(elem, indent)
+{
+  if (!elem.title) {
+    var $elem = $(elem),
+      txt = $.trim($elem.text()),
+      tmp = $('<span>').text(txt)
+        .css({'position': 'absolute', 'float': 'left', 'visibility': 'hidden',
+          'font-size': $elem.css('font-size'), 'font-weight': $elem.css('font-weight')})
+        .appendTo($('body')),
+      w = tmp.width();
+
+    tmp.remove();
+    if (w + indent * 15 > $elem.width())
+      elem.title = txt;
+  }
+};
+
 // copy event engine prototype
 rcube_webmail.prototype.addEventListener = rcube_event_engine.prototype.addEventListener;
 rcube_webmail.prototype.removeEventListener = rcube_event_engine.prototype.removeEventListener;

--
Gitblit v1.9.1