Python Sample Chatserver

templates/profile.html

<!doctype html>
<html>
    <head></head>
    <!-- Colour palette: Deep blue #252839; Mid grey #677077; Light grey #b5b5b7; Orange #f2b632 -->
    <link rel="stylesheet" href="/static/styles.css" type="text/css">
    <body>
        <div class="login-grid">
            <div class="header"><span>Chat app demo</span></div>
            <div class="welcome inset"><span>Welcome to Chat app!</span></div>
            <div class="inset">What display name do you want on this chat service?</div>
            <div class="inset">
                <form action="/login" method="post">
                    <input id="input-name" name="displayName" type="text" placeholder="Type your name here...">
                    <input id="input-submit" type="submit" value="Login">
                </form>
            </div>
        </div>
    </body>
</html>

templates/main.html

<!doctype html>
<html>
    <head></head>
    <link rel="stylesheet" href="/static/styles.css" type="text/css">
    <body>
        <div class="main-grid">
            <div class="header"><span>Chat app demo</span></div>
            <div class="msg-grid inset">
                <div class="cell-name"><span id="user-display-name">Paul Baumgarten</span> says</div>
                <div class="cell-msg">
                    <input id="input-message" name="msg" type="text" placeholder="Type your message here...">
                    <input id="input-submit" type="button" value="Send">
                </div>
            </div>
            <div id="messages-grid" class="inset">
                <!-- start of messages -->
                <div class="msg-grid">
                    <div class="cell-name author-and-datetime">
                        <span class="author"></span> @ <span class="datetime"></span>
                    </div>
                    <div class="cell-msg msg-text"></div>
                </div>
                <!-- end of messages -->
            </div>
        </div>
    </body>
    <script id="msg-template" type="text/x-handlebars-template">
        {{#each this}}
        <div class="msg-grid">
            <div class="cell-name author-and-datetime">
                <span class="author">{{displayName}}</span> @ <span class="datetime">{{datetime}}</span>
            </div>
            <div class="cell-msg msg-text">{{content}}</div>
        </div>
        {{/each}}
    </script>
    <script language="JavaScript" src="/static/handlebars.js"></script>
    <script language="JavaScript" src="/static/main.js"></script>
</html>

static/main.js

"use strict";

var messages = [];

function app() {
    function ajax( url, formData, callback ) {
        var xhttp = new XMLHttpRequest(); xhttp.onreadystatechange = function() {
            if (xhttp.readyState === 4) {
                if (callback === null) {
                    console.log("[ajax] completed: ",xhttp.status,xhttp.responseText)
                } else {
                    callback( xhttp.status, xhttp.responseText );
                }
            }
        };
        xhttp.open("POST", url, true);
        if (formData !== null) {
            xhttp.send(formData);
        } else {
            xhttp.send();
        }
    }

    function sendNewMessage(e) {
        var message = document.querySelector("#input-message").value;
        document.querySelector("#input-message").value = "";
        console.log("Sending message: "+message);
        var form = new FormData();
        form.append('message', message);
        ajax( "/message", form, null );
    }

    function showMessages(status, received) {
        var updates = JSON.parse(received);
        messages = [];
        for (var i in updates) {
            var update = updates[i];
            var d = new Date(Number(update[0])*1000);
            var dateString = d.toLocaleString();
            messages.push({"timestamp": update[0], "displayName": update[1], "content": update[2], "datetime": dateString});
        }
        var handlebarsHTML = Handlebars.compile( document.getElementById("msg-template").innerHTML );
        var html = handlebarsHTML( messages );
        document.getElementById( "messages-grid" ).innerHTML = html;
    }

    function refreshMessages() {
        ajax("/messages", null, showMessages);
    }

    function setDisplayName(status, received) {
        document.querySelector("#user-display-name").innerHTML = received;
    }

    ajax("/getDisplayName", null, setDisplayName);
    ajax("/messages", null, showMessages);
    document.querySelector("#input-submit").onclick = sendNewMessage;
    setInterval(refreshMessages,5000);
}

window.onload=app;

static/styles.css

html,body { 
    margin: 0 0 0 0;
    padding: 0 0 0 0;
    font-family: sans-serif;
    font-weight: 100;
    background-color: #f0f0f0;
}
.login-grid {
    display: grid;
    grid-gap: 1em;
    grid-auto-rows: minmax(100px, auto);
    grid-template-rows: 1fr 2fr 1fr 10fr;
}
.header {
    font-size: 24pt;
    font-weight: 100;
    color: white;
    background-color: #252839;
    box-shadow: 5px 10px 18px #b5b5b7;
}
.header span {
    padding: 0 2vw 0 2vw; 
}
.inset {
    padding: 0 2vw 0 2vw; 
}
.cell-pic {
    grid-row:1/3;
    border: 1px solid #e0e0e0;
}
.cell-name {
    padding-top: 1em;
    color: #677077;
}
.cell-msg {
    vertical-align: top;
}
.welcome {
    font-size: 48pt;
    font-weight: 100;
}
#user-display-name {
    font-size: 20pt;
}
#input-name {
    font-size: 20pt;
    font-weight: 100;
    width: 85%;
}
#input-message {
    font-size: 20pt;
    font-weight: 100;
    width: 75%;
}
#input-submit {
    font-size: 20pt;
    font-weight: 100;
    width: 10%;
    background-color: #f2b632;
    color: #fff;
}
.author-and-datetime {
    font-size: 12pt;
    font-weight: 600;
}
.msg-text {
    font-size: 20pt;
    font-weight: 100;
}
/* This is necessary to hide the ugly button for the camera input */
#input-camera {
    width: 0.1px;
    height: 0.1px;
    opacity: 0;
    overflow: hidden;
    position: absolute;
    z-index: -1;
}

static/handlebars.js

  1. Download from here
  2. Rename the file to remove the version number - make it just plain ol' handlebars.js or the link in main.html above won't work.