Thomas Bruederli
2014-09-26 fef904c6b16a83ee9aa6dfb7eff35d2934b07d19
program/js/app.js
@@ -187,6 +187,11 @@
    if (this.env.permaurl)
      this.enable_command('permaurl', 'extwin', true);
    // initialize html editor
    if (this.env.html_editor_init && window.rcmail_editor_init) {
      rcmail_editor_init(this.env.html_editor_init);
    }
    switch (this.task) {
      case 'mail':
@@ -593,6 +598,7 @@
      // remove copy from local storage if compose screen is left intentionally
      this.remove_compose_data(this.env.compose_id);
      this.compose_skip_unsavedcheck = true;
    }
    // process external commands
@@ -652,6 +658,7 @@
          if (win) {
            this.save_compose_form_local();
            this.compose_skip_unsavedcheck = true;
            $("input[name='_action']", form).val('compose');
            form.action = this.url('mail/compose', { _id: this.env.compose_id, _extwin: 1 });
            form.target = win.name;
@@ -978,7 +985,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;
@@ -1006,8 +1013,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;
@@ -1325,7 +1336,7 @@
    var url = this.get_task_url(task);
    if (task == 'mail')
      url += '&_mbox=INBOX';
    else if (task == 'logout')
    else if (task == 'logout' && !this.env.server_error)
      this.clear_compose_data();
    this.redirect(url);
@@ -2285,7 +2296,7 @@
  // expand all threads with unread children
  this.expand_unread = function()
  {
    var r, tbody = this.gui_objects.messagelist.tBodies[0],
    var r, tbody = this.message_list.tbody,
      new_row = tbody.firstChild;
    while (new_row) {
@@ -3160,62 +3171,7 @@
    }
    // check for locally stored compose data
    if (window.localStorage) {
      var index = this.local_storage_get_item('compose.index', []);
      for (var key, i = 0; i < index.length; i++) {
        key = index[i], formdata = this.local_storage_get_item('compose.' + key, null, true);
        if (!formdata) {
          continue;
        }
        // restore saved copy of current compose_id
        if (formdata.changed && key == this.env.compose_id) {
          this.restore_compose_form(key, html_mode);
          break;
        }
        // skip records from 'other' drafts
        if (this.env.draft_id && formdata.draft_id && formdata.draft_id != this.env.draft_id) {
          continue;
        }
        // skip records on reply
        if (this.env.reply_msgid && formdata.reply_msgid != this.env.reply_msgid) {
          continue;
        }
        // show dialog asking to restore the message
        if (formdata.changed && formdata.session != this.env.session_id) {
          this.show_popup_dialog(
            this.get_label('restoresavedcomposedata')
              .replace('$date', new Date(formdata.changed).toLocaleString())
              .replace('$subject', formdata._subject)
              .replace(/\n/g, '<br/>'),
            this.get_label('restoremessage'),
            [{
              text: this.get_label('restore'),
              click: function(){
                ref.restore_compose_form(key, html_mode);
                ref.remove_compose_data(key);  // remove old copy
                ref.save_compose_form_local();  // save under current compose_id
                $(this).dialog('close');
              }
            },
            {
              text: this.get_label('delete'),
              click: function(){
                ref.remove_compose_data(key);
                $(this).dialog('close');
              }
            },
            {
              text: this.get_label('ignore'),
              click: function(){
                $(this).dialog('close');
              }
            }]
          );
          break;
        }
      }
    }
    this.compose_restore_dialog(0, html_mode)
    if (input_to.val() == '')
      input_to.focus();
@@ -3232,6 +3188,72 @@
    // start the auto-save timer
    this.auto_save_start();
  };
  this.compose_restore_dialog = function(j, html_mode)
  {
    var i, key, formdata, index = this.local_storage_get_item('compose.index', []);
    var show_next = function(i) {
      if (++i < index.length)
        ref.compose_restore_dialog(i, html_mode)
    }
    for (i = j || 0; i < index.length; i++) {
      key = index[i];
      formdata = this.local_storage_get_item('compose.' + key, null, true);
      if (!formdata) {
        continue;
      }
      // restore saved copy of current compose_id
      if (formdata.changed && key == this.env.compose_id) {
        this.restore_compose_form(key, html_mode);
        break;
      }
      // skip records from 'other' drafts
      if (this.env.draft_id && formdata.draft_id && formdata.draft_id != this.env.draft_id) {
        continue;
      }
      // skip records on reply
      if (this.env.reply_msgid && formdata.reply_msgid != this.env.reply_msgid) {
        continue;
      }
      // show dialog asking to restore the message
      if (formdata.changed && formdata.session != this.env.session_id) {
        this.show_popup_dialog(
          this.get_label('restoresavedcomposedata')
            .replace('$date', new Date(formdata.changed).toLocaleString())
            .replace('$subject', formdata._subject)
            .replace(/\n/g, '<br/>'),
          this.get_label('restoremessage'),
          [{
            text: this.get_label('restore'),
            click: function(){
              ref.restore_compose_form(key, html_mode);
              ref.remove_compose_data(key);  // remove old copy
              ref.save_compose_form_local();  // save under current compose_id
              $(this).dialog('close');
            }
          },
          {
            text: this.get_label('delete'),
            click: function(){
              ref.remove_compose_data(key);
              $(this).dialog('close');
              show_next(i);
            }
          },
          {
            text: this.get_label('ignore'),
            click: function(){
              $(this).dialog('close');
              show_next(i);
            }
          }]
        );
        break;
      }
    }
  }
  this.init_address_input_events = function(obj, props)
  {
@@ -3261,6 +3283,7 @@
    form._draft.value = draft ? '1' : '';
    form.action = this.add_url(form.action, '_unlock', msgid);
    form.action = this.add_url(form.action, '_lang', lang);
    form.action = this.add_url(form.action, '_framed', 1);
    // register timer to notify about connection timeout
    this.submit_timer = setTimeout(function(){
@@ -3655,6 +3678,7 @@
    // always remove local copy upon saving as draft
    this.remove_compose_data(this.env.compose_id);
    this.compose_skip_unsavedcheck = false;
  };
  this.auto_save_start = function()
@@ -3679,6 +3703,21 @@
          ref.compose_type_activity_last = ref.compose_type_activity;
        }
      }, 5000);
      $(window).unload(function() {
        // remove copy from local storage if compose screen is left after warning
        if (!ref.env.server_error)
          ref.remove_compose_data(ref.env.compose_id);
      });
    }
    // check for unsaved changes before leaving the compose page
    if (!window.onbeforeunload) {
      window.onbeforeunload = function() {
        if (!ref.compose_skip_unsavedcheck && ref.cmp_hash != ref.compose_field_hash()) {
          return ref.get_label('notsentwarning');
        }
      };
    }
    // Unlock interface now that saving is complete
@@ -3750,15 +3789,16 @@
      }
    });
    if (window.localStorage && !empty) {
    if (!empty) {
      var index = this.local_storage_get_item('compose.index', []),
        key = this.env.compose_id;
        if ($.inArray(key, index) < 0) {
          index.push(key);
        }
        this.local_storage_set_item('compose.' + key, formdata, true);
        this.local_storage_set_item('compose.index', index);
      if ($.inArray(key, index) < 0) {
        index.push(key);
      }
      this.local_storage_set_item('compose.' + key, formdata, true);
      this.local_storage_set_item('compose.index', index);
    }
  };
@@ -3797,28 +3837,25 @@
  // remove stored compose data from localStorage
  this.remove_compose_data = function(key)
  {
    if (window.localStorage) {
      var index = this.local_storage_get_item('compose.index', []);
    var index = this.local_storage_get_item('compose.index', []);
      if ($.inArray(key, index) >= 0) {
        this.local_storage_remove_item('compose.' + key);
        this.local_storage_set_item('compose.index', $.grep(index, function(val,i) { return val != key; }));
      }
    if ($.inArray(key, index) >= 0) {
      this.local_storage_remove_item('compose.' + key);
      this.local_storage_set_item('compose.index', $.grep(index, function(val,i) { return val != key; }));
    }
  };
  // clear all stored compose data of this user
  this.clear_compose_data = function()
  {
    if (window.localStorage) {
      var index = this.local_storage_get_item('compose.index', []);
    var i, index = this.local_storage_get_item('compose.index', []);
      for (var i=0; i < index.length; i++) {
        this.local_storage_remove_item('compose.' + index[i]);
      }
      this.local_storage_remove_item('compose.index');
    for (i=0; i < index.length; i++) {
      this.local_storage_remove_item('compose.' + index[i]);
    }
  }
    this.local_storage_remove_item('compose.index');
  };
  this.change_identity = function(obj, show_sig)
@@ -3829,6 +3866,16 @@
    if (!show_sig)
      show_sig = this.env.show_sig;
    var id = obj.options[obj.selectedIndex].value;
    // enable manual signature insert
    if (this.env.signatures && this.env.signatures[id]) {
      this.enable_command('insert-sig', true);
      this.env.compose_commands.push('insert-sig');
    }
    else
      this.enable_command('insert-sig', false);
    // first function execution
    if (!this.env.identities_initialized) {
      this.env.identities_initialized = true;
@@ -3838,21 +3885,19 @@
        return;
    }
    var i, rx, cursor_pos, p = -1,
      id = obj.options[obj.selectedIndex].value,
    var cursor_pos, p = -1,
      input_message = $("[name='_message']"),
      message = input_message.val(),
      is_html = ($("input[name='_is_html']").val() == '1'),
      sig = this.env.identity,
      delim = this.env.recipients_separator,
      rx_delim = RegExp.escape(delim),
      headers = ['replyto', 'bcc'];
      rx_delim = RegExp.escape(delim);
    // update reply-to/bcc fields with addresses defined in identities
    for (i in headers) {
      var key = headers[i],
        old_val = sig && this.env.identities[sig] ? this.env.identities[sig][key] : '',
        new_val = id && this.env.identities[id] ? this.env.identities[id][key] : '',
    $.each(['replyto', 'bcc'], function() {
      var rx, key = this,
        old_val = sig && ref.env.identities[sig] ? ref.env.identities[sig][key] : '',
        new_val = id && ref.env.identities[id] ? ref.env.identities[id][key] : '',
        input = $('[name="_'+key+'"]'), input_val = input.val();
      // remove old address(es)
@@ -3879,15 +3924,7 @@
      if (old_val || new_val)
        input.val(input_val).change();
    }
    // enable manual signature insert
    if (this.env.signatures && this.env.signatures[id]) {
      this.enable_command('insert-sig', true);
      this.env.compose_commands.push('insert-sig');
    }
    else
      this.enable_command('insert-sig', false);
    });
    if (!is_html) {
      // remove the 'old' signature
@@ -4216,6 +4253,7 @@
  this.sent_successfully = function(type, msg, folders)
  {
    this.display_message(msg, type);
    this.compose_skip_unsavedcheck = true;
    if (this.env.extwin) {
      this.lock_form(this.gui_objects.messageform);
@@ -4656,6 +4694,7 @@
  this.list_contacts = function(src, group, page)
  {
    var win, folder, url = {},
      refresh = src === undefined && group === undefined && page === undefined,
      target = window;
    if (!src)
@@ -4668,7 +4707,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)
@@ -4804,6 +4843,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;
@@ -7131,6 +7173,7 @@
    // save message in local storage and do not redirect
    if (this.env.action == 'compose') {
      this.save_compose_form_local();
      this.compose_skip_unsavedcheck = true;
    }
    else if (redirect_url) {
      window.setTimeout(function(){ ref.redirect(redirect_url, true); }, 2000);
@@ -7684,23 +7727,43 @@
  // wrapper for localStorage.getItem(key)
  this.local_storage_get_item = function(key, deflt, encrypted)
  {
    var item;
    // TODO: add encryption
    var item = localStorage.getItem(this.get_local_storage_prefix() + key);
    try {
      item = localStorage.getItem(this.get_local_storage_prefix() + key);
    }
    catch (e) { }
    return item !== null ? JSON.parse(item) : (deflt || null);
  };
  // wrapper for localStorage.setItem(key, data)
  this.local_storage_set_item = function(key, data, encrypted)
  {
    // TODO: add encryption
    return localStorage.setItem(this.get_local_storage_prefix() + key, JSON.stringify(data));
    // try/catch to handle no localStorage support, but also error
    // in Safari-in-private-browsing-mode where localStorage exists
    // but can't be used (#1489996)
    try {
      // TODO: add encryption
      localStorage.setItem(this.get_local_storage_prefix() + key, JSON.stringify(data));
      return true;
    }
    catch (e) {
      return false;
    }
  };
  // wrapper for localStorage.removeItem(key)
  this.local_storage_remove_item = function(key)
  {
    return localStorage.removeItem(this.get_local_storage_prefix() + key);
    try {
      localStorage.removeItem(this.get_local_storage_prefix() + key);
      return true;
    }
    catch (e) {
      return false;
    }
  };
}  // end object rcube_webmail