summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthomascube <thomas@roundcube.net>2006-09-24 20:15:51 +0000
committerthomascube <thomas@roundcube.net>2006-09-24 20:15:51 +0000
commit6b47de3f49e880f08fa4a9226e70d18129095306 (patch)
tree292ae8ca9f101e17dfcd0494eceb0965669a5370
parent63583192f238dfb49152f6f470988d36366aa44b (diff)
Partial client re-write with a common list class
-rw-r--r--CHANGELOG8
-rw-r--r--program/include/main.inc2
-rw-r--r--program/js/app.js1267
-rw-r--r--program/js/common.js123
-rw-r--r--program/js/list.js704
-rw-r--r--program/steps/addressbook/edit.inc2
-rw-r--r--program/steps/addressbook/func.inc1
-rw-r--r--program/steps/addressbook/save.inc22
-rw-r--r--program/steps/mail/func.inc1
-rw-r--r--program/steps/settings/identities.inc1
-rwxr-xr-xskins/default/common.css12
11 files changed, 1202 insertions, 941 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 3319d38c1..4144b5a6d 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,14 @@
CHANGELOG RoundCube Webmail
---------------------------
+2006/09/24 (thomasb)
+----------
+- Partial client re-write with a common list class
+- Re-enabled multi select of contacts (Bug #1484017)
+- Enable contact editing right after creation (Bug #1459641)
+- Updated Hungarian, Estonian and Traditional Chinese localization
+
+
2006/09/19 (thomasb)
----------
- Correct UTF-7 to UTF-8 conversion if mbstring is not available
diff --git a/program/include/main.inc b/program/include/main.inc
index c6e9857b0..b2e83b767 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -365,7 +365,7 @@ function load_gui()
// add common javascripts
$javascript = "var $JS_OBJECT_NAME = new rcube_webmail();\n";
- $javascript .= "$JS_OBJECT_NAME.set_env('comm_path', '$COMM_PATH');\n";
+ $javascript .= sprintf("%s.set_env('comm_path', '%s');\n", $JS_OBJECT_NAME, str_replace('&amp;', '&', $COMM_PATH));
if (isset($CONFIG['javascript_config'] )){
foreach ($CONFIG['javascript_config'] as $js_config_var){
diff --git a/program/js/app.js b/program/js/app.js
index eedcd13e7..52050a9be 100644
--- a/program/js/app.js
+++ b/program/js/app.js
@@ -3,21 +3,19 @@
| RoundCube Webmail Client Script |
| |
| This file is part of the RoundCube Webmail client |
- | Copyright (C) 2005, RoundCube Dev, - Switzerland |
+ | Copyright (C) 2005-2006, RoundCube Dev, - Switzerland |
| Licensed under the GNU GPL |
| |
+-----------------------------------------------------------------------+
| Authors: Thomas Bruederli <roundcube@gmail.com> |
| Charles McNulty <charles@charlesmcnulty.com> |
+-----------------------------------------------------------------------+
-
+ | Requires: common.js, list.js |
+ +-----------------------------------------------------------------------+
+
$Id$
*/
-// Constants
-var CONTROL_KEY = 1;
-var SHIFT_KEY = 2;
-var CONTROL_SHIFT_KEY = 3;
var rcube_webmail_client;
@@ -28,9 +26,6 @@ function rcube_webmail()
this.buttons = new Object();
this.gui_objects = new Object();
this.commands = new Object();
- this.selection = new Array();
- this.last_selected = 0;
- this.in_message_list = false;
// create public reference to myself
rcube_webmail_client = this;
@@ -93,12 +88,13 @@ function rcube_webmail()
// initialize webmail client
this.init = function()
{
+ var p = this;
this.task = this.env.task;
// check browser
if (!bw.dom || !bw.xmlhttp_test())
{
- location.href = this.env.comm_path+'&_action=error&_code=0x199';
+ this.goto_url('error', '_code=0x199');
return;
}
@@ -116,13 +112,26 @@ function rcube_webmail()
switch (this.task)
{
case 'mail':
- var msg_list_frame = this.gui_objects.mailcontframe;
- var msg_list = this.gui_objects.messagelist;
- if (msg_list)
+ if (this.gui_objects.messagelist)
{
- msg_list_frame.onmousedown = function(e){return rcube_webmail_client.click_on_list(e);};
- this.init_messagelist(msg_list);
+ this.message_list = new rcube_list_widget(this.gui_objects.messagelist, {multiselect:true, draggable:true, keyboard:true, dblclick_time:this.dblclick_time});
+ this.message_list.row_init = function(o){ p.init_message_row(o); };
+ this.message_list.addEventListener('dblclick', function(o){ p.msglist_dbl_click(o); });
+ this.message_list.addEventListener('keypress', function(o){ p.msglist_keypress(o); });
+ this.message_list.addEventListener('select', function(o){ p.msglist_select(o); });
+ this.message_list.addEventListener('dragstart', function(o){ p.drag_active = true; });
+ this.message_list.addEventListener('dragend', function(o){ p.drag_active = false; });
+
+ this.message_list.init();
this.enable_command('toggle_status', true);
+
+ if (this.gui_objects.mailcontframe)
+ {
+ this.gui_objects.mailcontframe.onmousedown = function(e){ return p.click_on_list(e); };
+ document.onmouseup = function(e){ return p.doc_mouse_up(e); };
+ }
+ else
+ this.message_list.focus();
}
// enable mail commands
@@ -183,26 +192,36 @@ function rcube_webmail()
case 'addressbook':
- var contacts_list = this.gui_objects.contactslist;
- var ldap_contacts_list = this.gui_objects.ldapcontactslist;
+ if (this.gui_objects.contactslist)
+ {
+ this.contact_list = new rcube_list_widget(this.gui_objects.contactslist, {multiselect:true, draggable:false, keyboard:true});
+ this.contact_list.addEventListener('keypress', function(o){ p.contactlist_keypress(o); });
+ this.contact_list.addEventListener('select', function(o){ p.contactlist_select(o); });
+ this.contact_list.init();
- if (contacts_list)
- this.init_contactslist(contacts_list);
-
- if (ldap_contacts_list)
- this.init_ldapsearchlist(ldap_contacts_list);
+ if (this.env.cid)
+ this.contact_list.highlight_row(this.env.cid);
+
+ if (this.gui_objects.contactslist.parentNode)
+ {
+ this.gui_objects.contactslist.parentNode.onmousedown = function(e){ return p.click_on_list(e); };
+ document.onmouseup = function(e){ return p.doc_mouse_up(e); };
+ }
+ else
+ this.contact_list.focus();
+ }
this.set_page_buttons();
-
+
if (this.env.cid)
this.enable_command('show', 'edit', true);
if ((this.env.action=='add' || this.env.action=='edit') && this.gui_objects.editform)
this.enable_command('save', true);
-
+
this.enable_command('list', 'add', true);
- this.enable_command('ldappublicsearch', this.env.ldappublicsearch);
+ // this.enable_command('ldappublicsearch', this.env.ldappublicsearch);
break;
@@ -218,10 +237,17 @@ function rcube_webmail()
if (this.env.action=='folders')
this.enable_command('subscribe', 'unsubscribe', 'create-folder', 'rename-folder', 'delete-folder', true);
-
- var identities_list = this.gui_objects.identitieslist;
- if (identities_list)
- this.init_identitieslist(identities_list);
+
+ if (this.gui_objects.identitieslist)
+ {
+ this.identity_list = new rcube_list_widget(this.gui_objects.identitieslist, {multiselect:false, draggable:false, keyboard:false});
+ this.identity_list.addEventListener('select', function(o){ p.identity_select(o); });
+ this.identity_list.init();
+ this.identity_list.focus();
+
+ if (this.env.iid)
+ this.identity_list.highlight_row(this.env.iid);
+ }
break;
@@ -244,13 +270,6 @@ function rcube_webmail()
// enable basic commands
this.enable_command('logout', true);
- // disable browser's contextmenus
- // document.oncontextmenu = function(){ return false; }
-
- // load body click event
- document.onmousedown = function(){ return rcube_webmail_client.reset_click(); };
- document.onkeydown = function(e){ return rcube_webmail_client.key_pressed(e, msg_list_frame); };
-
// flag object as complete
this.loaded = true;
@@ -273,154 +292,25 @@ function rcube_webmail()
}
- // reset last clicked if user clicks on anything other than the message table
- this.reset_click = function()
- {
- var id;
- this.in_message_list = false;
- for (var n=0; n<this.selection.length; n++)
- {
- id = this.selection[n];
- if (this.list_rows[id] && this.list_rows[id].obj)
- {
- this.set_classname(this.list_rows[id].obj, 'selected', false);
- this.set_classname(this.list_rows[id].obj, 'unfocused', true);
- }
- }
- };
-
- this.click_on_list = function(e)
- {
- if (!e)
- e = window.event;
-
- for (var n=0; n<this.selection.length; n++)
+ this.init_message_row = function(row)
+ {
+ var uid = row.uid;
+ if (uid && this.env.messages[uid])
{
- id = this.selection[n];
- if (this.list_rows[id].obj)
- {
- this.set_classname(this.list_rows[id].obj, 'selected', true);
- this.set_classname(this.list_rows[id].obj, 'unfocused', false);
- }
+ row.deleted = this.env.messages[uid].deleted;
+ row.unread = this.env.messages[uid].unread;
+ row.replied = this.env.messages[uid].replied;
}
- var mbox_li;
- if (mbox_li = this.get_mailbox_li())
- this.set_classname(mbox_li, 'unfocused', true);
-
- this.in_message_list = true;
- e.cancelBubble = true;
- };
-
- this.key_pressed = function(e, msg_list_frame) {
- if (this.in_message_list != true)
- return true;
- var keyCode = document.layers ? e.which : document.all ? event.keyCode : document.getElementById ? e.keyCode : 0;
- var mod_key = this.get_modifier(e);
- switch (keyCode) {
- case 13:
- this.command('show','',this);
- break;
- case 40:
- case 38:
- return this.use_arrow_key(keyCode, mod_key, msg_list_frame);
- break;
- case 46:
- return this.use_delete_key(keyCode, mod_key, msg_list_frame);
- break;
- default:
- return true;
- }
- return true;
- }
-
- this.use_arrow_key = function(keyCode, mod_key, msg_list_frame) {
- var scroll_to = 0;
- if (keyCode == 40) { // down arrow key pressed
- new_row = this.get_next_row();
- if (!new_row) return false;
- scroll_to = (Number(new_row.offsetTop) + Number(new_row.offsetHeight)) - Number(msg_list_frame.offsetHeight);
- } else if (keyCode == 38) { // up arrow key pressed
- new_row = this.get_prev_row();
- if (!new_row) return false;
- scroll_to = new_row.offsetTop;
- } else {return true;}
-
- this.select_row(new_row.uid,mod_key,true);
-
- if (((Number(new_row.offsetTop)) < (Number(msg_list_frame.scrollTop))) ||
- ((Number(new_row.offsetTop) + Number(new_row.offsetHeight)) > (Number(msg_list_frame.scrollTop) + Number(msg_list_frame.offsetHeight)))) {
- msg_list_frame.scrollTop = scroll_to;
- }
- return false;
- };
-
- this.use_delete_key = function(keyCode, mod_key, msg_list_frame){
- this.command('delete','',this);
- return false;
- }
-
- // get all message rows from HTML table and init each row
- this.init_messagelist = function(msg_list)
- {
- if (msg_list && msg_list.tBodies[0])
+ // set eventhandler to message icon
+ if ((row.icon = row.obj.cells[0].childNodes[0]) && row.icon.nodeName=='IMG')
{
-
- this.message_rows = new Array();
-
- var row;
- for(var r=0; r<msg_list.tBodies[0].childNodes.length; r++)
- {
- row = msg_list.tBodies[0].childNodes[r];
- while (row && (row.nodeType != 1 || row.style.display == 'none')) {
- row = row.nextSibling;
- r++;
- }
- //row = msg_list.tBodies[0].rows[r];
- if (row) this.init_message_row(row);
- }
- }
-
- // alias to common rows array
- this.list_rows = this.message_rows;
- };
-
-
- // make references in internal array and set event handlers
- this.init_message_row = function(row)
- {
- var uid, msg_icon;
-
- if (String(row.id).match(/rcmrow([0-9]+)/))
- {
- uid = RegExp.$1;
- row.uid = uid;
-
- this.message_rows[uid] = {id:row.id, obj:row,
- classname:row.className,
- deleted:this.env.messages[uid] ? this.env.messages[uid].deleted : null,
- unread:this.env.messages[uid] ? this.env.messages[uid].unread : null,
- replied:this.env.messages[uid] ? this.env.messages[uid].replied : null};
-
- // set eventhandlers to table row
- row.onmousedown = function(e){ return rcube_webmail_client.drag_row(e, this.uid); };
- row.onmouseup = function(e){ return rcube_webmail_client.click_row(e, this.uid); };
-
- if (document.all)
- row.onselectstart = function() { return false; };
-
- // set eventhandler to message icon
- if ((msg_icon = row.cells[0].childNodes[0]) && row.cells[0].childNodes[0].nodeName=='IMG')
- {
- msg_icon.id = 'msgicn_'+uid;
- msg_icon._row = row;
- msg_icon.onmousedown = function(e) { rcube_webmail_client.command('toggle_status', this); };
-
- // get message icon and save original icon src
- this.message_rows[uid].icon = msg_icon;
- }
+ var p = this;
+ row.icon.id = 'msgicn_'+row.uid;
+ row.icon._row = row.obj;
+ row.icon.onmousedown = function(e) { p.command('toggle_status', this); };
}
- };
+ };
// init message compose form: set focus and eventhandlers
@@ -455,7 +345,7 @@ function rcube_webmail()
else if (input_subject && input_subject.value=='')
input_subject.focus();
else if (input_message)
- this.set_caret2start(input_message); // input_message.focus();
+ this.set_caret2start(input_message);
// get summary of all field values
this.cmp_hash = this.compose_field_hash();
@@ -468,116 +358,21 @@ function rcube_webmail()
{
var handler = function(e){ return rcube_webmail_client.ksearch_keypress(e,this); };
var handler2 = function(e){ return rcube_webmail_client.ksearch_blur(e,this); };
-
+
if (bw.safari)
- {
obj.addEventListener('keydown', handler, false);
- // obj.addEventListener('blur', handler2, false);
- }
else if (bw.mz)
{
obj.addEventListener('keypress', handler, false);
obj.addEventListener('blur', handler2, false);
}
else if (bw.ie)
- {
obj.onkeydown = handler;
- //obj.attachEvent('onkeydown', handler);
- // obj.attachEvent('onblur', handler2, false);
- }
-
- obj.setAttribute('autocomplete', 'off');
- };
-
-
-
- // get all contact rows from HTML table and init each row
- this.init_contactslist = function(contacts_list)
- {
- if (contacts_list && contacts_list.tBodies[0])
- {
- this.contact_rows = new Array();
-
- var row;
- for(var r=0; r<contacts_list.tBodies[0].childNodes.length; r++)
- {
- row = contacts_list.tBodies[0].childNodes[r];
- this.init_table_row(row, 'contact_rows');
- }
- }
-
- // alias to common rows array
- this.list_rows = this.contact_rows;
-
- if (this.env.cid)
- this.highlight_row(this.env.cid);
- };
-
-
- // get all contact rows from HTML table and init each row
- this.init_ldapsearchlist = function(ldap_contacts_list)
- {
- if (ldap_contacts_list && ldap_contacts_list.tBodies[0])
- {
- this.ldap_contact_rows = new Array();
-
- var row;
- for(var r=0; r<ldap_contacts_list.tBodies[0].childNodes.length; r++)
- {
- row = ldap_contacts_list.tBodies[0].childNodes[r];
- this.init_table_row(row, 'ldap_contact_rows');
- }
- }
-
- // alias to common rows array
- this.list_rows = this.ldap_contact_rows;
- };
-
-
- // make references in internal array and set event handlers
- this.init_table_row = function(row, array_name)
- {
- var cid;
-
- if (String(row.id).match(/rcmrow([0-9]+)/))
- {
- cid = RegExp.$1;
- row.cid = cid;
- this[array_name][cid] = {id:row.id,
- obj:row,
- classname:row.className};
-
- // set eventhandlers to table row
- row.onmousedown = function(e) { rcube_webmail_client.in_selection_before=this.cid; return false; }; // fake for drag handler
- row.onmouseup = function(e){ return rcube_webmail_client.click_row(e, this.cid); };
- }
+ obj.setAttribute('autocomplete', 'off');
};
- // get all contact rows from HTML table and init each row
- this.init_identitieslist = function(identities_list)
- {
- if (identities_list && identities_list.tBodies[0])
- {
- this.identity_rows = new Array();
-
- var row;
- for(var r=0; r<identities_list.tBodies[0].childNodes.length; r++)
- {
- row = identities_list.tBodies[0].childNodes[r];
- this.init_table_row(row, 'identity_rows');
- }
- }
-
- // alias to common rows array
- this.list_rows = this.identity_rows;
-
- if (this.env.iid)
- this.highlight_row(this.env.iid);
- };
-
-
/*********************************************************/
/********* client command interface *********/
@@ -621,7 +416,7 @@ function rcube_webmail()
break;
case 'logout':
- location.href = this.env.comm_path+'&_action=logout';
+ this.goto_url('logout');
break;
// commands to switch task
@@ -639,11 +434,6 @@ function rcube_webmail()
if (this.env.search_request<0 || (this.env.search_request && props != this.env.mailbox))
this.reset_qsearch();
- // Reset message list header, unless returning from compose/read/etc
- // don't know what this is good for (thomasb, 2006/07/25)
- //if (this.env.mailbox != props && this.message_rows)
- // this.clear_message_list_header();
-
this.list_mailbox(props);
}
else if (this.task=='addressbook')
@@ -711,11 +501,8 @@ function rcube_webmail()
var uid = this.get_single_uid();
if (uid && (!this.env.uid || uid != this.env.uid))
{
- if (this.env.mailbox==this.env.drafts_mailbox)
- {
- this.set_busy(true);
- location.href = this.env.comm_path+'&_action=compose&_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox);
- }
+ if (this.env.mailbox == this.env.drafts_mailbox)
+ this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true);
else
this.show_message(uid);
}
@@ -730,6 +517,9 @@ function rcube_webmail()
case 'add':
if (this.task=='addressbook')
+ this.load_contact(0, 'add');
+
+ /* LDAP stuff, has to be re-written with new address book
if (!window.frames[this.env.contentframe].rcmail)
this.load_contact(0, 'add');
else
@@ -739,9 +529,10 @@ function rcube_webmail()
else
this.load_contact(0, 'add');
}
+ */
else if (this.task=='settings')
{
- this.clear_selection();
+ this.identity_list.clear_selection();
this.load_identity(0, 'add-identity');
}
break;
@@ -819,11 +610,11 @@ function rcube_webmail()
if (props._row.uid)
{
uid = props._row.uid;
- this.dont_select = true;
+ this.message_list.dont_select = true;
// toggle read/unread
- if (this.message_rows[uid].deleted) {
- flag = 'undelete';
- } else if (!this.message_rows[uid].unread)
+ if (this.message_list.rows[uid].deleted) {
+ flag = 'undelete';
+ } else if (!this.message_list.rows[uid].unread)
flag = 'unread';
}
@@ -836,12 +627,12 @@ function rcube_webmail()
break;
case 'load-attachment':
- var url = this.env.comm_path+'&_action=get&_mbox='+this.env.mailbox+'&_uid='+this.env.uid+'&_part='+props.part;
+ var qstring = '_mbox='+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 && find_in_array(props.mimetype, this.mimetypes)>=0)
{
- this.attachment_win = window.open(url+'&_frame=1', 'rcubemailattachment');
+ this.attachment_win = window.open(this.env.comm_path+'&_action=get'+url+'&_frame=1', 'rcubemailattachment');
if (this.attachment_win)
{
setTimeout(this.ref+'.attachment_win.focus()', 10);
@@ -849,27 +640,25 @@ function rcube_webmail()
}
}
- location.href = url;
+ this.goto_url('get', qstring+'&_download=1');
break;
case 'select-all':
- this.select_all(props);
+ this.message_list.select_all(props);
break;
case 'select-none':
- this.clear_selection();
+ this.message_list.clear_selection();
break;
case 'nextmessage':
if (this.env.next_uid)
this.show_message(this.env.next_uid);
- //location.href = this.env.comm_path+'&_action=show&_uid='+this.env.next_uid+'&_mbox='+this.env.mailbox;
break;
case 'previousmessage':
if (this.env.prev_uid)
this.show_message(this.env.prev_uid);
- //location.href = this.env.comm_path+'&_action=show&_uid='+this.env.prev_uid+'&_mbox='+this.env.mailbox;
break;
case 'checkmail':
@@ -894,14 +683,18 @@ function rcube_webmail()
// use contact_id passed as command parameter
if (props)
a_cids[a_cids.length] = props;
-
// get selected contacts
else
{
+ var selection = this.contact_list.get_selection();
+ for (var n=0; n<selection.length; n++)
+ a_cids[a_cids.length] = selection[n];
+
+ /* LDAP stuff, has to be re-written with new address book
if (!window.frames[this.env.contentframe].rcmail.selection.length)
{
- for (var n=0; n<this.selection.length; n++)
- a_cids[a_cids.length] = this.selection[n];
+ for (var n=0; n<selection.length; n++)
+ a_cids[a_cids.length] = selection[n];
}
else
{
@@ -910,6 +703,7 @@ function rcube_webmail()
for (var n=0; n<frameRcmail.selection.length; n++)
a_cids[a_cids.length] = frameRcmail.ldap_contact_rows[frameRcmail.selection[n]].obj.cells[1].innerHTML;
}
+ */
}
if (a_cids.length)
url += '&_to='+a_cids.join(',');
@@ -918,12 +712,13 @@ function rcube_webmail()
}
else if (props)
- url += '&_to='+encodeURIComponent(props);
+ url += '&_to='+urlencode(props);
// don't know if this is necessary...
url = url.replace(/&_framed=1/, "");
-
this.set_busy(true);
+
+ alert(url)
// need parent in case we are coming from the contact frame
if (this.env.framed)
@@ -997,19 +792,13 @@ function rcube_webmail()
case 'reply':
var uid;
if (uid = this.get_single_uid())
- {
- this.set_busy(true);
- location.href = this.env.comm_path+'&_action=compose&_reply_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(command=='reply-all' ? '&_all=1' : '');
- }
+ this.goto_url('compose', '_reply_uid='+uid+'&_mbox='+urlencode(this.env.mailbox)+(command=='reply-all' ? '&_all=1' : ''), true);
break;
case 'forward':
var uid;
if (uid = this.get_single_uid())
- {
- this.set_busy(true);
- location.href = this.env.comm_path+'&_action=compose&_forward_uid='+uid+'&_mbox='+urlencode(this.env.mailbox);
- }
+ this.goto_url('compose', '_forward_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true);
break;
case 'print':
@@ -1064,18 +853,18 @@ function rcube_webmail()
// user settings commands
case 'preferences':
- location.href = this.env.comm_path;
+ this.goto_url('');
break;
case 'identities':
- location.href = this.env.comm_path+'&_action=identities';
+ this.goto_url('identities');
break;
case 'delete-identity':
this.delete_identity();
case 'folders':
- location.href = this.env.comm_path+'&_action=folders';
+ this.goto_url('folders');
break;
case 'subscribe':
@@ -1201,6 +990,15 @@ function rcube_webmail()
/*********************************************************/
+ this.doc_mouse_up = function(e)
+ {
+ if (this.message_list)
+ this.message_list.blur();
+ else if (this.contact_list)
+ this.contact_list.blur();
+ };
+
+
// onmouseup handler for mailboxlist item
this.mbox_mouse_up = function(mbox)
{
@@ -1216,300 +1014,61 @@ function rcube_webmail()
};
- // onmousedown-handler of message list row
- this.drag_row = function(e, id)
+ this.click_on_list = function(e)
{
- this.in_selection_before = this.in_selection(id) ? id : false;
+ if (this.message_list)
+ this.message_list.focus();
+ else if (this.contact_list)
+ this.contact_list.focus();
- // don't do anything (another action processed before)
- if (this.dont_select)
- return false;
-
- // selects currently unselected row
- if (!this.in_selection_before && !this.list_rows[id].clicked)
- {
- var mod_key = this.get_modifier(e);
- this.select_row(id,mod_key,false);
- }
-
- if (this.selection.length)
- {
- this.drag_start = true;
- document.onmousemove = function(e){ return rcube_webmail_client.drag_mouse_move(e); };
- document.onmouseup = function(e){ return rcube_webmail_client.drag_mouse_up(e); };
- }
+ var mbox_li;
+ if (mbox_li = this.get_mailbox_li())
+ this.set_classname(mbox_li, 'unfocused', true);
- return false;
+ rcube_event.cancel(e);
};
- // onmouseup-handler of message list row
- this.click_row = function(e, id)
+ this.msglist_select = function(list)
{
- var mod_key = this.get_modifier(e);
-
- // don't do anything (another action processed before)
- if (this.dont_select)
+ var selected = list.selection.length==1;
+ if (this.env.mailbox == this.env.drafts_mailbox)
{
- this.dont_select = false;
- return false;
- }
-
- // unselects currently selected row
- if (!this.drag_active && this.in_selection_before==id && !this.list_rows[id].clicked)
- this.select_row(id,mod_key,false);
-
- 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 && this.in_selection(id))
- {
- if (this.env.mailbox==this.env.drafts_mailbox)
- {
- this.set_busy(true);
- location.href = this.env.comm_path+'&_action=compose&_draft_uid='+id+'&_mbox='+urlencode(this.env.mailbox);
- }
- else
- {
- this.show_message(id);
- }
- return false;
+ this.enable_command('show', selected);
+ this.enable_command('delete', 'moveto', list.selection.length>0 ? true : false);
}
- else if (this.task=='addressbook')
- {
- if (this.contact_rows && this.selection.length==1)
- {
- this.load_contact(this.selection[0], 'show', true);
- // change the text for the add contact button
- var links = parent.document.getElementById('abooktoolbar').getElementsByTagName('A');
- for (i = 0; i < links.length; i++)
- {
- var onclickstring = new String(links[i].onclick);
- if (onclickstring.search('\"add\"') != -1)
- links[i].title = this.env.newcontact;
- }
- }
- else if (this.contact_rows && this.contact_rows[id].clicked)
- {
- this.load_contact(id, 'show');
- return false;
- }
- else if (this.ldap_contact_rows && !this.ldap_contact_rows[id].clicked)
- {
- // clear selection
- parent.rcmail.clear_selection();
-
- // disable delete
- parent.rcmail.set_button('delete', 'pas');
-
- // change the text for the add contact button
- var links = parent.document.getElementById('abooktoolbar').getElementsByTagName('A');
- for (i = 0; i < links.length; i++)
- {
- var onclickstring = new String(links[i].onclick);
- if (onclickstring.search('\"add\"') != -1)
- links[i].title = this.env.addcontact;
- }
- }
- // handle double click event
- else if (this.ldap_contact_rows && this.selection.length==1 && this.ldap_contact_rows[id].clicked)
- this.command('compose', this.ldap_contact_rows[id].obj.cells[1].innerHTML);
- else if (this.env.contentframe)
- {
- var elm = document.getElementById(this.env.contentframe);
- elm.style.visibility = 'hidden';
- }
- }
- else if (this.task=='settings')
+ else
{
- if (this.selection.length==1)
- this.command('edit', this.selection[0]);
+ this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', selected);
+ this.enable_command('delete', 'moveto', list.selection.length>0 ? true : false);
}
-
- this.list_rows[id].clicked = true;
- setTimeout(this.ref+'.list_rows['+id+'].clicked=false;', this.dblclick_time);
-
- return false;
- };
-
+ };
- /*********************************************************/
- /********* (message) list functionality *********/
- /*********************************************************/
-
- // get next and previous rows that are not hidden
- this.get_next_row = function(){
- if (!this.list_rows) return false;
- var last_selected_row = this.list_rows[this.last_selected];
- var new_row = last_selected_row.obj.nextSibling;
- while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) {
- new_row = new_row.nextSibling;
- }
- return new_row;
- }
-
- this.get_prev_row = function(){
- if (!this.list_rows) return false;
- var last_selected_row = this.list_rows[this.last_selected];
- var new_row = last_selected_row.obj.previousSibling;
- while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none')) {
- new_row = new_row.previousSibling;
- }
- return new_row;
- }
-
- // highlight/unhighlight a row
- this.highlight_row = function(id, multiple)
+ this.msglist_dbl_click = function(list)
{
- var selected = false
-
- if (this.list_rows[id] && !multiple)
- {
- this.clear_selection();
- this.selection[0] = id;
- this.list_rows[id].obj.className += ' selected';
- selected = true;
- }
-
- else if (this.list_rows[id])
- {
- if (!this.in_selection(id)) // select row
- {
- this.selection[this.selection.length] = id;
- this.set_classname(this.list_rows[id].obj, 'selected', true);
- }
- else // unselect row
- {
- var p = find_in_array(id, this.selection);
- var a_pre = this.selection.slice(0, p);
- var a_post = this.selection.slice(p+1, this.selection.length);
- this.selection = a_pre.concat(a_post);
- this.set_classname(this.list_rows[id].obj, 'selected', false);
- this.set_classname(this.list_rows[id].obj, 'unfocused', false);
- }
- selected = (this.selection.length==1);
- }
-
- // enable/disable commands for message
- if (this.task=='mail')
- {
- if (this.env.mailbox==this.env.drafts_mailbox)
- {
- this.enable_command('show', selected);
- this.enable_command('delete', 'moveto', this.selection.length>0 ? true : false);
- }
- else
- {
- this.enable_command('show', 'reply', 'reply-all', 'forward', 'print', selected);
- this.enable_command('delete', 'moveto', this.selection.length>0 ? true : false);
- }
- }
- else if (this.task=='addressbook')
- {
- this.enable_command('edit', /*'print',*/ selected);
- this.enable_command('delete', 'compose', this.selection.length>0 ? true : false);
- }
+ var uid = list.get_single_selection();
+ if (uid && this.env.mailbox == this.env.drafts_mailbox)
+ this.goto_url('compose', '_draft_uid='+uid+'&_mbox='+urlencode(this.env.mailbox), true);
+ else if (uid)
+ this.show_message(uid);
};
-// selects or unselects the proper row depending on the modifier key pressed
- this.select_row = function(id,mod_key,with_mouse) {
- if (!mod_key) {
- this.shift_start = id;
- this.highlight_row(id, false);
- } else {
- switch (mod_key) {
- case SHIFT_KEY: {
- this.shift_select(id,false);
- break; }
- case CONTROL_KEY: {
- this.shift_start = id;
- if (!with_mouse)
- this.highlight_row(id, true);
- break;
- }
- case CONTROL_SHIFT_KEY: {
- this.shift_select(id,true);
- break;
- }
- default: {
- this.highlight_row(id, false);
- break;
- }
- }
- }
- if (this.last_selected != 0 && this.list_rows[this.last_selected])
- this.set_classname(this.list_rows[this.last_selected].obj, 'focused', false);
-
- this.last_selected = id;
- this.set_classname(this.list_rows[id].obj, 'focused', true);
- };
-
- this.shift_select = function(id, control) {
- var from_rowIndex = this.list_rows[this.shift_start].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);
-
- // iterate through the entire message list
- 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.highlight_row(n, true);
- } else {
- if (this.in_selection(n) && !control)
- this.highlight_row(n, true);
- }
- }
- };
-
-
- this.clear_selection = function()
+ this.msglist_keypress = function(list)
{
- for(var n=0; n<this.selection.length; n++)
- if (this.list_rows[this.selection[n]]) {
- this.set_classname(this.list_rows[this.selection[n]].obj, 'selected', false);
- this.set_classname(this.list_rows[this.selection[n]].obj, 'unfocused', false);
- }
- this.selection = new Array();
+ if (list.key_pressed == list.ENTER_KEY)
+ this.command('show');
+ else if (list.key_pressed == list.DELETE_KEY)
+ this.command('delete');
};
- // check if given id is part of the current selection
- this.in_selection = function(id)
- {
- for(var n in this.selection)
- if (this.selection[n]==id)
- return true;
-
- return false;
- };
-
- // select each row in list
- this.select_all = function(filter)
- {
- if (!this.list_rows || !this.list_rows.length)
- return false;
-
- // reset selection first
- this.clear_selection();
-
- for (var n in this.list_rows)
- {
- if (!filter || this.list_rows[n][filter]==true)
- {
- this.last_selected = n;
- this.highlight_row(n, true);
- }
- }
+ /*********************************************************/
+ /********* (message) list functionality *********/
+ /*********************************************************/
- return true;
- };
-
// when user doble-clicks on a row
this.show_message = function(id, safe)
@@ -1521,7 +1080,7 @@ function rcube_webmail()
target = window.frames[this.env.contentframe];
add_url = '&_framed=1';
}
-
+
if (safe)
add_url = '&_safe=1';
@@ -1574,7 +1133,7 @@ function rcube_webmail()
page = 1;
add_url += '&_refresh=1';
this.env.current_page = page;
- this.clear_selection();
+ this.message_list.clear_selection();
}
// also send search request to get the right messages
@@ -1609,7 +1168,7 @@ function rcube_webmail()
this.list_mailbox_remote = function(mbox, page, add_url)
{
// clear message list first
- this.clear_message_list();
+ this.message_list.clear();
// send request to server
var url = '_mbox='+urlencode(mbox)+(page ? '&_page='+page : '');
@@ -1618,38 +1177,6 @@ function rcube_webmail()
};
- this.clear_message_list = function()
- {
- var table = this.gui_objects.messagelist;
-
- var tbody = document.createElement('TBODY');
- table.insertBefore(tbody, table.tBodies[0]);
- table.removeChild(table.tBodies[1]);
-
- this.message_rows = new Array();
- this.list_rows = this.message_rows;
-
- };
-
-
- this.clear_message_list_header = function()
- {
- var table;
- if (table = this.gui_objects.messagelist)
- {
- if (table.colgroup)
- table.removeChild(table.colgroup);
- if (table.tHead)
- table.removeChild(table.tHead);
-
- var colgroup = document.createElement('COLGROUP');
- var thead = document.createElement('THEAD');
- table.insertBefore(colgroup, table.tBodies[0]);
- table.insertBefore(thead, table.tBodies[0]);
- }
- };
-
-
this.expunge_mailbox = function(mbox)
{
var lock = false;
@@ -1694,14 +1221,14 @@ function rcube_webmail()
this.focus_mailbox = function(mbox)
{
var mbox_li;
- if (this.drag_active && mbox != this.env.mailbox && (mbox_li = this.get_mailbox_li(mbox)))
+ if (this.drag_active && mbox != this.env.mailbox && (mbox_li = this.get_mailbox_li(mbox)))
this.set_classname(mbox_li, 'droptarget', true);
}
this.unfocus_mailbox = function(mbox)
{
var mbox_li;
- if (this.drag_active && (mbox_li = this.get_mailbox_li(mbox)))
+ if (this.drag_active && (mbox_li = this.get_mailbox_li(mbox)))
this.set_classname(mbox_li, 'droptarget', false);
}
@@ -1709,7 +1236,8 @@ function rcube_webmail()
this.move_messages = function(mbox)
{
// exit if no mailbox specified or if selection is empty
- if (!mbox || !(this.selection.length || this.env.uid) || mbox==this.env.mailbox)
+ var selection = this.message_list.get_selection();
+ if (!mbox || !(selection.length || this.env.uid) || mbox==this.env.mailbox)
return;
var a_uids = new Array();
@@ -1719,19 +1247,14 @@ function rcube_webmail()
else
{
var id;
- for (var n=0; n<this.selection.length; n++)
+ for (var n=0; n<selection.length; n++)
{
- id = this.selection[n];
+ id = selection[n];
a_uids[a_uids.length] = id;
-
- // 'remove' message row from list (just hide it)
- if (this.message_rows[id].obj)
- this.message_rows[id].obj.style.display = 'none';
+ this.message_list.remove_row(id);
}
- next_row = this.get_next_row();
- prev_row = this.get_prev_row();
- new_row = (next_row) ? next_row : prev_row;
- if (new_row) this.select_row(new_row.uid,false,false);
+
+ this.message_list.select_next();
}
var lock = false;
@@ -1742,13 +1265,16 @@ function rcube_webmail()
lock = true;
this.set_busy(true, 'movingmessage');
}
+
// send request to server
this.http_request('moveto', '_uid='+a_uids.join(',')+'&_mbox='+urlencode(this.env.mailbox)+'&_target_mbox='+urlencode(mbox)+'&_from='+(this.env.action ? this.env.action : ''), lock);
};
- this.permanently_remove_messages = function() {
+ this.permanently_remove_messages = function()
+ {
// exit if no mailbox specified or if selection is empty
- if (!(this.selection.length || this.env.uid))
+ var selection = this.message_list.get_selection();
+ if (!(selection.length || this.env.uid))
return;
var a_uids = new Array();
@@ -1758,21 +1284,16 @@ function rcube_webmail()
else
{
var id;
- for (var n=0; n<this.selection.length; n++)
+ for (var n=0; n<selection.length; n++)
{
- id = this.selection[n];
+ id = selection[n];
a_uids[a_uids.length] = id;
-
- // 'remove' message row from list (just hide it)
- if (this.message_rows[id].obj)
- this.message_rows[id].obj.style.display = 'none';
+ this.message_list.remove_row(id);
}
- }
- next_row = this.get_next_row();
- prev_row = this.get_prev_row();
- new_row = (next_row) ? next_row : prev_row;
- if (new_row) this.select_row(new_row.uid,false,false);
+ this.message_list.select_next();
+ }
+
// send request to server
this.http_request('delete', '_uid='+a_uids.join(',')+'&_mbox='+urlencode(this.env.mailbox)+'&_from='+(this.env.action ? this.env.action : ''));
}
@@ -1782,8 +1303,10 @@ function rcube_webmail()
this.delete_messages = function()
{
// exit if no mailbox specified or if selection is empty
- if (!(this.selection.length || this.env.uid))
+ var selection = this.message_list.get_selection();
+ if (!(selection.length || this.env.uid))
return;
+
// if there is a trash mailbox defined and we're not currently in it:
if (this.env.trash_mailbox && String(this.env.mailbox).toLowerCase()!=String(this.env.trash_mailbox).toLowerCase())
this.move_messages(this.env.trash_mailbox);
@@ -1791,22 +1314,18 @@ function rcube_webmail()
else if (this.env.trash_mailbox && String(this.env.mailbox).toLowerCase() == String(this.env.trash_mailbox).toLowerCase())
this.permanently_remove_messages();
// if there isn't a defined trash mailbox and the config is set to flag for deletion
- else if (!this.env.trash_mailbox && this.env.flag_for_deletion) {
+ else if (!this.env.trash_mailbox && this.env.flag_for_deletion)
+ {
flag = 'delete';
this.mark_message(flag);
- if(this.env.action=="show"){
+ if(this.env.action=="show")
this.command('nextmessage','',this);
- } else if (this.selection.length == 1) {
- next_row = this.get_next_row();
- prev_row = this.get_prev_row();
- new_row = (next_row) ? next_row : prev_row;
- if (new_row) this.select_row(new_row.uid,false,false);
+ else if (selection.length == 1)
+ this.message_list.select_next();
}
// if there isn't a defined trash mailbox and the config is set NOT to flag for deletion
- }else if (!this.env.trash_mailbox && !this.env.flag_for_deletion) {
+ else if (!this.env.trash_mailbox)
this.permanently_remove_messages();
- }
- return;
};
@@ -1814,6 +1333,7 @@ function rcube_webmail()
this.mark_message = function(flag, uid)
{
var a_uids = new Array();
+ var selection = this.message_list.get_selection();
if (uid)
a_uids[0] = uid;
@@ -1822,16 +1342,18 @@ function rcube_webmail()
else
{
var id;
- for (var n=0; n<this.selection.length; n++)
+ for (var n=0; n<selection.length; n++)
{
- id = this.selection[n];
+ id = selection[n];
a_uids[a_uids.length] = id;
}
}
- switch (flag) {
+
+ switch (flag)
+ {
case 'read':
case 'unread':
- this.toggle_read_status(flag,a_uids);
+ this.toggle_read_status(flag, a_uids);
break;
case 'delete':
case 'undelete':
@@ -1841,66 +1363,70 @@ function rcube_webmail()
};
// set class to read/unread
- this.toggle_read_status = function(flag, a_uids) {
+ this.toggle_read_status = function(flag, a_uids)
+ {
// mark all message rows as read/unread
var icn_src;
+ var rows = this.message_list.rows;
for (var i=0; i<a_uids.length; i++)
{
uid = a_uids[i];
- if (this.message_rows[uid])
+ if (rows[uid])
{
- this.message_rows[uid].unread = (flag=='unread' ? true : false);
+ rows[uid].unread = (flag=='unread' ? true : false);
- if (this.message_rows[uid].classname.indexOf('unread')<0 && this.message_rows[uid].unread)
+ if (rows[uid].classname.indexOf('unread')<0 && rows[uid].unread)
{
- this.message_rows[uid].classname += ' unread';
- this.set_classname(this.message_rows[uid].obj, 'unread', true);
+ rows[uid].classname += ' unread';
+ this.set_classname(rows[uid].obj, 'unread', true);
if (this.env.unreadicon)
icn_src = this.env.unreadicon;
}
- else if (!this.message_rows[uid].unread)
+ else if (!rows[uid].unread)
{
- this.message_rows[uid].classname = this.message_rows[uid].classname.replace(/\s*unread/, '');
- this.set_classname(this.message_rows[uid].obj, 'unread', false);
+ rows[uid].classname = rows[uid].classname.replace(/\s*unread/, '');
+ this.set_classname(rows[uid].obj, 'unread', false);
- if (this.message_rows[uid].replied && this.env.repliedicon)
+ if (rows[uid].replied && this.env.repliedicon)
icn_src = this.env.repliedicon;
else if (this.env.messageicon)
icn_src = this.env.messageicon;
}
- if (this.message_rows[uid].icon && icn_src)
- this.message_rows[uid].icon.src = icn_src;
+ if (rows[uid].icon && icn_src)
+ rows[uid].icon.src = icn_src;
}
}
- this.http_request('mark', '_uid='+a_uids.join(',')+'&_flag='+flag);
- }
+
+ this.http_request('mark', '_uid='+a_uids.join(',')+'&_flag='+flag);
+ };
// mark all message rows as deleted/undeleted
- this.toggle_delete_status = function(a_uids) {
- if (this.env.read_when_deleted) {
+ this.toggle_delete_status = function(a_uids)
+ {
+ if (this.env.read_when_deleted)
this.toggle_read_status('read',a_uids);
- }
+
// if deleting message from "view message" don't bother with delete icon
if (this.env.action == "show")
return false;
- if (a_uids.length==1){
- if(this.message_rows[a_uids[0]].classname.indexOf('deleted') < 0 ){
- this.flag_as_deleted(a_uids)
- } else {
- this.flag_as_undeleted(a_uids)
- }
+ var rows = this.message_list.rows;
+ if (a_uids.length==1) {
+ if (rows[a_uids[0]] && rows[a_uids[0]].classname.indexOf('deleted') < 0)
+ this.flag_as_deleted(a_uids);
+ else
+ this.flag_as_undeleted(a_uids);
+
return true;
}
var all_deleted = true;
-
for (var i=0; i<a_uids.length; i++) {
uid = a_uids[i];
- if (this.message_rows[uid]) {
- if (this.message_rows[uid].classname.indexOf('deleted')<0) {
+ if (rows[uid]) {
+ if (rows[uid].classname.indexOf('deleted')<0) {
all_deleted = false;
break;
}
@@ -1913,59 +1439,67 @@ function rcube_webmail()
this.flag_as_deleted(a_uids);
return true;
- }
+ };
- this.flag_as_undeleted = function(a_uids){
+
+ this.flag_as_undeleted = function(a_uids)
+ {
// if deleting message from "view message" don't bother with delete icon
if (this.env.action == "show")
return false;
var icn_src;
+ var rows = this.message_list.rows;
for (var i=0; i<a_uids.length; i++) {
uid = a_uids[i];
- if (this.message_rows[uid]) {
- this.message_rows[uid].deleted = false;
+ if (rows[uid]) {
+ rows[uid].deleted = false;
- if (this.message_rows[uid].classname.indexOf('deleted') > 0) {
- this.message_rows[uid].classname = this.message_rows[uid].classname.replace(/\s*deleted/, '');
- this.set_classname(this.message_rows[uid].obj, 'deleted', false);
+ if (rows[uid].classname.indexOf('deleted') > 0) {
+ rows[uid].classname = rows[uid].classname.replace(/\s*deleted/, '');
+ this.set_classname(rows[uid].obj, 'deleted', false);
}
- if (this.message_rows[uid].unread && this.env.unreadicon)
+ if (rows[uid].unread && this.env.unreadicon)
icn_src = this.env.unreadicon;
- else if (this.message_rows[uid].replied && this.env.repliedicon)
+ else if (rows[uid].replied && this.env.repliedicon)
icn_src = this.env.repliedicon;
else if (this.env.messageicon)
icn_src = this.env.messageicon;
- if (this.message_rows[uid].icon && icn_src)
- this.message_rows[uid].icon.src = icn_src;
+ if (rows[uid].icon && icn_src)
+ rows[uid].icon.src = icn_src;
}
}
+
this.http_request('mark', '_uid='+a_uids.join(',')+'&_flag=undelete');
return true;
- }
+ };
+
- this.flag_as_deleted = function(a_uids) {
+ this.flag_as_deleted = function(a_uids)
+ {
// if deleting message from "view message" don't bother with delete icon
if (this.env.action == "show")
return false;
+ var rows = this.message_list.rows;
for (var i=0; i<a_uids.length; i++) {
uid = a_uids[i];
- if (this.message_rows[uid]) {
- this.message_rows[uid].deleted = true;
+ if (rows[uid]) {
+ rows[uid].deleted = true;
- if (this.message_rows[uid].classname.indexOf('deleted')<0) {
- this.message_rows[uid].classname += ' deleted';
- this.set_classname(this.message_rows[uid].obj, 'deleted', true);
+ if (rows[uid].classname.indexOf('deleted')<0) {
+ rows[uid].classname += ' deleted';
+ this.set_classname(rows[uid].obj, 'deleted', true);
}
- if (this.message_rows[uid].icon && this.env.deletedicon)
- this.message_rows[uid].icon.src = this.env.deletedicon;
+ if (rows[uid].icon && this.env.deletedicon)
+ rows[uid].icon.src = this.env.deletedicon;
}
}
+
this.http_request('mark', '_uid='+a_uids.join(',')+'&_flag=delete');
return true;
- }
+ };
this.get_mailbox_li = function(mbox)
@@ -2034,9 +1568,9 @@ function rcube_webmail()
this.set_spellcheck_state = function(s)
{
- this.spellcheck_ready = (s=='check_spelling' || s=='ready');
+ this.spellcheck_ready = (s=='check_spelling' || s=='ready');
this.enable_command('spellcheck', this.spellcheck_ready);
- };
+ };
this.auto_save_start = function()
@@ -2272,7 +1806,7 @@ function rcube_webmail()
{
if (value && mbox)
{
- this.clear_message_list();
+ this.message_list.clear();
this.set_busy(true, 'searching');
this.http_request('search', '_search='+value+'&_mbox='+mbox, true);
}
@@ -2527,6 +2061,30 @@ function rcube_webmail()
/*********************************************************/
+ this.contactlist_keypress = function(list)
+ {
+ if (list.key_pressed == list.DELETE_KEY)
+ this.command('delete');
+ };
+
+
+ this.contactlist_select = function(list)
+ {
+ var id, frame;
+ if (id = list.get_single_selection())
+ this.load_contact(id, 'show');
+ else if (frame = document.getElementById(this.env.contentframe))
+ frame.style.visibility = 'hidden';
+
+ this.enable_command('edit', id?true:false);
+
+ if (list.selection.length)
+ this.enable_command('delete', 'compose', true);
+
+ return false;
+ };
+
+
this.list_contacts = function(page)
{
var add_url = '';
@@ -2549,21 +2107,15 @@ function rcube_webmail()
}
this.set_busy(true, 'loading');
- location.href = this.env.comm_path+(page ? '&_page='+page : '')+add_url;
+ target.location.href = this.env.comm_path+(page ? '&_page='+page : '')+add_url;
};
// send remote request to load contacts list
this.list_contacts_remote = function(page)
{
- // clear list
- var table = this.gui_objects.contactslist;
- var tbody = document.createElement('TBODY');
- table.insertBefore(tbody, table.tBodies[0]);
- table.tBodies[1].style.display = 'none';
-
- this.contact_rows = new Array();
- this.list_rows = this.contact_rows;
+ // clear message list first
+ this.contact_list.clear();
// send request to server
var url = page ? '&_page='+page : '';
@@ -2585,11 +2137,7 @@ function rcube_webmail()
}
else if (framed)
return false;
-
- //if (this.env.framed && add_url=='')
-
- // add_url = '&_framed=1';
-
+
if (action && (cid || action=='add'))
{
this.set_busy(true);
@@ -2602,7 +2150,8 @@ function rcube_webmail()
this.delete_contacts = function()
{
// exit if no mailbox specified or if selection is empty
- if (!(this.selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm')))
+ var selection = this.contact_list.get_selection();
+ if (!(selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm')))
return;
var a_cids = new Array();
@@ -2612,18 +2161,15 @@ function rcube_webmail()
else
{
var id;
- for (var n=0; n<this.selection.length; n++)
+ for (var n=0; n<selection.length; n++)
{
- id = this.selection[n];
+ id = selection[n];
a_cids[a_cids.length] = id;
-
- // 'remove' row from list (just hide it)
- if (this.contact_rows[id].obj)
- this.contact_rows[id].obj.style.display = 'none';
+ this.contact_list.remove_row(id);
}
// hide content frame if we delete the currently displayed contact
- if (this.selection.length==1 && this.env.contentframe)
+ if (selection.length==1 && this.env.contentframe)
{
var elm = document.getElementById(this.env.contentframe);
elm.style.visibility = 'hidden';
@@ -2639,19 +2185,21 @@ function rcube_webmail()
// update a contact record in the list
this.update_contact_row = function(cid, cols_arr)
{
- if (!this.contact_rows[cid] || !this.contact_rows[cid].obj)
- return false;
-
- var row = this.contact_rows[cid].obj;
- for (var c=0; c<cols_arr.length; c++){
- if (row.cells[c])
- row.cells[c].innerHTML = cols_arr[c];
- }
- return true;
+ var row;
+ if (this.contact_list.rows[cid] && (row = this.contact_list.rows[cid].obj))
+ {
+ for (var c=0; c<cols_arr.length; c++)
+ if (row.cells[c])
+ row.cells[c].innerHTML = cols_arr[c];
+
+ return true;
+ }
+
+ return false;
};
-
-
+
// load ldap search form
+ // deprecated
this.ldappublicsearch = function(action)
{
var add_url = '';
@@ -2663,8 +2211,7 @@ function rcube_webmail()
document.getElementById(this.env.contentframe).style.visibility = 'inherit';
}
else
- return false;
-
+ return false;
if (action == 'ldappublicsearch')
target.location.href = this.env.comm_path+'&_action='+action+add_url;
@@ -2695,13 +2242,18 @@ function rcube_webmail()
}
return false;
}
-
/*********************************************************/
/********* user settings methods *********/
/*********************************************************/
+ this.identity_select = function(list)
+ {
+ var id;
+ if (id = list.get_single_selection())
+ this.load_identity(id, 'edit-identity');
+ };
// load contact record
this.load_identity = function(id, action)
@@ -2731,11 +2283,12 @@ function rcube_webmail()
this.delete_identity = function(id)
{
// exit if no mailbox specified or if selection is empty
- if (!(this.selection.length || this.env.iid))
+ var selection = this.identity_list.get_selection();
+ if (!(selection.length || this.env.iid))
return;
if (!id)
- id = this.env.iid ? this.env.iid : this.selection[0];
+ id = this.env.iid ? this.env.iid : selection[0];
/*
// 'remove' row from list (just hide it)
@@ -2747,10 +2300,7 @@ function rcube_webmail()
*/
// if (this.env.framed && id)
- this.set_busy(true);
- location.href = this.env.comm_path+'&_action=delete-identity&_iid='+id;
- // else if (id)
- // this.http_request('delete-identity', '_iid='+id);
+ this.goto_url('delete-identity', '_iid='+id, true);
return true;
};
@@ -2758,8 +2308,8 @@ function rcube_webmail()
// tell server to create and subscribe a new mailbox
this.create_folder = function(name)
{
- if (this.edit_folder)
- this.reset_folder_rename();
+ if (this.edit_folder)
+ this.reset_folder_rename();
var form;
if ((form = this.gui_objects.editform) && form.elements['_folder_name'])
@@ -2801,12 +2351,12 @@ function rcube_webmail()
var id = this.get_folder_row_id(folder);
// reset current renaming
- if (temp = this.edit_folder)
- {
- this.reset_folder_rename();
- if (temp == id)
- return;
- }
+ if (temp = this.edit_folder)
+ {
+ this.reset_folder_rename();
+ if (temp == id)
+ return;
+ }
if (id && (row = document.getElementById(id)))
{
@@ -2857,8 +2407,8 @@ function rcube_webmail()
// delete a specific mailbox with all its messages
this.delete_folder = function(folder)
{
- if (this.edit_folder)
- this.reset_folder_rename();
+ if (this.edit_folder)
+ this.reset_folder_rename();
if (folder)
this.http_request('delete-folder', '_mboxes='+urlencode(folder));
@@ -2883,7 +2433,7 @@ function rcube_webmail()
if (!id || !(refrow = document.getElementById(refid)))
{
// Refresh page if we don't have a table row to clone
- location.href = this.env.comm_path+'&_action=folders';
+ this.goto_url('folders');
}
else
{
@@ -3271,7 +2821,7 @@ function rcube_webmail()
this.set_classname(mbox_li, 'selected', true);
}
}
-
+
// also update mailbox name in window title
if (document.title)
{
@@ -3317,9 +2867,9 @@ function rcube_webmail()
// create a table row in the message list
this.add_message_row = function(uid, cols, flags, attachment, attop)
{
- if (!this.gui_objects.messagelist || !this.gui_objects.messagelist.tBodies[0])
+ if (!this.gui_objects.messagelist || !this.message_list)
return false;
-
+
var tbody = this.gui_objects.messagelist.tBodies[0];
var rowcount = tbody.rows.length;
var even = rowcount%2;
@@ -3331,8 +2881,8 @@ function rcube_webmail()
var row = document.createElement('TR');
row.id = 'rcmrow'+uid;
row.className = 'message '+(even ? 'even' : 'odd')+(flags.unread ? ' unread' : '')+(flags.deleted ? ' deleted' : '');
-
- if (this.in_selection(uid))
+
+ if (this.message_list.in_selection(uid))
row.className += ' selected';
var icon = flags.deleted && this.env.deletedicon ? this.env.deletedicon:
@@ -3358,13 +2908,8 @@ function rcube_webmail()
col.className = 'icon';
col.innerHTML = attachment && this.env.attachmenticon ? '<img src="'+this.env.attachmenticon+'" alt="" border="0" />' : '';
row.appendChild(col);
-
- if (attop && tbody.rows.length)
- tbody.insertBefore(row, tbody.firstChild);
- else
- tbody.appendChild(row);
-
- this.init_message_row(row);
+
+ this.message_list.insert_row(row, attop);
};
@@ -3384,7 +2929,7 @@ function rcube_webmail()
if (this.gui_objects.quotadisplay)
this.gui_objects.quotadisplay.innerHTML = text;
};
-
+
// update the mailboxlist
this.set_unread_count = function(mbox, count, set_title)
@@ -3433,7 +2978,7 @@ function rcube_webmail()
// add row to contacts list
- this.add_contact_row = function(cid, cols)
+ this.add_contact_row = function(cid, cols, select)
{
if (!this.gui_objects.contactslist || !this.gui_objects.contactslist.tBodies[0])
return false;
@@ -3446,7 +2991,7 @@ function rcube_webmail()
row.id = 'rcmrow'+cid;
row.className = 'contact '+(even ? 'even' : 'odd');
- if (this.in_selection(cid))
+ if (this.contact_list.in_selection(cid))
row.className += ' selected';
// add each submitted col
@@ -3458,8 +3003,7 @@ function rcube_webmail()
row.appendChild(col);
}
- tbody.appendChild(row);
- this.init_table_row(row, 'contact_rows');
+ this.contact_list.insert_row(row);
};
@@ -3474,78 +3018,25 @@ function rcube_webmail()
{
tinyMCE.execCommand('mceRemoveControl', true, textElementName);
}
- }
+ };
+
+
/********************************************************/
- /********* drag & drop methods *********/
+ /********* remote request methods *********/
/********************************************************/
- this.drag_mouse_move = function(e)
+ this.goto_url = function(action, query, lock)
{
- if (this.drag_start)
- {
- if (!this.draglayer)
- this.draglayer = new rcube_layer('rcmdraglayer', {x:0, y:0, width:300, vis:0, zindex:2000});
-
- // get subjects of selectedd messages
- var names = '';
- var c, subject, obj;
- for(var n=0; n<this.selection.length; n++)
- {
- if (n>12) // only show 12 lines
- {
- names += '...';
- break;
- }
-
- if (this.message_rows[this.selection[n]].obj)
- {
- obj = this.message_rows[this.selection[n]].obj;
- subject = '';
-
- for(c=0; c<obj.childNodes.length; c++)
- if (!subject && obj.childNodes[c].nodeName=='TD' && obj.childNodes[c].firstChild && obj.childNodes[c].firstChild.nodeType==3)
- {
- subject = obj.childNodes[c].firstChild.data;
- names += (subject.length > 50 ? subject.substring(0, 50)+'...' : subject) + '<br />';
- }
- }
- }
-
- this.draglayer.write(names);
- this.draglayer.show(1);
- }
-
- var pos = this.get_mouse_pos(e);
- this.draglayer.move(pos.x+20, pos.y-5);
-
- this.drag_start = false;
- this.drag_active = true;
-
- return false;
- };
-
+ if (lock)
+ this.set_busy(true);
- this.drag_mouse_up = function()
- {
- document.onmousemove = null;
-
- if (this.draglayer && this.draglayer.visible)
- this.draglayer.show(0);
-
- this.drag_active = false;
-
- return false;
+ var querystring = query ? '&'+query : '';
+ location.href = this.env.comm_path+'&_action='+action+querystring;
};
-
- /********************************************************/
- /********* remote request methods *********/
- /********************************************************/
-
-
this.http_sockets = new Array();
// find a non-busy socket or create a new one
@@ -3677,91 +3168,16 @@ function rcube_webmail()
// and return the message uid
this.get_single_uid = function()
{
- return this.env.uid ? this.env.uid : (this.selection.length==1 ? this.selection[0] : null);
+ return this.env.uid ? this.env.uid : (this.message_list ? this.message_list.get_single_selection() : null);
};
// same as above but for contacts
this.get_single_cid = function()
{
- return this.env.cid ? this.env.cid : (this.selection.length==1 ? this.selection[0] : null);
+ return this.env.cid ? this.env.cid : (this.contact_list ? this.contact_list.get_single_selection() : null);
};
-/* deprecated methods
-
- // check if Shift-key is pressed on event
- this.check_shiftkey = function(e)
- {
- if(!e && window.event)
- e = window.event;
-
- if(bw.linux && bw.ns4 && e.modifiers)
- return true;
- else if((bw.ns4 && e.modifiers & Event.SHIFT_MASK) || (e && e.shiftKey))
- return true;
- else
- return false;
- }
-
- // check if Shift-key is pressed on event
- this.check_ctrlkey = function(e)
- {
- if(!e && window.event)
- e = window.event;
-
- if(bw.linux && bw.ns4 && e.modifiers)
- return true;
- else if (bw.mac)
- return this.check_shiftkey(e);
- else if((bw.ns4 && e.modifiers & Event.CTRL_MASK) || (e && e.ctrlKey))
- return true;
- else
- return false;
- }
-*/
-
- // returns modifier key (constants defined at top of file)
- this.get_modifier = function(e)
- {
- var opcode = 0;
- e = e || window.event;
-
- if (bw.mac && e)
- {
- opcode += (e.metaKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY);
- return opcode;
- }
- if (e)
- {
- 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;
- var mX = (e.pageX) ? e.pageX : e.clientX;
- var mY = (e.pageY) ? e.pageY : e.clientY;
-
- if(document.body && document.all)
- {
- mX += document.body.scrollLeft;
- mY += document.body.scrollTop;
- }
-
- return { x:mX, y:mY };
- };
-
-
this.get_caret_pos = function(obj)
{
if (typeof(obj.selectionEnd)!='undefined')
@@ -3826,7 +3242,10 @@ function rcube_webmail()
-// class for HTTP requests
+/**
+ * Class for sending HTTP requests
+ * @constructor
+ */
function rcube_http_request()
{
this.url = '';
@@ -3889,7 +3308,7 @@ function rcube_http_request()
{
// default value for contentType if not provided
contentType = typeof(contentType) != 'undefined' ?
- contentType : 'application/x-www-form-urlencoded';
+ contentType : 'application/x-www-form-urlencoded';
this.build();
diff --git a/program/js/common.js b/program/js/common.js
index b0dc5564a..d5ecf8f89 100644
--- a/program/js/common.js
+++ b/program/js/common.js
@@ -3,7 +3,7 @@
| RoundCube common js library |
| |
| This file is part of the RoundCube web development suite |
- | Copyright (C) 2005, RoundCube Dev, - Switzerland |
+ | Copyright (C) 2005-2006, RoundCube Dev, - Switzerland |
| Licensed under the GNU GPL |
| |
+-----------------------------------------------------------------------+
@@ -13,8 +13,16 @@
$Id$
*/
+// Constants
+var CONTROL_KEY = 1;
+var SHIFT_KEY = 2;
+var CONTROL_SHIFT_KEY = 3;
-// default browsercheck
+
+/**
+ * Default browser check class
+ * @construcotr
+ */
function roundcube_browser()
{
this.ver = parseFloat(navigator.appVersion);
@@ -92,10 +100,118 @@ function roundcube_browser()
}
+// static functions for event handling
+var rcube_event = {
+
+/**
+ * returns modifier key (constants defined at top of file)
+ */
+get_modifier: function(e)
+{
+ var opcode = 0;
+ e = e || window.event;
+
+ if (bw.mac && e)
+ {
+ opcode += (e.metaKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY);
+ return opcode;
+ }
+ if (e)
+ {
+ opcode += (e.ctrlKey && CONTROL_KEY) + (e.shiftKey && SHIFT_KEY);
+ return opcode;
+ }
+},
+
+/**
+ * Return absolute mouse position of an event
+ */
+get_mouse_pos: function(e)
+{
+ if (!e) e = window.event;
+ var mX = (e.pageX) ? e.pageX : e.clientX;
+ var mY = (e.pageY) ? e.pageY : e.clientY;
+
+ if (document.body && document.all)
+ {
+ mX += document.body.scrollLeft;
+ mY += document.body.scrollTop;
+ }
+
+ return { x:mX, y:mY };
+},
+
+/**
+ * Add an object method as event listener to a certain element
+ */
+add_listener: function(p)
+{
+ if (!p.object || !p.method) // not enough arguments
+ return;
+ if (!p.element)
+ p.element = document;
+
+ if (!p.object._rc_events)
+ p.object._rc_events = [];
+
+ var key = p.event + '*' + p.method;
+ if (!p.object._rc_events[key])
+ p.object._rc_events[key] = function(e){ return p.object[p.method](e); };
+
+ if (p.element.addEventListener)
+ p.element.addEventListener(p.event, p.object._rc_events[key], false);
+ else if (p.element.attachEvent)
+ p.element.attachEvent('on'+p.event, p.object._rc_events[key]);
+ else
+ p.element['on'+p.event] = p.object._rc_events[key];
+},
+
+/**
+ * Remove event listener
+ */
+remove_listener: function(p)
+{
+ if (!p.element)
+ p.element = document;
+
+ var key = p.event + '*' + p.method;
+ if (p.object && p.object._rc_events && p.object._rc_events[key]) {
+ if (p.element.removeEventListener)
+ p.element.removeEventListener(p.event, p.object._rc_events[key], false);
+ else if (p.element.detachEvent)
+ p.element.detachEvent('on'+p.event, p.object._rc_events[key]);
+ else
+ p.element['on'+p.event] = null;
+ }
+},
+
+/**
+ * Prevent event propagation and bubbeling
+ */
+cancel: function(evt)
+{
+ var e = evt ? evt : window.event;
+ if (e.preventDefault)
+ e.preventDefault();
+ if (e.stopPropagation)
+ e.stopPropagation();
+
+ e.cancelBubble = true;
+ e.returnValue = false;
+ return false;
+}
+
+};
var rcube_layer_objects = new Array();
+
+/**
+ * RoundCube generic layer (floating box) class
+ *
+ * @constructor
+ */
function rcube_layer(id, attributes)
{
this.name = id;
@@ -263,6 +379,7 @@ function rcube_layer(id, attributes)
}
}
+
// check if input is a valid email address
// By Cal Henderson <cal@iamcal.com>
// http://code.iamcal.com/php/rfc822/
@@ -346,7 +463,7 @@ function find_in_array()
// make a string URL safe
function urlencode(str)
{
- return window.encodeURI ? encodeURI(str).replace(/&/g, '%26') : escape(str);
+ return window.encodeURIComponent ? encodeURIComponent(str) : escape(str);
}
diff --git a/program/js/list.js b/program/js/list.js
new file mode 100644
index 000000000..88719049a
--- /dev/null
+++ b/program/js/list.js
@@ -0,0 +1,704 @@
+/*
+ +-----------------------------------------------------------------------+
+ | RoundCube List Widget |
+ | |
+ | This file is part of the RoundCube Webmail client |
+ | Copyright (C) 2006, RoundCube Dev, - Switzerland |
+ | Licensed under the GNU GPL |
+ | |
+ +-----------------------------------------------------------------------+
+ | Authors: Thomas Bruederli <roundcube@gmail.com> |
+ | Charles McNulty <charles@charlesmcnulty.com> |
+ +-----------------------------------------------------------------------+
+ | Requires: common.js |
+ +-----------------------------------------------------------------------+
+
+ $Id: list.js 344 2006-09-18 03:49:28Z thomasb $
+*/
+
+
+/**
+ * RoundCube List Widget class
+ * @contructor
+ */
+function rcube_list_widget(list, p)
+ {
+ // static contants
+ this.ENTER_KEY = 13;
+ this.DELETE_KEY = 46;
+
+ this.list = list ? list : null;
+ this.frame = null;
+ this.rows = [];
+ this.selection = [];
+
+ this.multiselect = false;
+ this.draggable = false;
+ this.keyboard = false;
+
+ this.dont_select = false;
+ this.drag_active = false;
+ this.last_selected = 0;
+ this.in_selection_before = false;
+ this.focused = false;
+ this.drag_mouse_start = null;
+ this.dblclick_time = 600;
+ this.row_init = function(){};
+ this.events = { click:[], dblclick:[], select:[], keypress:[], dragstart:[], dragend:[] };
+
+ // overwrite default paramaters
+ if (p && typeof(p)=='object')
+ for (var n in p)
+ this[n] = p[n];
+ }
+
+
+rcube_list_widget.prototype = {
+
+
+/**
+ * get all message rows from HTML table and init each row
+ */
+init: function()
+{
+ if (this.list && this.list.tBodies[0])
+ {
+ this.rows = new Array();
+
+ var row;
+ for(var r=0; r<this.list.tBodies[0].childNodes.length; r++)
+ {
+ row = this.list.tBodies[0].childNodes[r];
+ while (row && (row.nodeType != 1 || row.style.display == 'none'))
+ {
+ row = row.nextSibling;
+ r++;
+ }
+
+ this.init_row(row);
+ }
+
+ this.frame = this.list.parentNode;
+
+ // set body events
+ if (this.keyboard)
+ rcube_event.add_listener({element:document, event:'keydown', object:this, method:'key_press'});
+ }
+},
+
+
+/**
+ *
+ */
+init_row: function(row)
+{
+ // make references in internal array and set event handlers
+ if (row && String(row.id).match(/rcmrow([0-9]+)/))
+ {
+ var p = this;
+ var uid = RegExp.$1;
+ row.uid = uid;
+ this.rows[uid] = {uid:uid, id:row.id, obj:row, classname:row.className};
+
+ // set eventhandlers to table row
+ row.onmousedown = function(e){ return p.drag_row(e, this.uid); };
+ row.onmouseup = function(e){ return p.click_row(e, this.uid); };
+
+ if (document.all)
+ row.onselectstart = function() { return false; };
+
+ this.row_init(this.rows[uid]);
+ }
+},
+
+
+/**
+ *
+ */
+clear: function()
+{
+ var tbody = document.createElement('TBODY');
+ this.list.insertBefore(tbody, this.list.tBodies[0]);
+ this.list.removeChild(this.list.tBodies[1]);
+ this.rows = new Array();
+},
+
+
+/**
+ * 'remove' message row from list (just hide it)
+ */
+remove_row: function(uid)
+{
+ if (this.rows[uid].obj)
+ this.rows[uid].obj.style.display = 'none';
+
+ this.rows[uid] = null;
+},
+
+
+/**
+ *
+ */
+insert_row: function(row, attop)
+{
+ var tbody = this.list.tBodies[0];
+
+ if (attop && tbody.rows.length)
+ tbody.insertBefore(row, tbody.firstChild);
+ else
+ tbody.appendChild(row);
+
+ this.init_row(row);
+},
+
+
+
+/**
+ * Set focur to the list
+ */
+focus: function(e)
+{
+ this.focused = true;
+ for (var n=0; n<this.selection.length; n++)
+ {
+ id = this.selection[n];
+ if (this.rows[id].obj)
+ {
+ this.set_classname(this.rows[id].obj, 'selected', true);
+ this.set_classname(this.rows[id].obj, 'unfocused', false);
+ }
+ }
+
+ if (e || (e = window.event))
+ rcube_event.cancel(e);
+},
+
+
+/**
+ * remove focus from the list
+ */
+blur: function()
+{
+ var id;
+ this.focused = false;
+ for (var n=0; n<this.selection.length; n++)
+ {
+ id = this.selection[n];
+ if (this.rows[id] && this.rows[id].obj)
+ {
+ this.set_classname(this.rows[id].obj, 'selected', false);
+ this.set_classname(this.rows[id].obj, 'unfocused', true);
+ }
+ }
+},
+
+
+/**
+ * onmousedown-handler of message list row
+ */
+drag_row: function(e, id)
+{
+ this.in_selection_before = this.in_selection(id) ? id : false;
+
+ // don't do anything (another action processed before)
+ if (this.dont_select)
+ return false;
+
+ // selects currently unselected row
+ if (!this.in_selection_before)
+ {
+ var mod_key = rcube_event.get_modifier(e);
+ this.select_row(id, mod_key, false);
+ }
+
+ if (this.draggable && this.selection.length)
+ {
+ this.drag_start = true;
+ this.drag_mouse_start = rcube_event.get_mouse_pos(e);
+ rcube_event.add_listener({element:document, event:'mousemove', object:this, method:'drag_mouse_move'});
+ rcube_event.add_listener({element:document, event:'mouseup', object:this, method:'drag_mouse_up'});
+ }
+
+ return false;
+},
+
+
+/**
+ * onmouseup-handler of message list row
+ */
+click_row: function(e, id)
+{
+ var now = new Date().getTime();
+ var mod_key = rcube_event.get_modifier(e);
+
+ // don't do anything (another action processed before)
+ if (this.dont_select)
+ {
+ this.dont_select = false;
+ return false;
+ }
+
+ var dblclicked = now - this.rows[id].clicked < this.dblclick_time;
+
+ // unselects currently selected row
+ if (!this.drag_active && this.in_selection_before == id && !dblclicked)
+ this.select_row(id, mod_key, false);
+
+ this.drag_start = false;
+ this.in_selection_before = false;
+
+ // row was double clicked
+ if (this.rows && dblclicked && this.in_selection(id))
+ this.trigger_event('dblclick');
+ else
+ this.trigger_event('click');
+
+ if (!this.drag_active)
+ rcube_event.cancel(e);
+
+ this.rows[id].clicked = now;
+ return false;
+},
+
+
+/**
+ * get next and previous rows that are not hidden
+ */
+get_next_row: function()
+{
+ if (!this.rows)
+ return false;
+
+ var last_selected_row = this.rows[this.last_selected];
+ var new_row = last_selected_row && last_selected_row.obj.nextSibling;
+ while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none'))
+ new_row = new_row.nextSibling;
+
+ return new_row;
+},
+
+get_prev_row: function()
+{
+ if (!this.rows)
+ return false;
+
+ var last_selected_row = this.rows[this.last_selected];
+ var new_row = last_selected_row && last_selected_row.obj.previousSibling;
+ while (new_row && (new_row.nodeType != 1 || new_row.style.display == 'none'))
+ new_row = new_row.previousSibling;
+
+ return new_row;
+},
+
+
+// selects or unselects the proper row depending on the modifier key pressed
+select_row: function(id, mod_key, with_mouse)
+{
+ var select_before = this.selection.join(',');
+ if (!this.multiselect)
+ mod_key = 0;
+
+ if (!mod_key)
+ {
+ this.shift_start = id;
+ this.highlight_row(id, false);
+ }
+ else
+ {
+ switch (mod_key)
+ {
+ case SHIFT_KEY:
+ this.shift_select(id, false);
+ break;
+
+ case CONTROL_KEY:
+ this.shift_start = id;
+ if (!with_mouse)
+ this.highlight_row(id, true);
+ break;
+
+ case CONTROL_SHIFT_KEY:
+ this.shift_select(id, true);
+ break;
+
+ default:
+ this.highlight_row(id, false);
+ break;
+ }
+ }
+
+ // trigger event if selection changed
+ if (this.selection.join(',') != select_before)
+ this.trigger_event('select');
+
+ if (this.last_selected != 0 && this.rows[this.last_selected])
+ this.set_classname(this.rows[this.last_selected].obj, 'focused', false);
+
+ this.last_selected = id;
+ this.set_classname(this.rows[id].obj, 'focused', true);
+},
+
+
+/**
+ * Alias method for select_row
+ */
+select: function(id)
+{
+ this.select_row(id, false);
+ this.scrollto(id);
+},
+
+
+/**
+ * Select row next to the last selected one.
+ * Either below or above.
+ */
+select_next: function()
+{
+ var next_row = this.get_next_row();
+ var prev_row = this.get_prev_row();
+ var new_row = (next_row) ? next_row : prev_row;
+ if (new_row)
+ this.select_row(new_row.uid, false, false);
+},
+
+
+/**
+ * Perform selection when shift key is pressed
+ */
+shift_select: function(id, control)
+{
+ var from_rowIndex = this.rows[this.shift_start].obj.rowIndex;
+ var to_rowIndex = this.rows[id].obj.rowIndex;
+
+ var i = ((from_rowIndex < to_rowIndex)? from_rowIndex : to_rowIndex);
+ var j = ((from_rowIndex > to_rowIndex)? from_rowIndex : to_rowIndex);
+
+ // iterate through the entire message list
+ for (var n in this.rows)
+ {
+ if ((this.rows[n].obj.rowIndex >= i) && (this.rows[n].obj.rowIndex <= j))
+ {
+ if (!this.in_selection(n))
+ this.highlight_row(n, true);
+ }
+ else
+ {
+ if (this.in_selection(n) && !control)
+ this.highlight_row(n, true);
+ }
+ }
+},
+
+
+/**
+ * Check if given id is part of the current selection
+ */
+in_selection: function(id)
+{
+ for(var n in this.selection)
+ if (this.selection[n]==id)
+ return true;
+
+ return false;
+},
+
+
+/**
+ * Select each row in list
+ */
+select_all: function(filter)
+{
+ if (!this.rows || !this.rows.length)
+ return false;
+
+ // reset selection first
+ this.clear_selection();
+
+ for (var n in this.rows)
+ {
+ if (!filter || this.rows[n][filter]==true)
+ {
+ this.last_selected = n;
+ this.highlight_row(n, true);
+ }
+ }
+
+ return true;
+},
+
+
+/**
+ * Unselect all selected rows
+ */
+clear_selection: function()
+{
+ for(var n=0; n<this.selection.length; n++)
+ if (this.rows[this.selection[n]])
+ {
+ this.set_classname(this.rows[this.selection[n]].obj, 'selected', false);
+ this.set_classname(this.rows[this.selection[n]].obj, 'unfocused', false);
+ }
+
+ this.selection = new Array();
+},
+
+
+/**
+ * Getter for the selection array
+ */
+get_selection: function()
+{
+ return this.selection;
+},
+
+
+/**
+ * Return the ID if only one row is selected
+ */
+get_single_selection: function()
+{
+ if (this.selection.length == 1)
+ return this.selection[0];
+ else
+ return null;
+},
+
+
+/**
+ * Highlight/unhighlight a row
+ */
+highlight_row: function(id, multiple)
+{
+ if (this.rows[id] && !multiple)
+ {
+ this.clear_selection();
+ this.selection[0] = id;
+ this.set_classname(this.rows[id].obj, 'selected', true)
+ }
+ else if (this.rows[id])
+ {
+ if (!this.in_selection(id)) // select row
+ {
+ this.selection[this.selection.length] = id;
+ this.set_classname(this.rows[id].obj, 'selected', true);
+ }
+ else // unselect row
+ {
+ var p = find_in_array(id, this.selection);
+ var a_pre = this.selection.slice(0, p);
+ var a_post = this.selection.slice(p+1, this.selection.length);
+ this.selection = a_pre.concat(a_post);
+ this.set_classname(this.rows[id].obj, 'selected', false);
+ this.set_classname(this.rows[id].obj, 'unfocused', false);
+ }
+ }
+},
+
+
+/**
+ * Handler for keyboard events
+ */
+key_press: function(e)
+{
+ if (this.focused != true)
+ return true;
+
+ var keyCode = document.layers ? e.which : document.all ? event.keyCode : document.getElementById ? e.keyCode : 0;
+ var mod_key = rcube_event.get_modifier(e);
+ switch (keyCode)
+ {
+ case 40:
+ case 38:
+ return this.use_arrow_key(keyCode, mod_key);
+ break;
+
+ default:
+ this.key_pressed = keyCode;
+ this.trigger_event('keypress');
+ }
+
+ return true;
+},
+
+
+/**
+ * Special handling method for arrow keys
+ */
+use_arrow_key: function(keyCode, mod_key)
+{
+ var new_row;
+ if (keyCode == 40) // down arrow key pressed
+ new_row = this.get_next_row();
+ else if (keyCode == 38) // up arrow key pressed
+ new_row = this.get_prev_row();
+
+ if (new_row)
+ {
+ this.select_row(new_row.uid, mod_key, true);
+ this.scrollto(new_row.uid);
+ }
+
+ return false;
+},
+
+
+/**
+ * Try to scroll the list to make the specified row visible
+ */
+scrollto: function(id)
+{
+ var row = this.rows[id].obj;
+ if (row && this.frame)
+ {
+ var scroll_to = Number(row.offsetTop);
+
+ if (scroll_to < Number(this.frame.scrollTop))
+ this.frame.scrollTop = scroll_to;
+ else if (scroll_to + Number(row.offsetHeight) > Number(this.frame.scrollTop) + Number(this.frame.offsetHeight))
+ this.frame.scrollTop = (scroll_to + Number(row.offsetHeight)) - Number(this.frame.offsetHeight);
+ }
+},
+
+
+/**
+ * Handler for mouse move events
+ */
+drag_mouse_move: function(e)
+{
+ if (this.drag_start)
+ {
+ // check mouse movement, of less than 3 pixels, don't start dragging
+ var m = rcube_event.get_mouse_pos(e);
+ if (!this.drag_mouse_start || (Math.abs(m.x - this.drag_mouse_start.x) < 3 && Math.abs(m.y - this.drag_mouse_start.y) < 3))
+ return false;
+
+ if (!this.draglayer)
+ this.draglayer = new rcube_layer('rcmdraglayer', {x:0, y:0, width:300, vis:0, zindex:2000});
+
+ // get subjects of selectedd messages
+ var names = '';
+ var c, subject, obj;
+ for(var n=0; n<this.selection.length; n++)
+ {
+ if (n>12) // only show 12 lines
+ {
+ names += '...';
+ break;
+ }
+
+ if (this.rows[this.selection[n]].obj)
+ {
+ obj = this.rows[this.selection[n]].obj;
+ subject = '';
+
+ for(c=0; c<obj.childNodes.length; c++)
+ if (!subject && obj.childNodes[c].nodeName=='TD' && obj.childNodes[c].firstChild && obj.childNodes[c].firstChild.nodeType==3)
+ {
+ subject = obj.childNodes[c].firstChild.data;
+ names += (subject.length > 50 ? subject.substring(0, 50)+'...' : subject) + '<br />';
+ }
+ }
+ }
+
+ this.draglayer.write(names);
+ this.draglayer.show(1);
+
+ this.drag_active = true;
+ this.trigger_event('dragstart');
+ }
+
+ if (this.drag_active && this.draglayer)
+ {
+ var pos = rcube_event.get_mouse_pos(e);
+ this.draglayer.move(pos.x+20, pos.y-5);
+ }
+
+ this.drag_start = false;
+
+ return false;
+},
+
+
+/**
+ * Handler for mouse up events
+ */
+drag_mouse_up: function(e)
+{
+ document.onmousemove = null;
+
+ if (this.draglayer && this.draglayer.visible)
+ this.draglayer.show(0);
+
+ this.drag_active = false;
+ this.trigger_event('dragend');
+
+ rcube_event.remove_listener({element:document, event:'mousemove', object:this, method:'drag_mouse_move'});
+ rcube_event.remove_listener({element:document, event:'mouseup', object:this, method:'drag_mouse_up'});
+
+ return rcube_event.cancel(e);
+},
+
+
+
+/**
+ * set/unset a specific class name
+ */
+set_classname: function(obj, classname, set)
+{
+ var reg = new RegExp('\s*'+classname, 'i');
+ if (!set && obj.className.match(reg))
+ obj.className = obj.className.replace(reg, '');
+ else if (set && !obj.className.match(reg))
+ obj.className += ' '+classname;
+},
+
+
+/**
+ * Setter for object event handlers
+ *
+ * @param {String} Event name
+ * @param {Function} Handler function
+ * @return Listener ID (used to remove this handler later on)
+ */
+addEventListener: function(evt, handler)
+{
+ if (this.events[evt]) {
+ var handle = this.events[evt].length;
+ this.events[evt][handle] = handler;
+ return handle;
+ }
+ else
+ return false;
+},
+
+
+/**
+ * Removes a specific event listener
+ *
+ * @param {String} Event name
+ * @param {Int} Listener ID to remove
+ */
+removeEventListener: function(evt, handle)
+{
+ if (this.events[evt] && this.events[evt][handle])
+ this.events[evt][handle] = null;
+},
+
+
+/**
+ * This will execute all registered event handlers
+ * @private
+ */
+trigger_event: function(evt)
+{
+ if (this.events[evt] && this.events[evt].length) {
+ for (var i=0; i<this.events[evt].length; i++)
+ if (typeof(this.events[evt][i]) == 'function')
+ this.events[evt][i](this);
+ }
+}
+
+
+};
+
diff --git a/program/steps/addressbook/edit.inc b/program/steps/addressbook/edit.inc
index a129d0094..245c02409 100644
--- a/program/steps/addressbook/edit.inc
+++ b/program/steps/addressbook/edit.inc
@@ -94,7 +94,7 @@ function get_form_tags($attrib)
$hiddenfields = new hiddenfield(array('name' => '_task', 'value' => $GLOBALS['_task']));
$hiddenfields->add(array('name' => '_action', 'value' => 'save'));
- if ($_GET['_framed'] || $_POST['_framed'])
+ if ($GLOBALS['_framed'])
$hiddenfields->add(array('name' => '_framed', 'value' => 1));
if ($CONTACT_RECORD['contact_id'])
diff --git a/program/steps/addressbook/func.inc b/program/steps/addressbook/func.inc
index 6d3e95ea2..0df6df3e3 100644
--- a/program/steps/addressbook/func.inc
+++ b/program/steps/addressbook/func.inc
@@ -90,6 +90,7 @@ function rcmail_contacts_list($attrib)
//$javascript .= sprintf("%s.set_env('contacts', %s);", $JS_OBJECT_NAME, array2js($a_js_message_arr));
$OUTPUT->add_script($javascript);
+ $OUTPUT->include_script('list.js');
// add some labels to client
rcube_add_label('deletecontactconfirm');
diff --git a/program/steps/addressbook/save.inc b/program/steps/addressbook/save.inc
index abea316e5..a50d0388a 100644
--- a/program/steps/addressbook/save.inc
+++ b/program/steps/addressbook/save.inc
@@ -62,9 +62,6 @@ if (!empty($_POST['_cid']))
if ($updated)
{
- $_action = 'show';
- show_message('successfullysaved', 'confirmation');
-
if ($_framed)
{
// define list of cols to be displayed
@@ -89,9 +86,11 @@ if (!empty($_POST['_cid']))
$_POST['_cid'],
array2js($a_js_cols)));
- // show confirmation
- show_message('successfullysaved', 'confirmation');
}
+
+ // show confirmation
+ show_message('successfullysaved', 'confirmation');
+ rcmail_overwrite_action('show');
}
else
{
@@ -184,9 +183,6 @@ else
{
if (!$ldap_form)
{
- $_action = 'show';
- $_GET['_cid'] = $insert_id;
-
if ($_framed)
{
// add contact row or jump to the page where it should appear
@@ -198,11 +194,11 @@ else
$_SESSION['user_id']);
$commands .= rcmail_js_contacts_list($sql_result, $JS_OBJECT_NAME);
- $commands .= sprintf("if(parent.%s)parent.%s.select('%d');\n",
+ $commands .= sprintf("if(parent.%s)parent.%s.contact_list.select('%d');\n",
$JS_OBJECT_NAME,
$JS_OBJECT_NAME,
$insert_id);
-
+
// update record count display
$commands .= sprintf("if(parent.%s)parent.%s.set_rowcount('%s');\n",
$JS_OBJECT_NAME,
@@ -213,7 +209,8 @@ else
}
// show confirmation
- show_message('successfullysaved', 'confirmation');
+ show_message('successfullysaved', 'confirmation');
+ $_GET['_cid'] = $insert_id;
}
else
{
@@ -231,7 +228,7 @@ else
}
// display the last insert id
- $commands .= sprintf("if(parent.%s)parent.%s.select('%d');\n",
+ $commands .= sprintf("if(parent.%s)parent.%s.contact_list.select('%d');\n",
$JS_OBJECT_NAME,
$JS_OBJECT_NAME,
$last_id);
@@ -248,6 +245,7 @@ else
// show confirmation
show_message('successfullysaved', 'confirmation');
+ rcmail_overwrite_action('show');
}
else
{
diff --git a/program/steps/mail/func.inc b/program/steps/mail/func.inc
index bfddb5aa8..18ce9eca8 100644
--- a/program/steps/mail/func.inc
+++ b/program/steps/mail/func.inc
@@ -495,6 +495,7 @@ function rcmail_message_list($attrib)
$javascript .= sprintf("%s.set_env('messages', %s);", $JS_OBJECT_NAME, array2js($a_js_message_arr));
$OUTPUT->add_script($javascript);
+ $OUTPUT->include_script('list.js');
return $out;
}
diff --git a/program/steps/settings/identities.inc b/program/steps/settings/identities.inc
index 8bad6859a..caaa45342 100644
--- a/program/steps/settings/identities.inc
+++ b/program/steps/settings/identities.inc
@@ -22,6 +22,7 @@
if ($USER_DATA = $DB->fetch_assoc($sql_result))
$PAGE_TITLE = sprintf('%s (%s@%s)', rcube_label('identities'), $USER_DATA['username'], $USER_DATA['mail_host']);
+$OUTPUT->include_script('list.js');
// similar function as /steps/addressbook/func.inc::rcmail_contact_frame()
diff --git a/skins/default/common.css b/skins/default/common.css
index 6cec3cf9e..27ddfae6d 100755
--- a/skins/default/common.css
+++ b/skins/default/common.css
@@ -252,6 +252,18 @@ table.records-table tr.selected td
background-color: #CC3333;
}
+table.records-table tr.focused td
+{
+ border-bottom: thin dotted;
+ border-top: thin dotted;
+}
+
+table.records-table tr.unfocused td
+{
+ font-weight: bold;
+ color: #FFFFFF;
+ background-color: #929292;
+}
/***** roundcube webmail pre-defined classes *****/