diff options
| author | alecpl <alec@alec.pl> | 2010-05-02 15:09:36 +0000 | 
|---|---|---|
| committer | alecpl <alec@alec.pl> | 2010-05-02 15:09:36 +0000 | 
| commit | b62c4869f7c43804601b7786809e7e7a2508566d (patch) | |
| tree | a2912d83818b22b0f64ed9cb8e466e386a8e7d26 /program/js | |
| parent | d44571bde1db578e69d82ad0121e9b44a89991a0 (diff) | |
- Allow columns order change per user - drag&drop (#1485795)
Diffstat (limited to 'program/js')
| -rw-r--r-- | program/js/app.js | 54 | ||||
| -rw-r--r-- | program/js/list.js | 269 | 
2 files changed, 296 insertions, 27 deletions
| diff --git a/program/js/app.js b/program/js/app.js index b2888d028..dd3feeeca 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -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 diff --git a/program/js/list.js b/program/js/list.js index 8d6d9f1e6..9493121d5 100644 --- a/program/js/list.js +++ b/program/js/list.js @@ -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 @@ -120,6 +121,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   */  clear: function(sel) @@ -207,6 +231,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   */  drag_row: function(e, id) @@ -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'); @@ -1143,6 +1193,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   */  set_background_mode: function(flag) | 
