function stripHTML(html) {
  return html.replace(/<\/?([a-z][a-z0-9]*)\b[^>]*>?/gi, '');
}

var emptyEmail = {
  header: {},
  body: ''
};

function MainViewModel() {
  self = this;

  self.domains = ko.observableArray([]);
  self.users = ko.observableArray([]);
  self.emails = ko.observableArray([]);

  self.domain = ko.observable();
  self.user = ko.observable();
  self.email = ko.observable(emptyEmail);

  self.emailFilter = ko.observable('');

  setInterval(function() {
    self.fetchUsers();
    self.fetchEmails({prepend: true});
  }, 2000);

  self.fetchEmails = function(options) {
    if (self.user()) {
      var existingEmails = self.emails();
      var params = {
        recipient__email: self.user(),
      };
      if (options.prepend && existingEmails[0]) {
        params.after = existingEmails[0].date;
      }
      $.get('/api/email', params , function(data) {
        var newEmails = _.map(data.results, function(email) {
          email.header = $.parseJSON(email.header);
          email.fuzzyDate = moment.utc(email.date).local().fromNow();
          email.formatedDate = moment.utc(email.date).local().format('YYYY-MM-DD\THH:mm:ss');
          email.preview = stripHTML(email.body);
          email.textAsHtml = '<p>' + email.body.replace(/\n{1,2}/, '</p><p>') + '</p>';
          return email;
        });
        if (newEmails.length) {
          if (options.prepend) {
            newEmails = newEmails.concat(existingEmails);
          }
          self.emails(newEmails);
        }
      });
    } else {
      self.emails([]);
    }
  };

  self.fetchDomains = function() {
    $.get('/api/domain/', self.domains);
  };
  self.fetchDomains();
  self.domain.subscribe(function() {
    self.fetchUsers();
    self.user(null);
    self.emails([]);
    self.email(emptyEmail);
  });

  self.fetchUsers = function() {
    $.get('/api/user/?domain__name=' + self.domain(), self.users);
  };
  self.activateUser = function(user) {
    self.email(emptyEmail);
    self.user(user.email);
  };
  self.user.subscribe(self.fetchEmails);

  self.filteredEmails = ko.computed(function() {
    var filter = self.emailFilter().toLowerCase();
    return ko.utils.arrayFilter(this.emails(), function(email) {
      if (!filter) {
        return true;
      }
      return _.some(['body', 'subject', 'sender'], function(key) {
        return email[key].toLowerCase().indexOf(filter) >= 0;
      });
    });
  }, self);

  self.raw = ko.computed(function() {
    var email = self.email();
    if (email.header) {
      return _.reduce(email.header, function(result, value, key) {
        return result + key + ': ' + value + '\n';
      }, '') + '\n' + email.body;
    }
  });
}
ko.applyBindings(new MainViewModel());

function email_display_format() {
  $('.display_type_change').on('click', function(){
    $('.mail-format').hide();
    $($(this).find('input').data('target')).fadeIn();
  });
}

$(function() {
  $('#reload-domains').tooltip({'placement': 'bottom'});
  email_display_format();
});

@@ -1,16 +1,59 @@
+//util function to strip HTML form strings%0A
 function stripHT
@@ -128,16 +128,58 @@
 '');%0A%7D%0A%0A
+//placeholder mail if no mail is selected%0A
 var empt
@@ -218,16 +218,85 @@
  ''%0A%7D;%0A%0A
+//main view model%0A//TODO split to seperate view models for user/mail%0A
 function
@@ -595,24 +595,40 @@
 vable('');%0A%0A
+  //update poll%0A
   setInterva
@@ -713,24 +713,153 @@
  %7D, 2000);%0A%0A
+  //fetches mails of currently seleced user%0A  //if options.prepend is set, only the mails prior the last mail where%0A  //fetched.%0A
   self.fetch
@@ -1866,16 +1866,40 @@
 %7D%0A  %7D;%0A%0A
+  //fetches all domains%0A
   self.f
@@ -2127,24 +2127,46 @@
 il);%0A  %7D);%0A%0A
+  //fetches all users%0A
   self.fetch
@@ -2395,24 +2395,72 @@
 chEmails);%0A%0A
+  //property to filter the mails by input value%0A
   self.filte
@@ -2818,24 +2818,89 @@
  %7D, self);%0A%0A
+  //helper function to get raw version of currently seleced mail%0A
   self.raw =

Add some docs