nasawillia
New Member
During past few days, I focused on creating notifications system, similar to Facebook one (you know what I mean, popup list, icon with badge and so on). I had two jobs to do - first: to set up long running ajax to gather data to display from database,- second: estabilish communication protocol between browser cards, to make sure that actions in one card will propagate to other cards (for example: stop icon blinking, mark as read etc.).This is not a question, I thought that it will be nice to share my code with you. I can't share the first part (what doesn't matter, because it's quite easy to do), but here's second part.Main goals are:- communicate between cards without usage of web server- use cookies to communicate- maintain real time (max 1 sec.) event propagation- because of cookie limitations (4kb max), take care of handled requests and purge cookie parts that aren't needed anymoreAfter loading a page, each card gets unique id. It looks something like this: \[code\]f2165a06-41d5-caf7-4c7b-76c5142d81b0\[/code\]. Next, script checks if this id is in cookie and if cookie even exists. If something is false, it fixes it.User starts to use the page. If sending data to other cards is required, script creates new entry in cookie, with unique entryId, to make sure that there will be no actions executed multiple times or executed by cards that they are'nt belong to.After opening page on few cards and playing with them, cookie structure looks similar to this:\[code\]cookie{ [card1hash]: commands{ [command1hash]: { command: 'stopBlinking', sender: '(sendingCardHash)', date: '(miliseconds)' }, [command2hash]: { command: 'closePopup', sender: '(sendingCardHash)', date: '(miliseconds)' }, } [card2hash]: commands{ [command1hash]: { command: 'stopBlinking', sender: '(sendingCardHash)', date: '(miliseconds)' }, [command2hash]: { command: 'closePopup', sender: '(sendingCardHash)', date: '(miliseconds)' }, } }\[/code\]and so on. As you can see, it's my poorly representation of \[code\]JSON\[/code\] structure. In fact cookie is set of objects, not string. When it comes to write cookie, object is encoded to \[code\]JSON\[/code\] and saved. On read, script uses \[code\]$.parseJSON\[/code\] and \[code\]eval()\[/code\] to rebulid object from string.After setup, script goes into infilite loop, with 1s interval, and checks cookie for new commands. If there are commands for card that received cookie, they're handled and deleted from cookie.Everything is packed in 'class', so init is simple and you can extend that class easily - add your own properties, methods and so on. You can also access methods from outside of class (as presented at the bottom of that post).Class name comes from reason that it was programmed, but feel free to change it, as long as you don't delete my name from comments.DISCLAIMER: That code is tested on Firefox only. I used jQuery 1.7.8 to write it, but it should work with more recent versions, as well as other browsers, but I can't guarantee you that. Even if it doesn't work, I hope it will help someone to find solution to this problem.\[code\]//author: Maciej Szkamruk//version: first function notificationsObject(){ var nl = new Object(); //attributes nl.uuid = null; //unique card id nl.cookie = null; // cookie holder nl.cookieName = "notificationsCommands"; //cookie name /////////////// // user methods /////////////// nl.doSomething = function(sendCommand){ //do something. //function called without parameters will send command to other cards. //Calling function with 'false' argument will prevent that. //it's required to prevent endless loop while trying to execute received command. if(sendCommand != false){ nl.sendCommand('doSomething'); } } ////////////////////////////////////////////// // internal class methods, required to setup ///////////////////////////////////////////// nl.getMiliseconds = function(){ var now = new Date().getTime() / 1000; var s = parseInt(now, 10); } nl.s4 = function() { return Math.floor((1 + Math.random()) * 0x10000) .toString(16) .substring(1); }; nl.setCookie = function (value, expire){ value = http://stackoverflow.com/questions/15701438/JSON.stringify(value); document.cookie = nl.cookieName +"=" + escape(value) + ((expire==null)?"" : ("; expires=" + expire.toGMTString())) } nl.countCommands = function(obj){ var count = 0; for(i in obj){ if(obj.hasOwnProperty(i)){ count++; } } return count; } nl.getCookie = function(){ if (document.cookie!="") { var toCookie=document.cookie.split("; "); for (i=0; i<toCookie.length; i++) { var nazwaCookie=toCookie.split("=")[0]; var wartoscCookie=toCookie.split("=")[1]; if (nazwaCookie==nl.cookieName) { var cookieVal = unescape(wartoscCookie); return eval(jQuery.parseJSON(cookieVal)); } } } return null; } nl.loop = function(){ nl.cookie = nl.getCookie(); if(nl.cookie.hasOwnProperty(nl.uuid)){ var commands = nl.cookie[nl.uuid].commands; if(commands != null && nl.countCommands(commands) > 0){ var commandsToDelete = []; $.each(commands, function(commandId, command){ if(nl.executeCommand(command)){ commandsToDelete.push(commandId); } }); if(commandsToDelete.length > 0){ nl.cookie = nl.getCookie(); $.each(commandsToDelete, function(key, commandId){ delete nl.cookie[nl.uuid].commands[commandId]; }); nl.setCookie(nl.cookie); } } } setTimeout(function(){nl.loop()}, 1000); } nl.deleteCookiePart = function(){ nl.cookie = nl.getCookie(); delete nl.cookie[nl.uuid]; nl.setCookie(nl.cookie); } nl.sendCommand = function(command){ nl.cookie = nl.getCookie(); $.each(nl.cookie, function(uuid, commandsList){ if(uuid != nl.uuid){ var commandObject = new Object(); commandObject.command = command; commandObject.sender = nl.uuid; commandObject.date = nl.getMiliseconds(); nl.cookie[uuid].commands[nl.s4() + '-' + nl.s4()] = commandObject; } }); nl.setCookie(nl.cookie); } nl.executeCommand = function(command){ switch(command.command){ case "doSomething": nl.doSomething(false); //passing false to break; } return true; } ////////////////////////////////////////////////////////////////////////////////////////////////// // class startup - generate uuid, set cookie, add listeners to the code and methods that you like ////////////////////////////////////////////////////////////////////////////////////////////////// //generate uuid nl.uuid = nl.s4() + nl.s4() + '-' + nl.s4() + '-' + nl.s4() + '-' + nl.s4() + '-' + nl.s4() + nl.s4() + nl.s4(); //cookie //if something went wrong during development and you ended up with broken cookie, //uncomment below line to delete it and start fresh // nl.setCookie(null); //setup or update cookie - register new card in it nl.cookie=nl.getCookie(nl.cookieName); if (nl.cookie!=null) { var cookie = nl.cookie; if(cookie == null) cookie = new Object(); if(!cookie.hasOwnProperty(nl.uuid)){ cookie[nl.uuid] = {'commands': {}}; nl.setCookie(cookie); } } else{ cookie = Object(); cookie[nl.uuid] = {'commands': {}}; nl.setCookie(cookie); } //when user leaves the page, remove card from cookie. //Timeout is set, because code tended to fire on page load sometimes without it. setTimeout(function(){window.onbeforeunload = function(){notifications.deleteCookiePart()};}, 1000); /////////////////////////////// //add your custom methods here! //for example: /////////////////////////////// $('.notificationBanner').click(function(){ nl.doSomething(); //calling this without 'false' argument will execute method, as well as send it to other cards. }); return nl;}\[/code\]Just pack it to .js file and include in your html. To start cookie loop, you can call \[code\]nl.loop()\[/code\] in startup section, or do it after initialization manually, just when you want it:\[code\]$(document).ready(function(){ var notifications = notificationsObject(); notifications.loop();});\[/code\]Have fun!