Index: program/js/app.js
===================================================================
RCS file: /cvsroot/roundcubemail/roundcubemail/program/js/app.js,v
retrieving revision 1.27
diff -u -r1.27 app.js
--- program/js/app.js	13 Jan 2006 17:14:38 -0000	1.27
+++ program/js/app.js	16 Jan 2006 05:42:37 -0000
@@ -13,6 +13,9 @@
   $Id: app.js,v 1.27 2006/01/13 17:14:38 roundcube Exp $
 */
 
+const CONTROL_KEY = 1;
+const SHIFT_KEY = 2;
+const SHIFT_CONTROL_KEY = 3;
 
 var rcube_webmail_client;
 
@@ -997,11 +1000,30 @@
     if (this.dont_select)
       return false;
 
+    // selects currently unselected row
     if (!this.in_selection_before)
-      {
-      var ctrl = this.check_ctrlkey(e);
-      this.select(id, ctrl);
+    {
+      var mod_key = this.get_modifier(e);
+      if (!mod_key) {
+        this.select(id, false);
+        this.last_selected = id;
+      } else {
+        switch (mod_key) {
+          case SHIFT_KEY: { this.shift_select(id); break; }
+          case CONTROL_KEY: { 
+            this.select(id, true); 
+            this.last_selected = id;
+            break; 
+            }
+          case CONTROL_SHIFT_KEY: {break;}
+          default: {
+            this.select(id, false); 
+            this.last_selected = id;
+            break;
+            }
+        }
       }
+    }
     
     if (this.selection.length)
       {
@@ -1017,7 +1039,7 @@
   // onmouseup-handler of message list row
   this.click_row = function(e, id)
     {
-    var shift = this.check_shiftkey(e);
+    var mod_key = this.get_modifier(e);
     
     // don't do anything (another action processed before)
     if (this.dont_select)
@@ -1026,16 +1048,33 @@
       return false;
       }
     
-    if (!this.drag_active && this.in_selection_before==id)
-      {
-      this.select(id, (shift && this.task!='settings'));
+    // unselects currently selected row    
+    if (!this.drag_active && this.in_selection_before==id) {
+      if (!mod_key) {
+        this.last_selected = id;
+        this.select(id, false);
+      } else {
+        switch (mod_key) {
+          case SHIFT_KEY: { this.shift_select(id); break; }
+          case CONTROL_KEY: { 
+            this.last_selected = id;
+            this.select(id, (this.task!='settings')); 
+            break; 
+            }
+          case CONTROL_SHIFT_KEY: {break;}
+          default: {
+            this.select(id, false); 
+            this.last_selected = id;
+            break; 
+            }
+        }        
       }
-    
+    }
     this.drag_start = false;
     this.in_selection_before = false;
         
     // row was double clicked
-    if (this.task=='mail' && this.list_rows && this.list_rows[id].clicked && !shift)
+    if (this.task=='mail' && this.list_rows && this.list_rows[id].clicked)
       {
       this.show_message(id);
       return false;
@@ -1132,7 +1171,6 @@
         this.selection = a_pre.concat(a_post);
         this.set_classname(this.list_rows[id].obj, 'selected', false);
         }
-        
       selected = (this.selection.length==1);
       }
 
@@ -1150,6 +1188,27 @@
     };
 
 
+// select all rows from the last selected row to the current one, while deselecting all other rows
+  this.shift_select = function(id)
+  { 
+    var from_rowIndex = this.list_rows[this.last_selected].obj.rowIndex;
+    var to_rowIndex = this.list_rows[id].obj.rowIndex;
+        
+    var i = ((from_rowIndex < to_rowIndex)? from_rowIndex : to_rowIndex);
+    var j = ((from_rowIndex > to_rowIndex)? from_rowIndex : to_rowIndex);
+        
+    for (var n in this.list_rows) {
+      if ((this.list_rows[n].obj.rowIndex >= i) && (this.list_rows[n].obj.rowIndex <= j)) {
+        if (!this.in_selection(n))
+          this.select(n, true);
+      } else {
+        if  (this.in_selection(n))
+          this.select(n,true);
+      }
+    }
+  };
+  
+
   this.clear_selection = function()
     {
     for(var n=0; n<this.selection.length; n++)
@@ -2809,6 +2868,26 @@
       return false;
     }
 
+
+// returns modifier key (constants defined at top of file)
+  this.get_modifier = function(e)
+    {
+    var opcode = 0;
+    if (e = e || window.event)
+    {
+      opcode += (e.ctrlKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY);
+	  return opcode;
+    }
+    if (e.cancelBubble)
+    {
+      e.cancelBubble = true;
+      e.returnValue = false;
+    }
+    else if (e.preventDefault)
+      e.preventDefault();
+  }
+
+
   this.get_mouse_pos = function(e)
     {
     if(!e) e = window.event;
