diff options
| author | alecpl <alec@alec.pl> | 2011-05-20 10:38:44 +0000 | 
|---|---|---|
| committer | alecpl <alec@alec.pl> | 2011-05-20 10:38:44 +0000 | 
| commit | 254d5ef32b7ec45a48abd43f19c84168dabe13d1 (patch) | |
| tree | 4b8551073ec4ac519856f9f04049d3c5b1d7dd40 /program | |
| parent | 3253b296c21c54df228de39ff3e4775974df81d5 (diff) | |
- Improve performence of folder manager operations by moving subscriptions table operations (like adding/updateing/moving folders) into client-side - no need to invoke LIST, do sorting in browser
- This change should also handle better situations when working with replicated IMAP backend (e.g.Cyrus Murder)
Diffstat (limited to 'program')
| -rw-r--r-- | program/js/app.js | 261 | ||||
| -rw-r--r-- | program/steps/settings/edit_folder.inc | 6 | ||||
| -rw-r--r-- | program/steps/settings/folders.inc | 44 | ||||
| -rw-r--r-- | program/steps/settings/func.inc | 23 | ||||
| -rw-r--r-- | program/steps/settings/save_folder.inc | 8 | 
5 files changed, 200 insertions, 142 deletions
| diff --git a/program/js/app.js b/program/js/app.js index a114c80d6..ea54b0b78 100644 --- a/program/js/app.js +++ b/program/js/app.js @@ -4016,7 +4016,6 @@ function rcube_webmail()      this.triggerEvent('group_update', { id:prop.id, source:prop.source, name:prop.name, li:li[0], newid:prop.newid });    }; -    this.init_edit_field = function(col, elem)    {      if (!elem) @@ -4179,21 +4178,6 @@ function rcube_webmail()    /*********        user settings methods          *********/    /*********************************************************/ -  this.init_subscription_list = function() -  { -    var p = this; -    this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist, -      {multiselect:false, draggable:true, keyboard:false, toggleselect:true}); -    this.subscription_list.addEventListener('select', function(o){ p.subscription_select(o); }); -    this.subscription_list.addEventListener('dragstart', function(o){ p.drag_active = true; }); -    this.subscription_list.addEventListener('dragend', function(o){ p.subscription_move_folder(o); }); -    this.subscription_list.row_init = function (row) { -      row.obj.onmouseover = function() { p.focus_subscription(row.id); }; -      row.obj.onmouseout = function() { p.unfocus_subscription(row.id); }; -    }; -    this.subscription_list.init(); -  }; -    // preferences section select and load options frame    this.section_select = function(list)    { @@ -4258,6 +4242,26 @@ function rcube_webmail()      return true;    }; + +  /*********************************************************/ +  /*********        folder manager methods         *********/ +  /*********************************************************/ + +  this.init_subscription_list = function() +  { +    var p = this; +    this.subscription_list = new rcube_list_widget(this.gui_objects.subscriptionlist, +      {multiselect:false, draggable:true, keyboard:false, toggleselect:true}); +    this.subscription_list.addEventListener('select', function(o){ p.subscription_select(o); }); +    this.subscription_list.addEventListener('dragstart', function(o){ p.drag_active = true; }); +    this.subscription_list.addEventListener('dragend', function(o){ p.subscription_move_folder(o); }); +    this.subscription_list.row_init = function (row) { +      row.obj.onmouseover = function() { p.focus_subscription(row.id); }; +      row.obj.onmouseout = function() { p.unfocus_subscription(row.id); }; +    }; +    this.subscription_list.init(); +  }; +    this.focus_subscription = function(id)    {      var row, folder, @@ -4347,91 +4351,183 @@ function rcube_webmail()      }    }; -  // add a new folder to the subscription list by cloning a folder row -  this.add_folder_row = function(name, display_name, replace, before) +  // Add folder row to the table and initialize it +  this.add_folder_row = function (name, display_name, protected, subscribed, skip_init)    {      if (!this.gui_objects.subscriptionlist)        return false; -    // find not protected folder -    var refid; -    for (var rid in this.env.subscriptionrows) { -      if (this.env.subscriptionrows[rid]!=null && !this.env.subscriptionrows[rid][2]) { -        refid = rid; -        break; -      } -    } - -    var refrow, form, +    var row, n, i, tmp, folders, len, list = [], slist = [],        tbody = this.gui_objects.subscriptionlist.tBodies[0], -      id = 'rcmrow'+(tbody.childNodes.length+1), -      selection = this.subscription_list.get_single_selection(); - -    if (replace && replace.id) { -      id = replace.id; -      refid = replace.id; -    } +      refrow = $('tr', tbody).get(0), +      id = 'rcmrow'+((new Date).getTime()); -    if (!id || !refid || !(refrow = document.getElementById(refid))) { +    if (!refrow) {        // Refresh page if we don't have a table row to clone        this.goto_url('folders');        return false;      }      // clone a table row if there are existing rows -    var row = this.clone_table_row(refrow); -    row.id = id; +    row    = $(refrow).clone(true); +    row.attr('id', id); -    if (before && (before = this.get_folder_row_id(before))) -      tbody.insertBefore(row, document.getElementById(before)); -    else -      tbody.appendChild(row); +    // set folder name +    row.find('td:first').html(display_name); -    if (replace) -      tbody.removeChild(replace); +    // update subscription checkbox +    $('input[name="_subscribed[]"]', row).val(name) +      .prop({checked: subscribed ? true : false, disabled: protected ? true : false});      // add to folder/row-ID map -    this.env.subscriptionrows[row.id] = [name, display_name, 0]; +    this.env.subscriptionrows[id] = [name, display_name, 0]; -    // set folder name -    row.cells[0].innerHTML = display_name; - -    if (!replace) { -      // set messages count to zero -      row.cells[1].innerHTML = '*'; +    // sort folders, to find a place where to insert the row +    folders = this.env.subscriptionrows; +    for (n in folders) { +      // protected folder +      if (folders[n][2]) { +        slist.push(folders[n][0]); +        tmp = folders[n][0]+this.env.delimiter; +      } +      // protected folder's child +      else if (tmp && folders[n][0].indexOf(tmp) == 0) +        slist.push(folders[n][0]); +      // other +      else { +        list.push(folders[n][0]); +        tmp = null; +      } +    } +    list.sort(); +    // make sure protected folders (and their subs) are on top +    list = slist.concat(list); -      // update subscription checkbox -      $('input[name="_subscribed[]"]', row).val(name).prop('checked', true); +    // find folder position after sorting +    for (n=0, len=list.length; n<len; n++) { +      if (list[n] == name) +        break;      } -    this.init_subscription_list(); -    if (selection && document.getElementById('rcmrow'+selection)) -      this.subscription_list.select_row(selection); +    // add row to the table +    if (n && n < len) +      $('#'+this.get_folder_row_id(list[n-1])).after(row); +    else +      row.appendTo(tbody); -    if (document.getElementById(id).scrollIntoView) -      document.getElementById(id).scrollIntoView(); +    // update list widget +    this.subscription_list.clear_selection(); +    if (!skip_init) +      this.init_subscription_list(); + +    row = row.get(0); +    if (row.scrollIntoView) +      row.scrollIntoView(); + +    return row;    }; -  // replace an existing table row with a new folder line -  this.replace_folder_row = function(oldfolder, newfolder, display_name, before) +  // replace an existing table row with a new folder line (with subfolders) +  this.replace_folder_row = function(oldfolder, newfolder, display_name, protected)    { -    var id = this.get_folder_row_id(oldfolder), -      row = document.getElementById(id); +    if (!this.gui_objects.subscriptionlist) +      return false; + +    var i, n, len, name, dispname, oldrow, tmprow, row, level, +      tbody = this.gui_objects.subscriptionlist.tBodies[0], +      folders = this.env.subscriptionrows, +      id = this.get_folder_row_id(oldfolder), +      regex = new RegExp('^'+RegExp.escape(oldfolder)), +      subscribed = $('input[name="_subscribed[]"]', $('#'+id)).prop('checked'), +      // find subfolders of renamed folder +      list = this.get_subfolders(oldfolder); -    // replace an existing table row (if found) -    this.add_folder_row(newfolder, display_name, row, before); +    // replace an existing table row +    this._remove_folder_row(id); +    row = $(this.add_folder_row(newfolder, display_name, protected, subscribed, true)); + +    // detect tree depth change +    if (len = list.length) { +      level = (oldfolder.split(this.env.delimiter)).length - (newfolder.split(this.env.delimiter)).length; +    } + +    // move subfolders to the new branch +    for (n=0; n<len; n++) { +      id = list[n]; +      name = this.env.subscriptionrows[id][0]; +      dispname = this.env.subscriptionrows[id][1]; +      oldrow = $('#'+id); +      tmprow = oldrow.clone(true); +      oldrow.remove(); +      row.after(tmprow); +      row = tmprow; +      // update folder index +      name = name.replace(regex, newfolder); +      $('input[name="_subscribed[]"]', row).val(name); +      this.env.subscriptionrows[id][0] = name; +      // update the name if level is changed +      if (level != 0) { +        if (level > 0) { +          for (i=level; i>0; i--) +            dispname = dispname.replace(/^    /, ''); +        } +        else { +          for (i=level; i<0; i++) +            dispname = '    ' + dispname; +        } +        row.find('td:first').html(dispname); +        this.env.subscriptionrows[id][1] = dispname; +      } +    } + +    // update list widget +    this.init_subscription_list();    };    // remove the table row of a specific mailbox from the table -  // (the row will not be removed, just hidden) -  this.remove_folder_row = function(folder) +  this.remove_folder_row = function(folder, subs)    { -    var row, id = this.get_folder_row_id(folder); +    var n, len, list = [], id = this.get_folder_row_id(folder); + +    // get subfolders if any +    if (subs) +      list = this.get_subfolders(folder); -    if (id && (row = document.getElementById(id))) -      row.style.display = 'none'; +    // remove old row +    this._remove_folder_row(id); + +    // remove subfolders +    for (n=0, len=list.length; n<len; n++) +      this._remove_folder_row(list[n]);    }; +  this._remove_folder_row = function(id) +  { +    this.subscription_list.remove_row(id.replace(/^rcmrow/, '')); +    $('#'+id).remove(); +    delete this.env.subscriptionrows[id]; +  } + +  this.get_subfolders = function(folder) +  { +    var name, list = [], +      regex = new RegExp('^'+RegExp.escape(folder)+RegExp.escape(this.env.delimiter)), +      row = $('#'+this.get_folder_row_id(folder)).get(0); + +    while (row = row.nextSibling) { +      if (row.id) { +        name = this.env.subscriptionrows[row.id][0]; +        if (regex.test(name)) { +          list.push(row.id); +        } +        else +          break; +      } +    } + +    return list; +  } +    this.subscribe = function(folder)    {      if (folder) { @@ -4451,35 +4547,14 @@ function rcube_webmail()    // helper method to find a specific mailbox row ID    this.get_folder_row_id = function(folder)    { -    for (var id in this.env.subscriptionrows) -      if (this.env.subscriptionrows[id] && this.env.subscriptionrows[id][0] == folder) +    var id, folders = this.env.subscriptionrows; +    for (id in folders) +      if (folders[id] && folders[id][0] == folder)          break;      return id;    }; -  // duplicate a specific table row -  this.clone_table_row = function(row) -  { -    var cell, td, -      new_row = document.createElement('tr'); - -    for (var n=0; n<row.cells.length; n++) { -      cell = row.cells[n]; -      td = document.createElement('td'); - -      if (cell.className) -        td.className = cell.className; -      if (cell.align) -        td.setAttribute('align', cell.align); - -      td.innerHTML = cell.innerHTML; -      new_row.appendChild(td); -    } - -    return new_row; -  }; -    // when user select a folder in manager    this.show_folder = function(folder, path, force)    { diff --git a/program/steps/settings/edit_folder.inc b/program/steps/settings/edit_folder.inc index bc4310310..0bc7ab657 100644 --- a/program/steps/settings/edit_folder.inc +++ b/program/steps/settings/edit_folder.inc @@ -24,7 +24,7 @@  // init IMAP connection  $RCMAIL->imap_connect(); -function rcube_folder_form($attrib) +function rcmail_folder_form($attrib)  {      global $RCMAIL; @@ -41,7 +41,7 @@ function rcube_folder_form($attrib)      // Get mailbox parameters      if (strlen($mbox)) { -        $options   = rcube_folder_options($mbox_imap); +        $options   = rcmail_folder_options($mbox_imap);          $namespace = $RCMAIL->imap->get_namespace();          $path   = explode($delimiter, $mbox_imap); @@ -319,7 +319,7 @@ function rcmail_localize_folderpath($path)  // register UI objects  $OUTPUT->add_handlers(array( -    'folderdetails' => 'rcube_folder_form', +    'folderdetails' => 'rcmail_folder_form',  ));  $OUTPUT->add_label('nonamewarning'); diff --git a/program/steps/settings/folders.inc b/program/steps/settings/folders.inc index bc95c7506..a9068099b 100644 --- a/program/steps/settings/folders.inc +++ b/program/steps/settings/folders.inc @@ -76,24 +76,12 @@ else if ($RCMAIL->action == 'delete-folder')      $mbox_utf8 = get_input_value('_mbox', RCUBE_INPUT_POST, true);      $mbox      = rcube_charset_convert($mbox_utf8, RCMAIL_CHARSET, 'UTF7-IMAP'); -    // get folder's children or all folders if the name contains special characters -    $delimiter = $IMAP->get_hierarchy_delimiter(); -    if ((strpos($mbox, '%') === false) && (strpos($mbox, '*') === false)) -        $a_mboxes  = $IMAP->list_unsubscribed('', $mbox.$delimiter.'*'); -    else -        $a_mboxes  = $IMAP->list_unsubscribed(); -      if (strlen($mbox))          $deleted = $IMAP->delete_mailbox($mbox);      if ($OUTPUT->ajax_call && $deleted) {          // Remove folder and subfolders rows -        $OUTPUT->command('remove_folder_row', $mbox_utf8); -        foreach ($a_mboxes as $folder) { -            if (preg_match('/^'. preg_quote($mbox.$delimiter, '/') .'/', $folder)) { -                $OUTPUT->command('remove_folder_row', rcube_charset_convert($folder, 'UTF7-IMAP')); -            } -        } +        $OUTPUT->command('remove_folder_row', $mbox_utf8, true);          $OUTPUT->show_message('folderdeleted', 'confirmation');          // Clear content frame          $OUTPUT->command('subscription_select'); @@ -118,34 +106,7 @@ else if ($RCMAIL->action == 'rename-folder')      }      if ($rename && $OUTPUT->ajax_call) { -        $folderlist = $IMAP->list_unsubscribed(); -        $delimiter  = $IMAP->get_hierarchy_delimiter(); - -        $regexp = '/^' . preg_quote($name . $delimiter, '/') . '/'; - -        // subfolders -        for ($x=sizeof($folderlist)-1; $x>=0; $x--) { -            if (preg_match($regexp, $folderlist[$x])) { -                $oldfolder   = $oldname . $delimiter . preg_replace($regexp, '', $folderlist[$x]); -                $foldersplit = explode($delimiter, $IMAP->mod_mailbox($folderlist[$x])); -                $level       = count($foldersplit) - 1; -                $display_rename = str_repeat('    ', $level)  -                    . rcube_charset_convert($foldersplit[$level], 'UTF7-IMAP'); -                $before = isset($folderlist[$x+1]) ? rcube_charset_convert($folderlist[$x+1], 'UTF7-IMAP') : false; - -                $OUTPUT->command('replace_folder_row', rcube_charset_convert($oldfolder, 'UTF7-IMAP'), -                    rcube_charset_convert($folderlist[$x], 'UTF7-IMAP'), $display_rename, $before); -            } -        } - -        $index       = array_search($name, $folderlist); -        $name        = $IMAP->mod_mailbox($name); -        $foldersplit = explode($delimiter, $name); -        $level       = count($foldersplit) - 1; -        $display_rename = str_repeat('    ', $level) . rcube_charset_convert($foldersplit[$level], 'UTF7-IMAP'); -        $before         = $index !== false && isset($folderlist[$index+1]) ? rcube_charset_convert($folderlist[$index+1], 'UTF7-IMAP') : false; - -        $OUTPUT->command('replace_folder_row', $oldname_utf8, $name_utf8, $display_rename, $before); +        rcmail_update_folder_row($name, $oldname);      }      else if (!$rename) {          rcmail_display_server_error('errorsaving'); @@ -375,6 +336,7 @@ function rcmail_rename_folder($oldname, $newname)      return false;  } +  $OUTPUT->set_pagetitle(rcube_label('folders'));  $OUTPUT->include_script('list.js');  $OUTPUT->set_env('quota', $IMAP->get_capability('QUOTA')); diff --git a/program/steps/settings/func.inc b/program/steps/settings/func.inc index b204d9bc9..a44d6c8ff 100644 --- a/program/steps/settings/func.inc +++ b/program/steps/settings/func.inc @@ -747,7 +747,7 @@ function rcmail_get_skins()  } -function rcube_folder_options($mailbox) +function rcmail_folder_options($mailbox)  {      global $RCMAIL; @@ -785,6 +785,27 @@ function rcube_folder_options($mailbox)      return $options;      } +// Updates (or creates) folder row in the subscriptions table +function rcmail_update_folder_row($name, $oldname=null) +{ +    global $IMAP, $CONFIG, $OUTPUT; + +    $delimiter    = $IMAP->get_hierarchy_delimiter(); +    $name_utf8    = rcube_charset_convert($name, 'UTF7-IMAP'); +    $protected    = ($CONFIG['protect_default_folders'] == true && in_array($name, $CONFIG['default_imap_folders'])); + +    $foldersplit  = explode($delimiter, $IMAP->mod_mailbox($name)); +    $level        = count($foldersplit) - 1; +    $display_name = str_repeat('    ', $level) +        . Q($protected ? rcmail_localize_foldername($name) : rcube_charset_convert($foldersplit[$level], 'UTF7-IMAP')); + +    if ($oldname === null) +        $OUTPUT->command('add_folder_row', $name_utf8, $display_name, $protected, true); +    else +        $OUTPUT->command('replace_folder_row', rcube_charset_convert($oldname, 'UTF7-IMAP'), +            $name_utf8, $display_name, $protected); +} +  // register UI objects  $OUTPUT->add_handlers(array( diff --git a/program/steps/settings/save_folder.inc b/program/steps/settings/save_folder.inc index c1120961b..a4e752c90 100644 --- a/program/steps/settings/save_folder.inc +++ b/program/steps/settings/save_folder.inc @@ -34,7 +34,7 @@ $old_imap  = rcube_charset_convert($old, RCMAIL_CHARSET, 'UTF7-IMAP');  // $path is in UTF7-IMAP already  $delimiter = $IMAP->get_hierarchy_delimiter(); -$options = strlen($old_imap) ? rcube_folder_options($old_imap) : array(); +$options = strlen($old_imap) ? rcmail_folder_options($old_imap) : array();  // Folder name checks  if ($options['protected'] || $options['norename']) { @@ -105,9 +105,9 @@ if (!$error && !strlen($old)) {              $RCMAIL->user->save_prefs(array('message_threading' => $a_threaded));          } - +   +        rcmail_update_folder_row($folder['name']);          $OUTPUT->show_message('foldercreated', 'confirmation'); -        $OUTPUT->command('reload', 250);          $OUTPUT->send('iframe');      }      else { @@ -163,7 +163,7 @@ else if (!$error) {          $OUTPUT->show_message('folderupdated', 'confirmation');          if ($rename) { -            $OUTPUT->command('reload', 250); +            rcmail_update_folder_row($folder['name'], $folder['oldname']);              $OUTPUT->send('iframe');          }      } | 
