view media/js/openwebchat.js @ 77:1c99c08d2a54

Sort of simplified message display a bit
author Atul Varma <varmaa@toolness.com>
date Thu, 30 Apr 2009 17:47:32 -0700
parents 16a18e3a1098
children 0effc4481d18
line wrap: on
line source

var OpenWebStorage = {
  UnsupportedError: function UnsupportedError() {},

  FakeStorage: function FakeStorage() {
    var contents = {};

    function deepCopy(obj) {
      return JSON.parse(JSON.stringify(obj));
    }

    this.set = function set(key, value) {
      contents[key] = deepCopy(value);
    };

    this.get = function get(key, defaultValue) {
      if (key in contents)
        return deepCopy(contents[key]);
      return defaultValue;
    };
  },

  DOMLocalStorage: function DOMLocalStorage() {
    var self = this;
    var localStorage = window.localStorage;

    if (window.globalStorage)
      localStorage = window.globalStorage[document.location.hostname];

    if (!localStorage)
      throw new OpenWebStorage.UnsupportedError('no local DOM storage');

    self.set = function set(key, value) {
      localStorage[key] = JSON.stringify(value);
    };

    self.get = function get(key, defaultValue) {
      var value = defaultValue;

      if (localStorage[key])
        try {
          value = JSON.parse(localStorage[key].value);
        } catch (e) {}

      return value;
    };
  }
};

var OpenWebChat = {
  ClientStorage: function ClientStorage(owStorage, prefix) {
    var self = this;
    self.length = owStorage.get(prefix + 'length', 0);

    self.get = function get(id) {
      return owStorage.get(prefix + id);
    };

    self.append = function append(msg) {
      owStorage.set(prefix + self.length, msg);
      self.length += 1;
      owStorage.set(prefix + 'length', self.length);
    };
  },

  SEND_TIMEOUT: 10000,

  LISTEN_TIMEOUT: 60000,

  listenForMessages: function listenForMessages(options) {
    var self = this;

    function processMessage(msg) {
      options.storage.append(msg);
      options.onMessage(msg);
    }

    jQuery.ajax(
      {type: 'GET',
       url: 'listen',
       data: {start: options.storage.length},
       dataType: 'json',
       timeout: self.LISTEN_TIMEOUT,
       error: function(xhr, textStatus, errorThrown) {
         if (textStatus == "timeout")
           // Start another long poll.
           self.listenForMessages(options);
         else
           options.onError([textStatus, errorThrown]);
       },
       success: function(data, textStatus) {
         // TODO: Make sure data.messages is an array.
         for (var i = 0; i < data.messages.length; i++)
           processMessage(data.messages[i]);
         // Start another long poll.
         self.listenForMessages(options);
       }
      });
  },

  sendMessage: function sendMessage(options) {
    jQuery.ajax(
      {type: 'POST',
       url: 'send',
       contentType: 'application/json',
       data: JSON.stringify(options.message),
       processData: false,
       timeout: this.LISTEN_TIMEOUT,
       error: function(xhr, textStatus, errorThrown) {
         options.onError([textStatus, errorThrown]);
       }
      });
  }
};

$(window).ready(
  function() {
    var ENTER_KEYCODE = 13;
    var RETURN_KEYCODE = 10;

    var owStorage;

    try {
      owStorage = new OpenWebStorage.DOMLocalStorage();
    } catch (e) {
      if (e instanceof OpenWebStorage.UnsupportedError)
        owStorage = new OpenWebStorage.FakeStorage();
      else
        throw e;
    }

    var convStorage = new OpenWebChat.ClientStorage(
      owStorage,
      '/conv' + document.location.pathname
    );

    $('#name').val(owStorage.get('name', "A Mysterious Stranger"));
    $('#name').blur(
      function() {
        owStorage.set('name', $(this).val());
      });

    $('#outgoing-message').val(owStorage.get('lastMessage', ''));
    $('#outgoing-message').blur(
      function() {
        if ($(this).val())
          owStorage.set('lastMessage', $(this).val());
      });

    $('#outgoing-message').focus();

    function onKey(evt) {
      var self = this;
      var content = $(this).val();
      var author = $('#name').val();
      if (evt.keyCode == ENTER_KEYCODE ||
          evt.keyCode == RETURN_KEYCODE) {
        if (content) {
          owStorage.set('lastMessage', content);
          $(this).val('');
          var msg = {content: content,
                     time: new Date()};
          if (author)
            msg.author = author;
          OpenWebChat.sendMessage(
            {message: msg,
             onError: function(exception) {
               $(self).val(content);
             }
            });
        }
        evt.preventDefault();
      }
    }

    $('#outgoing-message').keydown(onKey);
    $('#outgoing-message').keyup(onKey);

    function scrollToBottom() {
      window.scrollTo(0, $('#bottom').position().top);
    }

    function onMessage(msg, doAnimation) {
      if (typeof(doAnimation) == "undefined")
        doAnimation = true;

      if (owStorage.get('lastMessage') == msg.content)
        owStorage.set('lastMessage', '');

      var block = $('#templates .message').clone();
      $('.content', block).html(msg.content);

      var author = msg.author ? msg.author : 'Anonymous';
      if (author != $('#content .author:last').text())
        $('.author', block).text(author);
      else
        $('.author', block).remove();

      $('.timestamp', block).text(msg.time);

      if (doAnimation)
        block.hide();

      $('#incoming-messages').append(block);

      if (doAnimation)
        block.slideDown(scrollToBottom);
    }

    $('#incoming-messages').hide();

    for (var i = 0; i < convStorage.length; i++)
      onMessage(convStorage.get(i), false);

    $('#incoming-messages').slideDown();

    OpenWebChat.listenForMessages(
      {storage: convStorage,
       onMessage: onMessage,
       onError: function onError(exception) {
         if (window.console)
           window.console.log('The error', exception, 'occurred.');
         var error = $('#templates .error').clone();
         error.hide();
         $('#incoming-messages').append(error);
         error.slideDown();
       }
      });
  });