Pub/Sub Javascript

Subscribe Once

by vtortola

HTML

<div id="container">
   <div id="all-messages"><h3>All messages</h3></div>
   <div id="blue-messages"></div>
   <div id="red-messages"></div>
   <div id="yellow-messages"></div>
</div>

CSS

#container > div{
    font-family:Tahoma;
    letter-spacing:1px;
    border:none;
    width:200px;
    height:200px;
    float:left;
    padding:5px;
    text-align:center;
    font-size:9px;
    margin:1px;
    background-color:black;
    color:white;
}
#red-messages{
    background-color:red !important;
}

#blue-messages{
    background-color:blue !important;
}

#yellow-messages{
    background-color:gold !important;
}

hr{
    clear:both;
    visibility:hidden;
}

JavaScript

var messageDispatcher = function(){
    var me ={};
    var _handlers = [];
    var _handlerIdCount = 0;    
    
    me.subscribe = function(predicate, handler){
        var id =_handlerIdCount++;
        _handlers.push({predicate:predicate, handle:handler, id:id});
        return id;
    };
    
    me.subscribeOnce = function(predicate, handler, timeout, timeoutMessage){
        var id =_handlerIdCount++;
        console.log('tom ' + timeoutMessage);
        var timer = setTimeout(function(){
            me.unsubscribe(id);
            if(timeoutMessage)
                handler(timeoutMessage);
        },timeout);
        
        _handlers.push({
                predicate:predicate, 
                handle:function(){
                    clearTimeout(timer);
                    me.unsubscribe(id);
                    handler.apply(me, arguments);
                }, 
                id:id
            });
        return id;
    };
    
    me.unsubscribe = function(subscriptionId){
        var items = _handlers.filter(function(h){ return h.id === subscriptionId});
        if(items && items.length){
            var index = _handlers.indexOf(items[0]);
            if (index > -1) {
                _handlers.splice(index, 1);
            }
        }
    };
    
    me.push = function(message){
        var handled = false;
        _handlers.forEach(function(h){
            if(h.predicate(message)){
                handled=true;
                h.handle(message);
            }
        }); 
        if(!handled){
            // todo: unhandled message
        }
    };
       
    return me;
};

var md = messageDispatcher();

// Subscribe and subscribe once
md.subscribe(function(msg){ return msg && msg.all;}, // predicate
             function(message){$('#all-messages').append('<div>'+JSON.stringify(message)+'</div>');});

md.subscribeOnce(function(msg){return msg && msg.all;},
                 function(message){...