Thomas Bruederli
2014-08-18 3ebac0167bf20104fb7a2a55934765117760264c
program/js/app.js
@@ -236,8 +236,6 @@
            return ref.command('sort', $(this).attr('rel'), this);
          });
          this.gui_objects.messagelist.parentNode.onclick = function(e){ return ref.click_on_list(e || window.event); };
          this.enable_command('toggle_status', 'toggle_flag', 'sort', true);
          this.enable_command('set-listmode', this.env.threads && !this.is_multifolder_listing());
@@ -405,8 +403,6 @@
            .addEventListener('dragmove', function(e) { ref.drag_move(e); })
            .addEventListener('dragend', function(e) { ref.drag_end(e); })
            .init();
          this.gui_objects.contactslist.parentNode.onmousedown = function(e){ return ref.click_on_list(e); };
          $(this.gui_objects.qsearchbox).focusin(function() { ref.contact_list.blur(); });
@@ -1056,7 +1052,7 @@
        if (this.task == 'mail') {
          url._mbox = this.env.mailbox;
          if (props)
             url._to = props;
            url._to = props;
          // also send search request so we can go back to search result after message is sent
          if (this.env.search_request)
            url._search = this.env.search_request;
@@ -1084,8 +1080,12 @@
            break;
          }
        }
        else if (props)
        else if (props && typeof props == 'string') {
          url._to = props;
        }
        else if (props && typeof props == 'object') {
          $.extend(url, props);
        }
        this.open_compose_step(url);
        break;
@@ -1451,7 +1451,7 @@
  this.is_framed = function()
  {
    return (this.env.framed && parent.rcmail && parent.rcmail != this && parent.rcmail.command);
    return this.env.framed && parent.rcmail && parent.rcmail != this && typeof parent.rcmail.command == 'function';
  };
  this.save_pref = function(prop)
@@ -1713,19 +1713,6 @@
    return true;
  }
  this.click_on_list = function(e)
  {
    if (this.gui_objects.qsearchbox)
      this.gui_objects.qsearchbox.blur();
    if (this.message_list)
      this.message_list.focus(e);
    else if (this.contact_list)
      this.contact_list.focus(e);
    return true;
  };
  this.msglist_select = function(list)
  {
@@ -4752,6 +4739,7 @@
  this.list_contacts = function(src, group, page)
  {
    var win, folder, url = {},
      refresh = src === undefined && group === undefined && page === undefined,
      target = window;
    if (!src)
@@ -4764,7 +4752,7 @@
      page = this.env.current_page = 1;
      this.reset_qsearch();
    }
    else if (group != this.env.group)
    else if (!refresh && group != this.env.group)
      page = this.env.current_page = 1;
    if (this.env.search_id)
@@ -4902,6 +4890,9 @@
    if (action && (cid || action == 'add') && !this.drag_active) {
      if (this.env.group)
        url._gid = this.env.group;
      if (this.env.search_request)
        url._search = this.env.search_request;
      url._action = action;
      url._source = this.env.source;
@@ -5156,29 +5147,55 @@
        .submit(function() { $('input.mainaction').click(); return false; });
  };
  // group creation dialog
  this.group_create = function()
  {
    this.add_input_row('contactgroup');
    var input = $('<input>').attr('type', 'text'),
      content = $('<label>').text(this.get_label('namex')).append(input);
    this.show_popup_dialog(content, this.get_label('newgroup'),
      [{
        text: this.get_label('save'),
        click: function() {
          var name;
          if (name = input.val()) {
            ref.http_post('group-create', {_source: ref.env.source, _name: name},
              ref.set_busy(true, 'loading'));
          }
          $(this).dialog('close');
        }
      }]
    );
  };
  // group rename dialog
  this.group_rename = function()
  {
    if (!this.env.group || !this.gui_objects.folderlist)
    if (!this.env.group)
      return;
    if (!this.name_input) {
      this.enable_command('list', 'listgroup', false);
      this.name_input = $('<input>').attr('type', 'text').val(this.env.contactgroups['G'+this.env.source+this.env.group].name);
      this.name_input.bind('keydown', function(e) { return ref.add_input_keydown(e); });
      this.env.group_renaming = true;
    var group_name = this.env.contactgroups['G' + this.env.source + this.env.group].name,
      input = $('<input>').attr('type', 'text').val(group_name),
      content = $('<label>').text(this.get_label('namex')).append(input);
      var link, li = this.get_folder_li('G'+this.env.source+this.env.group,'',true);
      if (li && (link = li.firstChild)) {
        $(link).hide().before(this.name_input);
      }
    }
    this.show_popup_dialog(content, this.get_label('grouprename'),
      [{
        text: this.get_label('save'),
        click: function() {
          var name;
    this.name_input.select().focus();
          if ((name = input.val()) && name != group_name) {
            ref.http_post('group-rename', {_source: ref.env.source, _gid: ref.env.group, _name: name},
              ref.set_busy(true, 'loading'));
          }
          $(this).dialog('close');
        }
      }],
      {open: function() { input.select(); }}
    );
  };
  this.group_delete = function()
@@ -5203,38 +5220,6 @@
    this.list_contacts(prop.source, 0);
  };
  // @TODO: maybe it would be better to use popup instead of inserting input to the list?
  this.add_input_row = function(type)
  {
    if (!this.gui_objects.folderlist)
      return;
    if (!this.name_input) {
      this.name_input = $('<input>').attr('type', 'text').data('tt', type);
      this.name_input.bind('keydown', function(e) { return ref.add_input_keydown(e); });
      this.name_input_li = $('<li>').addClass(type).append(this.name_input);
      var ul, li;
      // find list (UL) element
      if (type == 'contactsearch')
        ul = this.gui_objects.savedsearchlist;
      else
        ul = $('ul.groups', this.get_folder_li(this.env.source,'',true));
      // append to the list
      li = $('li:last', ul);
      if (li.length)
        this.name_input_li.insertAfter(li);
      else {
        this.name_input_li.appendTo(ul);
        ul.show(); // make sure the list is visible
      }
    }
    this.name_input.select().focus();
  };
  //remove selected contacts from current active group
  this.group_remove_selected = function()
  {
@@ -5254,62 +5239,9 @@
    }
  };
  // handler for keyboard events on the input field
  this.add_input_keydown = function(e)
  {
    var key = rcube_event.get_keycode(e),
      input = $(e.target), itype = input.data('tt');
    // enter
    if (key == 13) {
      var newname = input.val();
      if (newname) {
        var lock = this.set_busy(true, 'loading');
        if (itype == 'contactsearch')
          this.http_post('search-create', {_search: this.env.search_request, _name: newname}, lock);
        else if (this.env.group_renaming)
          this.http_post('group-rename', {_source: this.env.source, _gid: this.env.group, _name: newname}, lock);
        else
          this.http_post('group-create', {_source: this.env.source, _name: newname}, lock);
      }
      return false;
    }
    // escape
    else if (key == 27)
      this.reset_add_input();
    return true;
  };
  this.reset_add_input = function()
  {
    if (this.name_input) {
      var li = this.name_input.parent();
      if (this.env.group_renaming) {
        li.children().last().show();
        this.env.group_renaming = false;
      }
      else if ($('li', li.parent()).length == 1)
        li.parent().hide();
      this.name_input.remove();
      if (this.name_input_li)
        this.name_input_li.remove();
      this.name_input = this.name_input_li = null;
    }
    this.enable_command('list', 'listgroup', true);
  };
  // callback for creating a new contact group
  this.insert_contact_group = function(prop)
  {
    this.reset_add_input();
    prop.type = 'group';
    var key = 'G'+prop.source+prop.id,
@@ -5327,8 +5259,6 @@
  // callback for renaming a contact group
  this.update_contact_group = function(prop)
  {
    this.reset_add_input();
    var key = 'G'+prop.source+prop.id,
      newnode = {};
@@ -5592,8 +5522,6 @@
  // callback for creating a new saved search record
  this.insert_saved_search = function(name, id)
  {
    this.reset_add_input();
    var key = 'S'+id,
      link = $('<a>').attr('href', '#')
        .attr('rel', id)
@@ -5609,10 +5537,27 @@
    this.triggerEvent('abook_search_insert', prop);
  };
  // creates an input for saved search name
  // creates a dialog for saved search
  this.search_create = function()
  {
    this.add_input_row('contactsearch');
    var input = $('<input>').attr('type', 'text'),
      content = $('<label>').text(this.get_label('namex')).append(input);
    this.show_popup_dialog(content, this.get_label('searchsave'),
      [{
        text: this.get_label('save'),
        click: function() {
          var name;
          if (name = input.val()) {
            ref.http_post('search-create', {_search: ref.env.search_request, _name: name},
              ref.set_busy(true, 'loading'));
          }
          $(this).dialog('close');
        }
      }]
    );
  };
  this.search_delete = function()
@@ -5800,15 +5745,18 @@
    this.subscription_list = new rcube_treelist_widget(this.gui_objects.subscriptionlist, {
        selectable: true,
        tabexit: false,
        id_prefix: 'rcmli',
        id_encode: this.html_identifier_encode,
        id_decode: this.html_identifier_decode
        id_decode: this.html_identifier_decode,
        searchbox: '#foldersearch'
    });
    this.subscription_list
      .addEventListener('select', function(node) { ref.subscription_select(node.id); })
      .addEventListener('collapse', function(node) { ref.folder_collapsed(node) })
      .addEventListener('expand', function(node) { ref.folder_collapsed(node) })
      .addEventListener('search', function(p) { if (p.query) ref.subscription_select(); })
      .draggable({cancel: 'li.mailbox.root'})
      .droppable({
        // @todo: find better way, accept callback is executed for every folder
@@ -5891,6 +5839,12 @@
    if (!this.gui_objects.subscriptionlist)
      return false;
    // reset searching
    if (this.subscription_list.is_search()) {
      this.subscription_select();
      this.subscription_list.reset_search();
    }
    // disable drag-n-drop temporarily
    this.subscription_list.draggable('destroy').droppable('destroy');
@@ -5909,8 +5863,9 @@
    row.attr({id: 'rcmli' + this.html_identifier_encode(id), 'class': class_name});
    if (!refrow || !refrow.length) {
      // remove old subfolders and toggle
      // remove old data, subfolders and toggle
      $('ul,div.treetoggle', row).remove();
      row.removeData('filtered');
    }
    // set folder name
@@ -6037,7 +5992,7 @@
      this.subscription_list.expand(this.folder_id2name(parent.id));
    }
    row = row.get(0);
    row = row.show().get(0);
    if (row.scrollIntoView)
      row.scrollIntoView();
@@ -6048,10 +6003,18 @@
  this.replace_folder_row = function(oldid, id, name, display_name, is_protected, class_name)
  {
    if (!this.gui_objects.subscriptionlist) {
      if (this.is_framed)
        return parent.rcmail.replace_folder_row(oldid, id, name, display_name, is_protected, class_name);
      if (this.is_framed()) {
        // @FIXME: for some reason this 'parent' variable need to be prefixed with 'window.'
        return window.parent.rcmail.replace_folder_row(oldid, id, name, display_name, is_protected, class_name);
      }
      return false;
    }
    // reset searching
    if (this.subscription_list.is_search()) {
      this.subscription_select();
      this.subscription_list.reset_search();
    }
    var subfolders = {},
@@ -6099,6 +6062,12 @@
  // remove the table row of a specific mailbox from the table
  this.remove_folder_row = function(folder)
  {
    // reset searching
    if (this.subscription_list.is_search()) {
      this.subscription_select();
      this.subscription_list.reset_search();
    }
    var list = [], row = this.subscription_list.get_item(folder, true);
    // get subfolders if any
@@ -6167,6 +6136,37 @@
    $('#folder-size').replaceWith(size);
  };
  // filter folders by namespace
  this.folder_filter = function(prefix)
  {
    this.subscription_list.reset_search();
    this.subscription_list.container.children('li').each(function() {
      var i, folder = ref.folder_id2name(this.id);
      // show all folders
      if (prefix == '---') {
      }
      // got namespace prefix
      else if (prefix) {
        if (folder !== prefix) {
          $(this).data('filtered', true).hide();
          return
        }
      }
      // no namespace prefix, filter out all other namespaces
      else {
        // first get all namespace roots
        for (i in ref.env.ns_roots) {
          if (folder === ref.env.ns_roots[i]) {
            $(this).data('filtered', true).hide();
            return;
          }
        }
      }
      $(this).removeData('filtered').show();
    });
  };
  /*********************************************************/
  /*********           GUI functionality           *********/
@@ -6470,22 +6470,27 @@
  };
  // open a jquery UI dialog with the given content
  this.show_popup_dialog = function(html, title, buttons, options)
  this.show_popup_dialog = function(content, title, buttons, options)
  {
    // forward call to parent window
    if (this.is_framed()) {
      return parent.rcmail.show_popup_dialog(html, title, buttons, options);
      return parent.rcmail.show_popup_dialog(content, title, buttons, options);
    }
    var popup = $('<div class="popup">')
      .html(html)
      .dialog($.extend({
    var popup = $('<div class="popup">');
    if (typeof content == 'object')
      popup.append(content);
    else
      popup.html(content);
    popup.dialog($.extend({
        title: title,
        buttons: buttons,
        modal: true,
        resizable: true,
        width: 500,
        close: function(event, ui) { $(this).remove() }
        close: function(event, ui) { $(this).remove(); }
      }, options || {}));
    // resize and center popup