Guests list

by alekskorovin

HTML

<link rel="stylesheet" href="https://cdn.jsdelivr.net/bootstrap/3.3.0/css/bootstrap.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/bootstrap/3.3.0/css/bootstrap-theme.min.css">
<script src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
<script src="https://cdn.jsdelivr.net/bootstrap/3.3.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/2.4.1/lodash.min.js"></script>
<div class="col-xs-12">
    <h1>Список гостей</h1>
</div>
<div class="col-xs-4 invited">
    <h2>Приглашены</h2>
    <div id="invited-box"></div>
</div>
<div class="col-xs-4 in-hall">
    <h2>В зале</h2>
    <div id="in-hall-box"></div>
</div>
<div class="col-xs-4">
    <h2>Новый гость</h2>

    <div class="item">
        <form role="form">
            <div class="form-group">
                <label for="name">Имя гостя</label>
                <input type="text" id="name" class="form-control" name="name" placeholder="Имя гостя"/>
            </div>
            <button type="submit" id="addGuest" class="btn btn-default">Добавить</button>
        </form>
    </div>
</div>

<script id="item-template-invite" type="text/x-handlebars-template">
    <div data-id="<%id%>" class="item">
        <div class="close"><a class="btn btn-danger" href="#" role="button"><span class="glyphicon glyphicon-remove"></span></a></div>
        <%name%>
    </div>
</script>
<script id="item-template-in-hall" type="text/x-handlebars-template">
    <div data-id="<%id%>" class="item"><%name%></div>
</script>

CSS

.item {
    background-color: #eee;
    border-radius: 5px;
    padding: 5px 20px 5px 20px;
    position: relative;
    margin-bottom: 5px;
    font-size: 24px;
}

.delete {
    position: absolute;
    right: 5px;
    top: 5px;
}

JavaScript

var guests,
    ws,
    config = {
        inviteBoxSelector: '#invited-box',
        inHallBoxSelector: '#in-hall-box',
        templateInvitedSelector: '#item-template-invite',
        templateInHallSelector: '#item-template-in-hall',
        webSocketURL: 'ws://f2.smartjs.academy/ws',
        webSocketListURL: '//f2.smartjs.academy/list'
    };

var Dispatcher = (function () {
    var instance;
    
    function init() {
        // Singleton
        this.eventSubscriptions = {};
        this.isFiring = false;
        
        function trigger(eventName, data, context) {
            // Retrieve a list of subscribers for the event being triggered
            var subscribers = eventSubscriptions[eventName];
            if (typeof subscribers === 'undefined') {
                // No list found for this event, return early to abort execution
                return;
            }
            // Ensure data is an array or is wrapped in an array,
            // for Function.prototype.apply use
            data = (data instanceof Array) ? data : [data];
            // Set a default value for `this` in the callback
            context = this;
            for (var i = 0, iMax = subscribers.length; i < iMax; i += 1) {
                setTimeout(subscribers[i].apply(context, data), 0);
            }
            this.isFiring = true;
        }
        function on(eventName, callback) {
            var subscribers = eventSubscriptions[eventName];
            
            if(typeof subscribers === 'undefined') {
                subscribers = eventSubscriptions[eventName] = [];
            }
            subscribers.push(callback);
        }
        function off(eventName, callback) {
            if(eventSubscriptions[eventName]){
                eventSubscriptions[eventName] = eventSubscriptions[eventName].filter(function (currentFunction) {
                    if(currentFunction != callback) {
                        return currentFunction;
                    }
             ...