thomascube
2011-09-28 65082b3adbfaa04c4aff7c41147bb43e34941106
program/js/app.js
@@ -278,6 +278,9 @@
        if (this.gui_objects.folderlist)
          this.env.contactfolders = $.extend($.extend({}, this.env.address_sources), this.env.contactgroups);
        this.enable_command('add', 'import', this.env.writable_source);
        this.enable_command('list', 'listgroup', 'listsearch', 'advanced-search', true);
        if (this.gui_objects.contactslist) {
          this.contact_list = new rcube_list_widget(this.gui_objects.contactslist,
@@ -300,6 +303,7 @@
          }
          this.update_group_commands();
          this.command('list');
        }
        this.set_page_buttons();
@@ -319,21 +323,12 @@
          if (this.env.action == 'add' || this.env.action == 'edit')
              this.init_contact_form();
        }
        if (this.gui_objects.qsearchbox) {
          this.enable_command('search', 'reset-search', 'moveto', true);
        }
        if (this.contact_list && this.contact_list.rowcount > 0)
          this.enable_command('export', true);
        this.enable_command('add', 'import', this.env.writable_source);
        this.enable_command('list', 'listgroup', 'listsearch', 'advanced-search', true);
        // load contacts of selected source
        if (!this.env.action)
          this.command('list', this.env.source);
        break;
      case 'settings':
        this.enable_command('preferences', 'identities', 'save', 'folders', true);
@@ -385,7 +380,10 @@
          $('#rcmloginpwd').focus();
        // detect client timezone
        $('#rcmlogintz').val(new Date().getTimezoneOffset() / -60);
        var tz = new Date().getTimezoneOffset() / -60;
        var stdtz = new Date().getStdTimezoneOffset() / -60;
        $('#rcmlogintz').val(stdtz);
        $('#rcmlogindst').val(tz > stdtz ? 0 : 0);
        // display 'loading' message on form submit, lock submit button
        $('form').submit(function () {
@@ -444,6 +442,8 @@
  // execute a specific command on the web client
  this.command = function(command, props, obj)
  {
    var ret;
    if (obj && obj.blur)
      obj.blur();
@@ -467,24 +467,26 @@
    // process external commands
    if (typeof this.command_handlers[command] === 'function') {
      var ret = this.command_handlers[command](props, obj);
      ret = this.command_handlers[command](props, obj);
      return ret !== undefined ? ret : (obj ? false : true);
    }
    else if (typeof this.command_handlers[command] === 'string') {
      var ret = window[this.command_handlers[command]](props, obj);
      ret = window[this.command_handlers[command]](props, obj);
      return ret !== undefined ? ret : (obj ? false : true);
    }
    // trigger plugin hooks
    this.triggerEvent('actionbefore', {props:props, action:command});
    var ret = this.triggerEvent('before'+command, props);
    ret = this.triggerEvent('before'+command, props);
    if (ret !== undefined) {
      // abort if one the handlers returned false
      // abort if one of the handlers returned false
      if (ret === false)
        return false;
      else
        props = ret;
    }
    ret = undefined;
    // process internal command
    switch (command) {
@@ -847,6 +849,8 @@
          break;
        }
        else if (props)
          url += '&_to='+urlencode(props);
        this.redirect(url);
        break;
@@ -1048,15 +1052,17 @@
      // unified command call (command name == function name)
      default:
        var func = command.replace(/-/g, '_');
        if (this[func] && typeof this[func] === 'function')
          this[func](props);
        if (this[func] && typeof this[func] === 'function') {
          ret = this[func](props);
        }
        break;
    }
    this.triggerEvent('after'+command, props);
    if (this.triggerEvent('after'+command, props) === false)
      ret = false;
    this.triggerEvent('actionafter', {props:props, action:command});
    return obj ? false : true;
    return ret === false ? false : obj ? false : true;
  };
  // set command(s) enabled or disabled
@@ -1401,6 +1407,10 @@
  {
    var model, list, li, id;
    // ignore event if jquery UI dialog is open
    if ($(rcube_event.get_target(e)).closest('.ui-dialog, .ui-widget-overlay').length)
      return;
    if (list = this.message_list) {
      if (!rcube_mouse_is_over(e, list.list.parentNode))
        list.blur();
@@ -1639,6 +1649,10 @@
  this.add_message_row = function(uid, cols, flags, attop)
  {
    if (!this.gui_objects.messagelist || !this.message_list)
      return false;
    // Prevent from adding messages from different folder (#1487752)
    if (flags.mbox != this.env.mailbox && !flags.skip_mbox_check)
      return false;
    if (!this.env.messages[uid])
@@ -2091,8 +2105,12 @@
  };
  // Initializes threads indicators/expanders after list update
  this.init_threads = function(roots)
  this.init_threads = function(roots, mbox)
  {
    // #1487752
    if (mbox && mbox != this.env.mailbox)
      return false;
    for (var n=0, len=roots.length; n<len; n++)
      this.add_tree_icons(roots[n]);
    this.expand_threads();
@@ -3495,13 +3513,15 @@
        return rcube_event.cancel(e);
      case 9:  // tab
        if (mod == SHIFT_KEY)
          break;
      case 9:   // tab
        if (mod == SHIFT_KEY || !this.ksearch_visible()) {
          this.ksearch_hide();
          return;
        }
      case 13:  // enter
        if (this.ksearch_selected === null || !this.ksearch_value)
          break;
        if (!this.ksearch_visible())
          return false;
        // insert selected address and hide ksearch pane
        this.insert_recipient(this.ksearch_selected);
@@ -3524,6 +3544,11 @@
    this.ksearch_input = obj;
    return true;
  };
  this.ksearch_visible = function()
  {
    return (this.ksearch_selected !== null && this.ksearch_selected !== undefined && this.ksearch_value);
  };
  this.ksearch_select = function(node)
@@ -3603,7 +3628,8 @@
    var cpos = this.get_caret_pos(this.ksearch_input),
      p = inp_value.lastIndexOf(',', cpos-1),
      q = inp_value.substring(p+1, cpos),
      min = this.env.autocomplete_min_length;
      min = this.env.autocomplete_min_length,
      ac = this.ksearch_data;
    // trim query string
    q = $.trim(q);
@@ -3612,28 +3638,25 @@
    if (q == this.ksearch_value)
      return;
    this.ksearch_destroy();
    if (q.length && q.length < min) {
      if (!this.env.acinfo) {
        this.env.acinfo = this.display_message(
      if (!this.ksearch_info) {
        this.ksearch_info = this.display_message(
          this.get_label('autocompletechars').replace('$min', min));
      }
      return;
    }
    else if (this.env.acinfo) {
      this.hide_message(this.env.acinfo);
    }
    var old_value = this.ksearch_value;
    this.ksearch_value = q;
    this.ksearch_destroy();
    // ...string is empty
    if (!q.length)
      return;
    // ...new search value contains old one and previous search result was empty
    if (old_value && old_value.length && this.env.contacts && !this.env.contacts.length && q.indexOf(old_value) == 0)
    // ...new search value contains old one and previous search was not finished or its result was empty
    if (old_value && old_value.length && q.indexOf(old_value) == 0 && (!ac || !ac.num) && this.env.contacts && !this.env.contacts.length)
      return;
    var i, lock, source, xhr, reqid = new Date().getTime(),
@@ -3641,7 +3664,8 @@
      sources = props && props.sources ? props.sources : [],
      action = props && props.action ? props.action : 'mail/autocomplete';
    this.ksearch_data = {id: reqid, sources: sources.slice(), action: action, locks: [], requests: []};
    this.ksearch_data = {id: reqid, sources: sources.slice(), action: action,
      locks: [], requests: [], num: sources.length};
    for (i=0; i<threads; i++) {
      source = this.ksearch_data.sources.shift();
@@ -3668,7 +3692,9 @@
      return;
    // display search results
    var p, ul, li, text, init, s_val = this.ksearch_value,
    var ul, li, text, init,
      value = this.ksearch_value,
      data = this.ksearch_data,
      maxlen = this.env.autocomplete_max ? this.env.autocomplete_max : 15;
    // create results pane if not present
@@ -3701,7 +3727,7 @@
      for (i=0; i < results.length && maxlen > 0; i++) {
        text = typeof results[i] === 'object' ? results[i].name : results[i];
        li = document.createElement('LI');
        li.innerHTML = text.replace(new RegExp('('+RegExp.escape(s_val)+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>');
        li.innerHTML = text.replace(new RegExp('('+RegExp.escape(value)+')', 'ig'), '##$1%%').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/##([^%]+)%%/g, '<b>$1</b>');
        li.onmouseover = function(){ ref.ksearch_select(this); };
        li.onmouseup = function(){ ref.ksearch_click(this) };
        li._rcm_id = this.env.contacts.length + i;
@@ -3723,15 +3749,24 @@
      this.env.contacts = this.env.contacts.concat(results);
    // run next parallel search
    if (maxlen > 0 && this.ksearch_data.id == reqid && this.ksearch_data.sources.length) {
      var lock, xhr, props = this.ksearch_data, source = props.sources.shift();
      if (source) {
        lock = this.display_message(this.get_label('searching'), 'loading');
        xhr = this.http_post(props.action, '_search='+urlencode(s_val)+'&_id='+reqid
          +'&_source='+urlencode(source), lock);
    if (data.id == reqid) {
      data.num--;
      if (maxlen > 0 && data.sources.length) {
        var lock, xhr, source = data.sources.shift();
        if (source) {
          lock = this.display_message(this.get_label('searching'), 'loading');
          xhr = this.http_post(data.action, '_search='+urlencode(value)+'&_id='+reqid
            +'&_source='+urlencode(source), lock);
        this.ksearch_data.locks.push(lock);
        this.ksearch_data.requests.push(xhr);
          this.ksearch_data.locks.push(lock);
          this.ksearch_data.requests.push(xhr);
        }
      }
      else if (!maxlen) {
        if (!this.ksearch_msg)
          this.ksearch_msg = this.display_message(this.get_label('autocompletemore'));
        // abort pending searches
        this.ksearch_abort();
      }
    }
  };
@@ -3765,8 +3800,24 @@
    this.ksearch_destroy();
  };
  // Aborts pending autocomplete requests
  // Clears autocomplete data/requests
  this.ksearch_destroy = function()
  {
    this.ksearch_abort();
    if (this.ksearch_info)
      this.hide_message(this.ksearch_info);
    if (this.ksearch_msg)
      this.hide_message(this.ksearch_msg);
    this.ksearch_data = null;
    this.ksearch_info = null;
    this.ksearch_msg = null;
  }
  // Aborts pending autocomplete requests
  this.ksearch_abort = function()
  {
    var i, len, ac = this.ksearch_data;
@@ -3775,9 +3826,8 @@
    for (i=0, len=ac.locks.length; i<len; i++)
      this.abort_request({request: ac.requests[i], lock: ac.locks[i]});
  };
    this.ksearch_data = null;
  }
  /*********************************************************/
  /*********         address book methods          *********/
@@ -3978,8 +4028,10 @@
  this.delete_contacts = function()
  {
    // exit if no mailbox specified or if selection is empty
    var selection = this.contact_list.get_selection();
    if (!(selection.length || this.env.cid) || !confirm(this.get_label('deletecontactconfirm')))
    var selection = this.contact_list.get_selection(),
      undelete = this.env.address_sources[this.env.source].undelete;
    if (!(selection.length || this.env.cid) || (!undelete && !confirm(this.get_label('deletecontactconfirm'))))
      return;
    var id, n, a_cids = [], qs = '';
@@ -4006,7 +4058,10 @@
      qs += '&_search='+this.env.search_request;
    // send request to server
    this.http_post('delete', '_cid='+urlencode(a_cids.join(','))+'&_source='+urlencode(this.env.source)+'&_from='+(this.env.action ? this.env.action : '')+qs);
    this.http_post('delete', '_cid='+urlencode(a_cids.join(','))
      +'&_source='+urlencode(this.env.source)
      +'&_from='+(this.env.action ? this.env.action : '')+qs,
      this.display_message(this.get_label('contactdeleting'), 'loading'));
    return true;
  };
@@ -5433,8 +5488,12 @@
  };
  // replace content of row count display
  this.set_rowcount = function(text)
  this.set_rowcount = function(text, mbox)
  {
    // #1487752
    if (mbox && mbox != this.env.mailbox)
      return false;
    $(this.gui_objects.countdisplay).html(text);
    // update page navigation buttons