- Allow columns order change per user - drag&drop (#1485795)

release-0.6
alecpl 14 years ago
parent d44571bde1
commit b62c4869f7

@ -1,6 +1,7 @@
CHANGELOG RoundCube Webmail
===========================
- Allow columns order change per user - drag&drop (#1485795)
- Add References header in read receipt (#1486681)
- Fix database constraint violation when opening a message (#1486696)
- Add 'loading' message while login is in progress (#1486667)

@ -166,7 +166,8 @@ function rcube_webmail()
if (this.gui_objects.messagelist) {
this.message_list = new rcube_list_widget(this.gui_objects.messagelist,
{multiselect:true, multiexpand:true, draggable:true, keyboard:true, dblclick_time:this.dblclick_time});
{multiselect:true, multiexpand:true, draggable:true, keyboard:true,
column_movable:this.env.col_movable, column_fixed:0, 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('click', function(o){ p.msglist_click(o); });
@ -176,11 +177,11 @@ function rcube_webmail()
this.message_list.addEventListener('dragmove', function(e){ p.drag_move(e); });
this.message_list.addEventListener('dragend', function(e){ p.drag_end(e); });
this.message_list.addEventListener('expandcollapse', function(e){ p.msglist_expand(e); });
this.message_list.addEventListener('column_replace', function(e){ p.msglist_set_coltypes(e); });
document.onmouseup = function(e){ return p.doc_mouse_up(e); };
this.gui_objects.messagelist.parentNode.onmousedown = function(e){ return p.click_on_list(e); };
this.set_message_coltypes(this.env.coltypes);
this.message_list.init();
this.enable_command('toggle_status', 'toggle_flag', 'menu-open', 'menu-save', true);
@ -1487,6 +1488,24 @@ function rcube_webmail()
if (this.env.messages[row.uid])
this.env.messages[row.uid].expanded = row.expanded;
};
this.msglist_set_coltypes = function(list)
{
var i, found, name, cols = list.list.tHead.rows[0].cells;
this.env.coltypes = [];
for (i=0; i<cols.length; i++)
if (cols[i].id && cols[i].id.match(/^rcm/)) {
name = cols[i].id.replace(/^rcm/, '');
this.env.coltypes[this.env.coltypes.length] = name == 'to' ? 'from' : name;
}
if ((found = $.inArray('flag', this.env.coltypes)) >= 0)
this.set_env('flagged_col', found);
this.http_post('save-pref', { '_name':'list_cols', '_value':this.env.coltypes });
};
this.check_droptarget = function(id)
{
@ -1692,6 +1711,9 @@ function rcube_webmail()
{
var update, add_url = '';
if (!sort_col) sort_col = this.env.sort_col;
if (!sort_order) sort_order = this.env.sort_order;
if (this.env.sort_col != sort_col || this.env.sort_order != sort_order) {
update = 1;
this.set_list_sorting(sort_col, sort_order);
@ -1702,9 +1724,25 @@ function rcube_webmail()
add_url += '&_threads=' + threads;
}
if (cols.join() != this.env.coltypes.join()) {
update = 1;
add_url += '&_cols=' + cols.join(',');
if (cols && cols.length) {
// make sure new columns are added at the end of the list
var i, idx, name, newcols = [], oldcols = this.env.coltypes;
for (i=0; i<oldcols.length; i++) {
name = oldcols[i] == 'to' ? 'from' : oldcols[i];
idx = $.inArray(name, cols);
if (idx != -1) {
newcols[newcols.length] = name;
delete cols[idx];
}
}
for (i=0; i<cols.length; i++)
if (cols[i])
newcols[newcols.length] = cols[i];
if (newcols.join() != this.env.coltypes.join()) {
update = 1;
add_url += '&_cols=' + newcols.join(',');
}
}
if (update)
@ -4439,13 +4477,15 @@ function rcube_webmail()
this.env.flagged_col = null;
var found;
if((found = $.inArray('subject', this.env.coltypes)) >= 0) {
if ((found = $.inArray('subject', this.env.coltypes)) >= 0) {
this.set_env('subject_col', found);
if (this.message_list)
this.message_list.subject_col = found+1;
}
if((found = $.inArray('flag', this.env.coltypes)) >= 0)
if ((found = $.inArray('flag', this.env.coltypes)) >= 0)
this.set_env('flagged_col', found);
this.message_list.init_header();
};
// replace content of row count display

@ -33,6 +33,7 @@ function rcube_list_widget(list, p)
this.rows = [];
this.selection = [];
this.rowcount = 0;
this.colcount = 0;
this.subject_col = -1;
this.shiftkey = false;
@ -40,11 +41,14 @@ function rcube_list_widget(list, p)
this.multiexpand = false;
this.multi_selecting = false;
this.draggable = false;
this.column_movable = false;
this.keyboard = false;
this.toggleselect = false;
this.dont_select = false;
this.drag_active = false;
this.col_drag_active = false;
this.column_fixed = null;
this.last_selected = 0;
this.shift_start = 0;
this.in_selection_before = false;
@ -72,18 +76,15 @@ init: function()
this.rows = [];
this.rowcount = 0;
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 = row.nextSibling;
r++;
}
var row, r;
for (r=0; r<this.list.tBodies[0].rows.length; r++) {
row = this.list.tBodies[0].rows[r];
this.init_row(row);
this.rowcount++;
}
this.init_header();
this.frame = this.list.parentNode;
// set body events
@ -119,6 +120,29 @@ init_row: function(row)
},
/**
* Init list column headers and set mouse events on them
*/
init_header: function()
{
if (this.list && this.list.tHead) {
this.colcount = 0;
var col, r, p = this;
// add events for list columns moving
if (this.column_movable && this.list.tHead && this.list.tHead.rows) {
for (r=0; r<this.list.tHead.rows[0].cells.length; r++) {
if (this.column_fixed == r)
continue;
col = this.list.tHead.rows[0].cells[r];
col.onmousedown = function(e){ return p.drag_column(e, this); };
this.colcount++;
}
}
}
},
/**
* Remove all list rows
*/
@ -206,6 +230,34 @@ blur: function()
},
/**
* onmousedown-handler of message list column
*/
drag_column: function(e, col)
{
if (this.colcount > 1) {
this.drag_start = true;
this.drag_mouse_start = rcube_event.get_mouse_pos(e);
rcube_event.add_listener({event:'mousemove', object:this, method:'column_drag_mouse_move'});
rcube_event.add_listener({event:'mouseup', object:this, method:'column_drag_mouse_up'});
// enable dragging over iframes
this.add_dragfix();
// find selected column number
for (var i=0; i<this.list.tHead.rows[0].cells.length; i++) {
if (col == this.list.tHead.rows[0].cells[i]) {
this.selected_column = i;
break;
}
}
}
return false;
},
/**
* onmousedown-handler of message list row
*/
@ -236,15 +288,7 @@ drag_row: function(e, id)
rcube_event.add_listener({event:'mouseup', object:this, method:'drag_mouse_up'});
// enable dragging over iframes
$('iframe').each(function() {
$('<div class="iframe-dragdrop-fix"></div>')
.css({background: '#fff',
width: this.offsetWidth+'px', height: this.offsetHeight+'px',
position: 'absolute', opacity: '0.001', zIndex: 1000
})
.css($(this).offset())
.appendTo('body');
});
this.add_dragfix();
}
return false;
@ -287,7 +331,7 @@ click_row: function(e, id)
if (!this.drag_active) {
// remove temp divs
$('div.iframe-dragdrop-fix').each(function() { this.parentNode.removeChild(this); });
this.del_dragfix();
rcube_event.cancel(e);
}
@ -931,7 +975,11 @@ key_down: function(e)
switch (rcube_event.get_keycode(e)) {
case 27:
if (this.drag_active)
return this.drag_mouse_up(e);
return this.drag_mouse_up(e);
if (this.col_drag_active) {
this.selected_column = null;
return this.column_drag_mouse_up(e);
}
case 40:
case 38:
@ -1040,7 +1088,9 @@ drag_mouse_move: function(e)
return false;
if (!this.draglayer)
this.draglayer = $('<div>').attr('id', 'rcmdraglayer').css({ position:'absolute', display:'none', 'z-index':2000 }).appendTo(document.body);
this.draglayer = $('<div>').attr('id', 'rcmdraglayer')
.css({ position:'absolute', display:'none', 'z-index':2000 })
.appendTo(document.body);
// also select childs of (collapsed) threads for dragging
var selection = $.merge([], this.selection);
@ -1134,7 +1184,7 @@ drag_mouse_up: function(e)
rcube_event.remove_listener({event:'mouseup', object:this, method:'drag_mouse_up'});
// remove temp divs
$('div.iframe-dragdrop-fix').each(function() { this.parentNode.removeChild(this); });
this.del_dragfix();
this.triggerEvent('dragend');
@ -1142,6 +1192,185 @@ drag_mouse_up: function(e)
},
/**
* Handler for mouse move events for dragging list column
*/
column_drag_mouse_move: function(e)
{
if (this.drag_start) {
// check mouse movement, of less than 3 pixels, don't start dragging
var i, 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.col_draglayer) {
var lpos = $(this.list).offset(),
cells = this.list.tHead.rows[0].cells;
// create dragging layer
this.col_draglayer = $('<div>').attr('id', 'rcmcoldraglayer')
.css(lpos).css({ position:'absolute', 'z-index':2001,
'background-color':'white', opacity:0.75,
height: (this.frame.offsetHeight-2)+'px', width: (this.frame.offsetWidth-2)+'px' })
.appendTo(document.body)
// ... and column position indicator
.append($('<div>').attr('id', 'rcmcolumnindicator')
.css({ position:'absolute', 'border-right':'2px dotted #555',
'z-index':2002, height: (this.frame.offsetHeight-2)+'px' }));
this.cols = [];
this.list_pos = this.list_min_pos = lpos.left;
// save columns positions
for (i=0; i<cells.length; i++) {
this.cols[i] = cells[i].offsetWidth;
if (this.column_fixed !== null && i <= this.column_fixed) {
this.list_min_pos += this.cols[i];
}
}
}
this.col_draglayer.show();
this.col_drag_active = true;
this.triggerEvent('column_dragstart');
}
// set column indicator position
if (this.col_drag_active && this.col_draglayer) {
var i, cpos = 0, pos = rcube_event.get_mouse_pos(e);
for (i=0; i<this.cols.length; i++) {
if (pos.x >= this.cols[i]/2 + this.list_pos + cpos)
cpos += this.cols[i];
else
break;
}
// handle fixed columns on left
if (i == 0 && this.list_min_pos > pos.x)
cpos = this.list_min_pos - this.list_pos;
// empty list needs some assignment
else if (!this.list.rowcount && i == this.cols.length)
cpos -= 2;
$('#rcmcolumnindicator').css({ width: cpos+'px'});
this.triggerEvent('column_dragmove', e?e:window.event);
}
this.drag_start = false;
return false;
},
/**
* Handler for mouse up events for dragging list columns
*/
column_drag_mouse_up: function(e)
{
document.onmousemove = null;
if (this.col_draglayer) {
(this.col_draglayer).remove();
this.col_draglayer = null;
}
if (this.col_drag_active)
this.focus();
this.col_drag_active = false;
rcube_event.remove_listener({event:'mousemove', object:this, method:'column_drag_mouse_move'});
rcube_event.remove_listener({event:'mouseup', object:this, method:'column_drag_mouse_up'});
// remove temp divs
this.del_dragfix();
if (this.selected_column !== null && this.cols && this.cols.length) {
var i, cpos = 0, pos = rcube_event.get_mouse_pos(e);
// find destination position
for (i=0; i<this.cols.length; i++) {
if (pos.x >= this.cols[i]/2 + this.list_pos + cpos)
cpos += this.cols[i];
else
break;
}
if (i != this.selected_column && i != this.selected_column+1) {
this.column_replace(this.selected_column, i);
}
}
this.triggerEvent('column_dragend');
return rcube_event.cancel(e);
},
/**
* Creates a layer for drag&drop over iframes
*/
add_dragfix: function()
{
$('iframe').each(function() {
$('<div class="iframe-dragdrop-fix"></div>')
.css({background: '#fff',
width: this.offsetWidth+'px', height: this.offsetHeight+'px',
position: 'absolute', opacity: '0.001', zIndex: 1000
})
.css($(this).offset())
.appendTo(document.body);
});
},
/**
* Removes the layer for drag&drop over iframes
*/
del_dragfix: function()
{
$('div.iframe-dragdrop-fix').each(function() { this.parentNode.removeChild(this); });
},
/**
* Replaces two columns
*/
column_replace: function(from, to)
{
var cells = this.list.tHead.rows[0].cells,
elem = cells[from],
before = cells[to],
td = document.createElement('td');
// replace header cells
if (before)
cells[0].parentNode.insertBefore(td, before);
else
cells[0].parentNode.appendChild(td);
cells[0].parentNode.replaceChild(elem, td);
// replace list cells
for (r=0; r<this.list.tBodies[0].rows.length; r++) {
row = this.list.tBodies[0].rows[r];
elem = row.cells[from];
before = row.cells[to];
td = document.createElement('td');
if (before)
row.insertBefore(td, before);
else
row.appendChild(td);
row.replaceChild(elem, td);
}
// update subject column position
if (this.subject_col == from)
this.subject_col = to > from ? to - 1 : to;
this.triggerEvent('column_replace');
},
/**
* Creating the list in background
*/

@ -154,13 +154,16 @@ function rcmail_message_list($attrib)
$attrib['id'] = 'rcubemessagelist';
// define list of cols to be displayed based on parameter or config
if (empty($attrib['columns']))
$a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
else
$a_show_cols = preg_split('/[\s,;]+/', strip_quotes($attrib['columns']));
if (empty($attrib['columns'])) {
$a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
$OUTPUT->set_env('col_movable', !in_array('list_cols', (array)$CONFIG['dont_override']));
}
else {
$a_show_cols = preg_split('/[\s,;]+/', strip_quotes($attrib['columns']));
$attrib['columns'] = $a_show_cols;
}
// save some variables for use in ajax list
$_SESSION['list_columns'] = $a_show_cols;
$_SESSION['list_attrib'] = $attrib;
$mbox = $IMAP->get_mailbox_name();
@ -220,7 +223,7 @@ function rcmail_message_list($attrib)
$attrib,
html::tag('thead', null, html::tag('tr', null, $thead)) .
html::tag('tbody', null, ''),
array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary'));
}
@ -232,10 +235,10 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $replace=TRUE, $h
{
global $CONFIG, $IMAP, $OUTPUT;
if (empty($_SESSION['list_columns']))
$a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
if (!empty($_SESSION['list_attrib']['columns']))
$a_show_cols = $_SESSION['list_attrib']['columns'];
else
$a_show_cols = $_SESSION['list_columns'];
$a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject');
$mbox = $IMAP->get_mailbox_name();
$delim = $IMAP->get_hierarchy_delimiter();
@ -324,7 +327,7 @@ function rcmail_js_message_list($a_headers, $insert_top=FALSE, $replace=TRUE, $h
if ($browser->ie && $replace)
$OUTPUT->command('offline_message_list', false);
}
}
/*

@ -45,7 +45,7 @@ else
if ($cols = get_input_value('_cols', RCUBE_INPUT_GET))
{
$save_arr = array();
$_SESSION['list_columns'] = $save_arr['list_cols'] = explode(',', $cols);
$save_arr['list_cols'] = explode(',', $cols);
}
if ($save_arr)

Loading…
Cancel
Save