Changeset b62c486 in github


Ignore:
Timestamp:
May 2, 2010 11:09:36 AM (3 years ago)
Author:
alecpl <alec@…>
Branches:
master, HEAD, courier-fix, dev-browser-capabilities, pdo, release-0.6, release-0.7, release-0.8
Children:
e095094
Parents:
d44571b
Message:
  • Allow columns order change per user - drag&drop (#1485795)
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • CHANGELOG

    rea50e71 rb62c486  
    22=========================== 
    33 
     4- Allow columns order change per user - drag&drop (#1485795) 
    45- Add References header in read receipt (#1486681) 
    56- Fix database constraint violation when opening a message (#1486696) 
  • program/js/app.js

    rcecf46a4 rb62c486  
    167167 
    168168          this.message_list = new rcube_list_widget(this.gui_objects.messagelist, 
    169             {multiselect:true, multiexpand:true, draggable:true, keyboard:true, dblclick_time:this.dblclick_time}); 
     169            {multiselect:true, multiexpand:true, draggable:true, keyboard:true, 
     170            column_movable:this.env.col_movable, column_fixed:0, dblclick_time:this.dblclick_time}); 
    170171          this.message_list.row_init = function(o){ p.init_message_row(o); }; 
    171172          this.message_list.addEventListener('dblclick', function(o){ p.msglist_dbl_click(o); }); 
     
    177178          this.message_list.addEventListener('dragend', function(e){ p.drag_end(e); }); 
    178179          this.message_list.addEventListener('expandcollapse', function(e){ p.msglist_expand(e); }); 
     180          this.message_list.addEventListener('column_replace', function(e){ p.msglist_set_coltypes(e); }); 
    179181 
    180182          document.onmouseup = function(e){ return p.doc_mouse_up(e); }; 
    181183          this.gui_objects.messagelist.parentNode.onmousedown = function(e){ return p.click_on_list(e); }; 
    182184 
    183           this.set_message_coltypes(this.env.coltypes); 
    184185          this.message_list.init(); 
    185186          this.enable_command('toggle_status', 'toggle_flag', 'menu-open', 'menu-save', true); 
     
    14881489      this.env.messages[row.uid].expanded = row.expanded; 
    14891490  }; 
     1491   
     1492  this.msglist_set_coltypes = function(list) 
     1493  { 
     1494    var i, found, name, cols = list.list.tHead.rows[0].cells; 
     1495     
     1496    this.env.coltypes = []; 
     1497     
     1498    for (i=0; i<cols.length; i++) 
     1499      if (cols[i].id && cols[i].id.match(/^rcm/)) { 
     1500        name = cols[i].id.replace(/^rcm/, ''); 
     1501        this.env.coltypes[this.env.coltypes.length] = name == 'to' ? 'from' : name; 
     1502      } 
     1503 
     1504    if ((found = $.inArray('flag', this.env.coltypes)) >= 0) 
     1505      this.set_env('flagged_col', found); 
     1506 
     1507    this.http_post('save-pref', { '_name':'list_cols', '_value':this.env.coltypes }); 
     1508  }; 
    14901509 
    14911510  this.check_droptarget = function(id) 
     
    16931712    var update, add_url = ''; 
    16941713 
     1714    if (!sort_col) sort_col = this.env.sort_col; 
     1715    if (!sort_order) sort_order = this.env.sort_order; 
     1716 
    16951717    if (this.env.sort_col != sort_col || this.env.sort_order != sort_order) { 
    16961718      update = 1; 
     
    17031725    } 
    17041726 
    1705     if (cols.join() != this.env.coltypes.join()) { 
    1706       update = 1; 
    1707       add_url += '&_cols=' + cols.join(','); 
     1727    if (cols && cols.length) { 
     1728      // make sure new columns are added at the end of the list 
     1729      var i, idx, name, newcols = [], oldcols = this.env.coltypes; 
     1730      for (i=0; i<oldcols.length; i++) { 
     1731        name = oldcols[i] == 'to' ? 'from' : oldcols[i]; 
     1732        idx = $.inArray(name, cols); 
     1733        if (idx != -1) { 
     1734          newcols[newcols.length] = name; 
     1735          delete cols[idx]; 
     1736        } 
     1737      } 
     1738      for (i=0; i<cols.length; i++) 
     1739        if (cols[i]) 
     1740          newcols[newcols.length] = cols[i]; 
     1741       
     1742      if (newcols.join() != this.env.coltypes.join()) { 
     1743        update = 1; 
     1744        add_url += '&_cols=' + newcols.join(','); 
     1745      } 
    17081746    } 
    17091747 
     
    44404478 
    44414479    var found; 
    4442     if((found = $.inArray('subject', this.env.coltypes)) >= 0) { 
     4480    if ((found = $.inArray('subject', this.env.coltypes)) >= 0) { 
    44434481      this.set_env('subject_col', found); 
    44444482      if (this.message_list) 
    44454483        this.message_list.subject_col = found+1; 
    44464484    } 
    4447     if((found = $.inArray('flag', this.env.coltypes)) >= 0) 
     4485    if ((found = $.inArray('flag', this.env.coltypes)) >= 0) 
    44484486      this.set_env('flagged_col', found); 
     4487 
     4488    this.message_list.init_header(); 
    44494489  }; 
    44504490 
  • program/js/list.js

    rdd51b73 rb62c486  
    3434  this.selection = []; 
    3535  this.rowcount = 0; 
     36  this.colcount = 0; 
    3637 
    3738  this.subject_col = -1; 
     
    4142  this.multi_selecting = false; 
    4243  this.draggable = false; 
     44  this.column_movable = false; 
    4345  this.keyboard = false; 
    4446  this.toggleselect = false; 
     
    4648  this.dont_select = false; 
    4749  this.drag_active = false; 
     50  this.col_drag_active = false; 
     51  this.column_fixed = null; 
    4852  this.last_selected = 0; 
    4953  this.shift_start = 0; 
     
    7377    this.rowcount = 0; 
    7478 
    75     var row; 
    76     for(var r=0; r<this.list.tBodies[0].childNodes.length; r++) { 
    77       row = this.list.tBodies[0].childNodes[r]; 
    78       while (row && row.nodeType != 1) { 
    79         row = row.nextSibling; 
    80         r++; 
    81       } 
    82  
     79    var row, r; 
     80 
     81    for (r=0; r<this.list.tBodies[0].rows.length; r++) { 
     82      row = this.list.tBodies[0].rows[r]; 
    8383      this.init_row(row); 
    8484      this.rowcount++; 
    8585    } 
    8686 
     87    this.init_header(); 
    8788    this.frame = this.list.parentNode; 
    8889 
     
    121122 
    122123/** 
     124 * Init list column headers and set mouse events on them 
     125 */ 
     126init_header: function() 
     127{ 
     128  if (this.list && this.list.tHead) { 
     129    this.colcount = 0; 
     130 
     131    var col, r, p = this; 
     132    // add events for list columns moving 
     133    if (this.column_movable && this.list.tHead && this.list.tHead.rows) { 
     134      for (r=0; r<this.list.tHead.rows[0].cells.length; r++) { 
     135        if (this.column_fixed == r) 
     136          continue; 
     137        col = this.list.tHead.rows[0].cells[r]; 
     138        col.onmousedown = function(e){ return p.drag_column(e, this); }; 
     139        this.colcount++; 
     140      } 
     141    } 
     142  } 
     143}, 
     144 
     145 
     146/** 
    123147 * Remove all list rows 
    124148 */ 
     
    208232 
    209233/** 
     234 * onmousedown-handler of message list column 
     235 */ 
     236drag_column: function(e, col) 
     237{ 
     238  if (this.colcount > 1) { 
     239    this.drag_start = true; 
     240    this.drag_mouse_start = rcube_event.get_mouse_pos(e); 
     241 
     242    rcube_event.add_listener({event:'mousemove', object:this, method:'column_drag_mouse_move'}); 
     243    rcube_event.add_listener({event:'mouseup', object:this, method:'column_drag_mouse_up'}); 
     244 
     245    // enable dragging over iframes 
     246    this.add_dragfix(); 
     247 
     248    // find selected column number 
     249    for (var i=0; i<this.list.tHead.rows[0].cells.length; i++) { 
     250      if (col == this.list.tHead.rows[0].cells[i]) { 
     251        this.selected_column = i; 
     252        break; 
     253      } 
     254    } 
     255  } 
     256 
     257  return false; 
     258}, 
     259 
     260 
     261/** 
    210262 * onmousedown-handler of message list row 
    211263 */ 
     
    237289 
    238290    // enable dragging over iframes 
    239     $('iframe').each(function() { 
    240       $('<div class="iframe-dragdrop-fix"></div>') 
    241         .css({background: '#fff', 
    242           width: this.offsetWidth+'px', height: this.offsetHeight+'px', 
    243           position: 'absolute', opacity: '0.001', zIndex: 1000 
    244         }) 
    245         .css($(this).offset()) 
    246         .appendTo('body'); 
    247     });                                                                 
     291    this.add_dragfix(); 
    248292  } 
    249293 
     
    288332  if (!this.drag_active) { 
    289333    // remove temp divs 
    290     $('div.iframe-dragdrop-fix').each(function() { this.parentNode.removeChild(this); }); 
     334    this.del_dragfix(); 
    291335    rcube_event.cancel(e); 
    292336  } 
     
    932976    case 27: 
    933977      if (this.drag_active) 
    934         return this.drag_mouse_up(e); 
     978            return this.drag_mouse_up(e); 
     979      if (this.col_drag_active) { 
     980        this.selected_column = null; 
     981            return this.column_drag_mouse_up(e); 
     982      } 
    935983 
    936984    case 40: 
     
    10411089 
    10421090    if (!this.draglayer) 
    1043       this.draglayer = $('<div>').attr('id', 'rcmdraglayer').css({ position:'absolute', display:'none', 'z-index':2000 }).appendTo(document.body); 
     1091      this.draglayer = $('<div>').attr('id', 'rcmdraglayer') 
     1092        .css({ position:'absolute', display:'none', 'z-index':2000 }) 
     1093        .appendTo(document.body); 
    10441094 
    10451095    // also select childs of (collapsed) threads for dragging 
     
    11351185 
    11361186  // remove temp divs 
     1187  this.del_dragfix(); 
     1188 
     1189  this.triggerEvent('dragend'); 
     1190 
     1191  return rcube_event.cancel(e); 
     1192}, 
     1193 
     1194 
     1195/** 
     1196 * Handler for mouse move events for dragging list column 
     1197 */ 
     1198column_drag_mouse_move: function(e) 
     1199{ 
     1200  if (this.drag_start) { 
     1201    // check mouse movement, of less than 3 pixels, don't start dragging 
     1202    var i, m = rcube_event.get_mouse_pos(e); 
     1203 
     1204    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)) 
     1205      return false; 
     1206 
     1207    if (!this.col_draglayer) { 
     1208      var lpos = $(this.list).offset(), 
     1209        cells = this.list.tHead.rows[0].cells; 
     1210 
     1211      // create dragging layer 
     1212      this.col_draglayer = $('<div>').attr('id', 'rcmcoldraglayer') 
     1213        .css(lpos).css({ position:'absolute', 'z-index':2001, 
     1214           'background-color':'white', opacity:0.75, 
     1215           height: (this.frame.offsetHeight-2)+'px', width: (this.frame.offsetWidth-2)+'px' }) 
     1216        .appendTo(document.body) 
     1217        // ... and column position indicator 
     1218       .append($('<div>').attr('id', 'rcmcolumnindicator') 
     1219          .css({ position:'absolute', 'border-right':'2px dotted #555',  
     1220          'z-index':2002, height: (this.frame.offsetHeight-2)+'px' })); 
     1221 
     1222      this.cols = []; 
     1223      this.list_pos = this.list_min_pos = lpos.left; 
     1224      // save columns positions 
     1225      for (i=0; i<cells.length; i++) { 
     1226        this.cols[i] = cells[i].offsetWidth; 
     1227        if (this.column_fixed !== null && i <= this.column_fixed) { 
     1228          this.list_min_pos += this.cols[i]; 
     1229        } 
     1230      } 
     1231    } 
     1232 
     1233    this.col_draglayer.show(); 
     1234    this.col_drag_active = true; 
     1235    this.triggerEvent('column_dragstart'); 
     1236  } 
     1237 
     1238  // set column indicator position 
     1239  if (this.col_drag_active && this.col_draglayer) { 
     1240    var i, cpos = 0, pos = rcube_event.get_mouse_pos(e); 
     1241 
     1242    for (i=0; i<this.cols.length; i++) { 
     1243      if (pos.x >= this.cols[i]/2 + this.list_pos + cpos) 
     1244        cpos += this.cols[i]; 
     1245      else 
     1246        break; 
     1247    } 
     1248 
     1249    // handle fixed columns on left 
     1250    if (i == 0 && this.list_min_pos > pos.x) 
     1251      cpos = this.list_min_pos - this.list_pos; 
     1252    // empty list needs some assignment 
     1253    else if (!this.list.rowcount && i == this.cols.length) 
     1254      cpos -= 2; 
     1255    $('#rcmcolumnindicator').css({ width: cpos+'px'}); 
     1256    this.triggerEvent('column_dragmove', e?e:window.event); 
     1257  } 
     1258 
     1259  this.drag_start = false; 
     1260 
     1261  return false; 
     1262}, 
     1263 
     1264 
     1265/** 
     1266 * Handler for mouse up events for dragging list columns 
     1267 */ 
     1268column_drag_mouse_up: function(e) 
     1269{ 
     1270  document.onmousemove = null; 
     1271 
     1272  if (this.col_draglayer) { 
     1273    (this.col_draglayer).remove(); 
     1274    this.col_draglayer = null; 
     1275  } 
     1276 
     1277  if (this.col_drag_active) 
     1278    this.focus(); 
     1279  this.col_drag_active = false; 
     1280 
     1281  rcube_event.remove_listener({event:'mousemove', object:this, method:'column_drag_mouse_move'}); 
     1282  rcube_event.remove_listener({event:'mouseup', object:this, method:'column_drag_mouse_up'}); 
     1283  // remove temp divs 
     1284  this.del_dragfix(); 
     1285 
     1286  if (this.selected_column !== null && this.cols && this.cols.length) { 
     1287    var i, cpos = 0, pos = rcube_event.get_mouse_pos(e); 
     1288 
     1289    // find destination position 
     1290    for (i=0; i<this.cols.length; i++) { 
     1291      if (pos.x >= this.cols[i]/2 + this.list_pos + cpos) 
     1292        cpos += this.cols[i]; 
     1293      else 
     1294        break; 
     1295    } 
     1296 
     1297    if (i != this.selected_column && i != this.selected_column+1) { 
     1298      this.column_replace(this.selected_column, i); 
     1299    } 
     1300  } 
     1301 
     1302  this.triggerEvent('column_dragend'); 
     1303 
     1304  return rcube_event.cancel(e); 
     1305}, 
     1306 
     1307 
     1308/** 
     1309 * Creates a layer for drag&drop over iframes 
     1310 */ 
     1311add_dragfix: function() 
     1312{ 
     1313  $('iframe').each(function() { 
     1314    $('<div class="iframe-dragdrop-fix"></div>') 
     1315      .css({background: '#fff', 
     1316        width: this.offsetWidth+'px', height: this.offsetHeight+'px', 
     1317        position: 'absolute', opacity: '0.001', zIndex: 1000 
     1318      }) 
     1319      .css($(this).offset()) 
     1320      .appendTo(document.body); 
     1321  });                                                                 
     1322}, 
     1323 
     1324 
     1325/** 
     1326 * Removes the layer for drag&drop over iframes 
     1327 */ 
     1328del_dragfix: function() 
     1329{ 
    11371330  $('div.iframe-dragdrop-fix').each(function() { this.parentNode.removeChild(this); }); 
    1138  
    1139   this.triggerEvent('dragend'); 
    1140  
    1141   return rcube_event.cancel(e); 
     1331}, 
     1332 
     1333 
     1334/** 
     1335 * Replaces two columns 
     1336 */ 
     1337column_replace: function(from, to) 
     1338{ 
     1339  var cells = this.list.tHead.rows[0].cells, 
     1340    elem = cells[from], 
     1341    before = cells[to], 
     1342    td = document.createElement('td'); 
     1343 
     1344  // replace header cells 
     1345  if (before) 
     1346    cells[0].parentNode.insertBefore(td, before); 
     1347  else 
     1348    cells[0].parentNode.appendChild(td); 
     1349  cells[0].parentNode.replaceChild(elem, td); 
     1350 
     1351  // replace list cells 
     1352  for (r=0; r<this.list.tBodies[0].rows.length; r++) { 
     1353    row = this.list.tBodies[0].rows[r]; 
     1354 
     1355    elem = row.cells[from]; 
     1356    before = row.cells[to]; 
     1357    td = document.createElement('td'); 
     1358 
     1359    if (before) 
     1360      row.insertBefore(td, before); 
     1361    else 
     1362      row.appendChild(td); 
     1363    row.replaceChild(elem, td); 
     1364  } 
     1365 
     1366  // update subject column position 
     1367  if (this.subject_col == from) 
     1368    this.subject_col = to > from ? to - 1 : to; 
     1369 
     1370  this.triggerEvent('column_replace'); 
    11421371}, 
    11431372 
  • program/steps/mail/func.inc

    rea50e71 rb62c486  
    155155 
    156156  // define list of cols to be displayed based on parameter or config 
    157   if (empty($attrib['columns'])) 
    158       $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject'); 
    159   else 
    160       $a_show_cols = preg_split('/[\s,;]+/', strip_quotes($attrib['columns'])); 
     157  if (empty($attrib['columns'])) { 
     158    $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject'); 
     159    $OUTPUT->set_env('col_movable', !in_array('list_cols', (array)$CONFIG['dont_override'])); 
     160  } 
     161  else { 
     162    $a_show_cols = preg_split('/[\s,;]+/', strip_quotes($attrib['columns'])); 
     163    $attrib['columns'] = $a_show_cols; 
     164  } 
    161165 
    162166  // save some variables for use in ajax list 
    163   $_SESSION['list_columns'] = $a_show_cols; 
    164167  $_SESSION['list_attrib'] = $attrib; 
    165168   
     
    221224    html::tag('thead', null, html::tag('tr', null, $thead)) . 
    222225      html::tag('tbody', null, ''), 
    223     array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); 
     226        array('style', 'class', 'id', 'cellpadding', 'cellspacing', 'border', 'summary')); 
    224227} 
    225228 
     
    233236  global $CONFIG, $IMAP, $OUTPUT; 
    234237 
    235   if (empty($_SESSION['list_columns'])) 
     238  if (!empty($_SESSION['list_attrib']['columns'])) 
     239    $a_show_cols = $_SESSION['list_attrib']['columns']; 
     240  else 
    236241    $a_show_cols = is_array($CONFIG['list_cols']) ? $CONFIG['list_cols'] : array('subject'); 
    237   else 
    238     $a_show_cols = $_SESSION['list_columns']; 
    239242 
    240243  $mbox = $IMAP->get_mailbox_name(); 
     
    325328  if ($browser->ie && $replace) 
    326329    $OUTPUT->command('offline_message_list', false); 
    327   } 
     330} 
    328331 
    329332 
  • program/steps/mail/list.inc

    rf52c936f rb62c486  
    4646{ 
    4747  $save_arr = array(); 
    48   $_SESSION['list_columns'] = $save_arr['list_cols'] = explode(',', $cols); 
     48  $save_arr['list_cols'] = explode(',', $cols); 
    4949} 
    5050 
Note: See TracChangeset for help on using the changeset viewer.