view openwebchat.js @ 64:559c48a58254

Added the option to long poll instead of using mime multipart.
author Atul Varma <varmaa@toolness.com>
date Thu, 30 Apr 2009 06:42:13 -0700
parents b7b9932823e4
children 84bf6a3ac4ec
line wrap: on
line source

var OpenWebChat = {
  ClientStorage: function ClientStorage(localStorage, prefix) {
    var self = this;
    if (!localStorage[prefix + 'length'])
      localStorage[prefix + 'length'] = '0';

    self.length = Number(localStorage[prefix + 'length'].value);

    self.get = function get(id) {
      return JSON.parse(localStorage[prefix + id].value);
    };

    self.append = function append(msg) {
      localStorage[prefix + self.length] = JSON.stringify(msg);
      self.length += 1;
      localStorage[prefix + 'length'] = self.length.toString();
    };

    self.wipe = function wipe() {
      var names = [];
      for (name in localStorage)
        names.push(name);
      names.forEach(
        function(name) {
          if (name.indexOf(prefix) == 0)
            delete localStorage[name];
        });
    };
  },

  startMessageListener: function startMessageListener(options) {
    var self = this;
    var req = new XMLHttpRequest();
    var basePath = 'listen';
    if (options.useMultipart) {
      req.multipart = true;
      basePath += '/multipart';
    }
    req.open('GET',
             basePath + '?start=' + options.storage.length,
             true);
    req.overrideMimeType('application/json');
    req.addEventListener(
      "error",
      function() {
        options.onError(null);
      },
      false
    );
    req.addEventListener(
      "load",
      function onload(evt) {
        var data;
        var errorOccurred = false;
        try {
          data = JSON.parse(req.responseText);
        } catch (e) {
          options.onError(e);
          errorOccurred = true;
        }
        if (!errorOccurred) {
          function processMessage(msg) {
            options.storage.append(msg);
            options.onMessage(msg);
          }
          if (options.useMultipart)
            processMessage(data);
          else {
            // 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.startMessageListener(options);
          }
        }
      },
      false
    );
    req.send(null);
  },

  sendMessage: function sendMessage(options) {
    var req = new XMLHttpRequest();
    req.open('POST', 'send', true);
    req.overrideMimeType('application/json');
    req.addEventListener(
      "error",
      function() {
        options.onError(null);
      },
      false
    );
    req.send(JSON.stringify(options.message));
  }
};

$(window).ready(
  function() {
    var ENTER_KEYCODE = 13;
    var MAX_ANIMATING_MESSAGES = 3;

    var animatingMessages = 0;

    var localStorage = globalStorage[document.location.hostname];

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

    if (!localStorage.name)
      localStorage.name = "A Mysterious Stranger";

    if (!localStorage.lastMessage)
      localStorage.lastMessage = "";

    $('#name').val(localStorage.name.value);
    $('#name').blur(
      function() {
        localStorage.name = $(this).val();
      });

    $('#outgoing-message').val(localStorage.lastMessage.value);
    $('#outgoing-message').blur(
      function() {
        if ($(this).val())
          localStorage.lastMessage = $(this).val();
      });

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

    $('#outgoing-message').keydown(
      function(evt) {
        var self = this;
        var content = $(this).val();
        var author = $('#name').val();
        if (evt.keyCode == ENTER_KEYCODE) {
          if (content) {
            localStorage.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();
        }
      });

    function onMessage(msg) {
      var block = $('#templates .message').clone();

      if (localStorage.lastMessage.value == msg.content)
        localStorage.lastMessage = "";

      $('.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);

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

      if (animatingMessages < MAX_ANIMATING_MESSAGES) {
        animatingMessages += 1;

        block.slideDown(
          function() {
            animatingMessages -= 1;
            window.scrollTo(0, $('#bottom').position().top);
          });
      } else
        block.show();
    }

    var currStoredMessage = 0;
    var CHUNK_SIZE = 20;
    var UI_BREATHE_TIME = 10;

    function showStoredConversation() {
      if (currStoredMessage < convStorage.length) {
        var i = 0;
        while (i < CHUNK_SIZE && currStoredMessage < convStorage.length) {
          onMessage(convStorage.get(currStoredMessage));
          currStoredMessage += 1;
          i += 1;
        }
        window.setTimeout(showStoredConversation, UI_BREATHE_TIME);
      } else
        OpenWebChat.startMessageListener(
          {storage: convStorage,
           useMultipart: false,
           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();
           }
          });
    }

    showStoredConversation();
  });