Tutorial: Creating a chat with Hydna and jQuery, part one

This tutorial will go through the basic steps required to create a simple, HTML-based chat application using Hydna and jQuery.

Note that the chat application is very basic. Improvements are made in parts two and three.

If you get stuck, please don't hesitate to contact support@hydna.com.

Prerequisites

  • Basic knowledge of JavaScript, HTML, and CSS.
  • Very basic knowledge of jQuery (understanding what it means to wait for the DOM to be "ready", selecting elements, and making basic manipulations)
  • Some familiarity with Hydna. You should've at-least glanced through the documentation

Getting started

This step is optional if you already have a domain.

Before we get our hands dirty you should:

We've used our domain, tutorials.hydna.net, in the code below. That won't work for you. Make sure to replace that with the name of the domain you create.

Your domain should not have any behaviors attached to the channel /chat (if you don't know what this means, we're probably good).

Initial setup

Create an empty directory somewhere on your local computer. You could name it chat-tutorial-part-one for sake of clarity.

Inside the directory chat-tutorial-part-one create two directories: script and style. Also create an empty file named index.html.

Create an empty file named app.css in style, and an empty file named app.js in script.

The layout should look like this when you're done:

chat-tutorial-part-one/
    index.html
    script/
        app.js
    style/
        app.css

The HTML

We'll start off with a basic HTML document that sources a few scripts we need, links to the stylesheet, and creates a couple of elements we'll use in app.js.

Put the following code in index.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Chat</title>

    <!-- jQuery -->
    <script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>

    <!-- Hydna -->
    <script src="http://cdn.hydna.com/1/hydna.js"></script>

    <!-- The chat application -->
    <script src="./script/app.js"></script>

    <!-- Main stylesheet -->
    <link rel="stylesheet" href="./style/app.css" type="text/css" media="screen"/>
</head>
<body>
    <!-- Where our messages will be displayed -->
    <div id="output"></div>

    <!-- Form used to send chat messages -->
    <form id="input">
        <input type="text" name="chat-input"/>
    </form>
</body>

The scripts sourced are:

  • jquery.js (from CDN) for cross-browser compatibility when we create elements and attach event listeners.
  • hydna.js (from CDN) contains the client library required to use Hynda.
  • app.js contains the code of the actual chat application (we'll go over this file in detail later in the tutorial).

A single stylesheet, app.css, is sourced. It contains a few basic styles required to make this application resemble a typical chat.

We've created an empty div with the id output. This is were our chat messages will be placed (let's call it the chat box). The form with the id input will be used to send chat messages.

The CSS

Put the following code in the file style/app.css:

* {
    margin: 0;
    padding: 0;
    line-height: normal;
}

html,
body {
    height: 100%;
}

body {
    font-family: sans-serif;
    font-size: 14px;
}

/* Chat */

#output {
    position: absolute;
    top: 0;
    bottom: 40px;
    left: 0;
    right: 0;
    padding: 10px;
    overflow: auto;
}

#output div {
    line-height: 150%;
    margin-bottom: 5px;
}

/* Input */

#input {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 40px;
    border-top: 1px solid #999;
    padding: 0 10px;
    background: #FFF;
    box-shadow: inset 0 3px 0 #EEE;
}

#input input {
    display: block;
    width: 100%;
    height: 20px;
    line-height: 20px;
    border: none;
    padding: 10px 0;
    background: transparent;
    font-size: 16px;
    margin: 0;
}

#input input:focus {
    outline: 0;
}

We won't go into details here, but we're basically resetting margin, padding, and line-height of all elements and laying out the input- and output elements.

The Application

We're finally ready to start digging in! app.js is the core of the application and contains all of the more interesting bits.

What we'll do is wait until the DOM is ready, open a channel on Hydna, attach event listeners to the Hydna-channel to display incoming chat messages, and hook into a form to send data to other participants of the chat connected to the same channel (i.e. have also opened the chat application).

Put the following code in script/app.js:

$(document).ready(function() {
    var output = $('#output');

    output.append($('<div/>', { text: 'Connecting ...' }));

    // NOTE: You should replace 'tutorials.hydna.net' with your own domain.
    var channel = new HydnaChannel('tutorials.hydna.net/chat', 'rw');

    channel.onopen = function(event) {
        output.append($('<div/>', { text: 'Connected!' }));
    };

    channel.onclose = function(event) {
        var text = "Channel closed: " + event.reason;
        output.append($('<div/>', { text: text }));
    };

    channel.onmessage = function(event) {
        var text = escapeHTML(event.data);
        output.append($('<div/>', { 'text': text }));

        // Scroll to bottom of output when new messages are appended.
        output.prop('scrollTop', output.prop('scrollHeight'));
    };

    $('#input input').focus();

    $('form').submit(function(event) {
        event.preventDefault();

        var input = $('input', this);
        if (input.val()) {
            try {
                channel.send(input.val());
                input.val('');
            } catch (e) {
                alert("Cannot send messages while disconnected.");
            }
        }
    });
});

// Escape input to prevent XSS attacks. Note that we're only escaping
// characters that are potentially dangerous for this specific tutorial.
function escapeHTML(value) {
    var entities = {
        "&": "&amp;",
        "<": "&lt;",
        ">": "&gt;",
        '"': "&quot;",
        "'": "&apos;"
    };

    function escapeCharacter(c) {
        return entities[c];
    }

    return String(value).replace(/[&<>]/g, escapeCharacter);
}

Let's go over a few important pieces of code in detail.

The first interesting line is when we open a channel on Hydna:

var channel = new HydnaChannel('tutorials.hydna.net/chat', 'rw');

We're telling Hydna that we want to open the channel /chat on the domain tutorials.hydna.net in rw (read and write) mode.

Replace tutorials.hydna.net with the name of the domain you created before starting this tutorial. The line should read like below if you created the domain my-fantastic-domain.hydna.net:

var channel = new HydnaChannel('my-fantastic-domain.hydna.net/chat', 'rw');

Note that you'll have to open the channel in both read and write mode (rw) as you'll be reading (receiving chat messages) and writing (sending chat messages).

After creating an instance of HydnaChannel we attached three event handlers to be able to define what to do when certain events are triggered by Hydna.

First we attached a handler to the onopen event. This handler is triggered when the channel is actually opened. We create a <div> element with the text 'Connected!' and append it to the output element.

channel.onopen = function(event) {
    output.append($('<div/>', { text: 'Connected!' }));
};

Then we attached a handler to onclose. This handler is triggered when the channel has been closed, like if your connection Hydna has been servered due to a rabid dog chewing through your network cable. event.reason contains the (optional) reason for the error.

channel.onclose = function(event) {
    var text = "Channel closed: " + event.reason;
    output.append($('<div/>', { text: text }));
};

Finally we attached a handler to onmessage. This handler is triggered every time data is sent to the channel. In our case that would be when users send chat messages. event.data contains the message sent. We escape the message, create a div, and append it to the chat box. The last bit scrolls the chat box so that we can see the last appended div if there are a lot of chat messages in the chat box. The function escapeHTML (defined later in the app.js) is used to escape all messages coming in from Hydna. It's important to always escape data received from "untrusted" sources (user input, in this case).

channel.onmessage = function(event) {
    var text = escapeHTML(event.data);
    output.append($('<div/>', { 'text': text }));

    // Scroll to bottom of output when new messages are appended.
    output.prop('scrollTop', output.prop('scrollHeight'));
};

And now for the final piece of the application: sending chat messages. In the code below we hook into the form's submit event, and, if the input element contains text, try to send it's contents to the channel. An exception may be thrown if we try to send a message before the channel has been properly opened (before onopen has been called). We catch the exception and display a message to the user.

$('form').submit(function(event) {
    event.preventDefault();

    var input = $('input', this);
    if (input.val()) {
        try {
            channel.send(input.val());
            input.val('');
        } catch (e) {
            alert("Cannot send messages while disconnected.");
        }
    }
});

Try it out

Open index.html in your preferred browser. You should see a white page with an input field at the bottom. The chat box should contain two lines:

Connecting ...
Connected!

So far, so good!

You can now enter text into the input element and press enter to send your first chat message. If you type "Hello" and press Enter you should see:

Connecting ...
Connected!
Hello

Without closing your browser window, open the file (index.html) in another browser window. Everything you type in the newly opened window should instantly appear in the chat box of the first window you opened.

It's simple, but it's a chat!

And that's it for the first part of this tutorial! We hope you've enjoyed it. Please send an email to support@hydna.com if you've discovered any errors, found a section particularly unclear, or if something went wrong.

Next step

A pretty glaring limitation of the chat is that you cannot easily discern who wrote what. In part two we assign nicknames to the participants and show messages when they join/leave the chat.