Skip to content

Instantly share code, notes, and snippets.

@dopa
Last active August 29, 2015 14:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dopa/29e88b385545cb01ffdb to your computer and use it in GitHub Desktop.
Save dopa/29e88b385545cb01ffdb to your computer and use it in GitHub Desktop.
/*jshint forin:true, noarg:true, noempty:true, eqeqeq:true, bitwise:true, strict:true, undef:true, unused:true, curly:true, browser:true, devel:true, jquery:true, indent:4, maxerr:50, laxcomma:true, indent:false, unused: false */
/*global Pusher:false, Handlebars:false, Modernizr:false, store:false, performance:false */
;(function($, doc, win){
"use strict";
var $app, appEnvironment, realtime_templates = {};
var pusherIsConnected=false;
var $pings, pingInterval;
var meetingId, meetingChannelName, meetingChannel;
var sessionChannel, boundSessionChannelEventId=-1;
var $attendee, isSignedIn=false, attendeeId, attendeeChannelName, attendeeChannel;
function init() {
$app = $('#app');
$pings = $('#pings');
$app.data('pings',[]);
appEnvironment = $app.data('appenvironment');
meetingId = $app.data('meetingid');
meetingChannelName = 'meeting_'+meetingId;
$attendee = $('#attendee');
if( $attendee.length ) {
isSignedIn = true;
attendeeId = $attendee.data('attendeeid');
attendeeChannelName = meetingChannelName + '_attendee_' + attendeeId;
var teamId = $attendee.data('teamid');
if( typeof teamId !== 'undefined' && teamId.toString().length > 0 && parseInt(teamId,10) > 0 ) {
if ( Modernizr.localstorage ){
store.set('meeting_'+meetingId+'_teamId',teamId);
}
}
}
if( $('.initPush').length ) {
if ( !$app.length ) { return; }
var pusherKey = $app.data('pusherkey');
if( typeof pusherKey === 'undefined' || typeof Pusher === 'undefined' ) { return; }
win.pusher = new Pusher(pusherKey);
}
listen();
connect();
if ( window.performance ) { // disable ping feature if not supported on device
connect();
} else {
hidePingButton();
}
}
// TEMP ----> Pusher Debugging to Console
// if( $('#app').data('appenvironment') === "development" && typeof Pusher !== 'undefined' ) {
// Pusher.log = function(message) {
// if (window.console && window.console.log) window.console.log(message);
// };
// }
function printConnectingIn(ms) {
if( appEnvironment === "development" ) {
console.log("Connecting in",Math.abs(ms),"ms.");
}
}
function connect() {
var timerId, $indicator = $(".indicator-connection");
win.pusher.connection.bind('connecting_in', function(delay) {
clearInterval(timerId);
if( $indicator.length ) {
$indicator.attr('class','indicator-connection isDisconnected');
}
timerId = setInterval(function() {
delay = delay - 1000;
printConnectingIn(delay);
}, 1000);
});
win.pusher.connection.bind('connected', function() {
clearInterval(timerId);
if( !pusherIsConnected ) {
$indicator.attr('class', "indicator-connection isConnected");
$app.trigger('pusherConnected');
}
pusherIsConnected = true;
});
win.pusher.connection.bind('disconnected', function() {
$indicator.attr("class", "indicator-connection isDisconnected");
});
win.pusher.connection.bind('failed', function() {
$indicator.attr("class", "indicator-connection isDisconnected");
});
win.pusher.connection.bind('unavailable', function() {
$indicator.attr("class", "indicator-connection isDisconnected");
});
}
function listen() {
$app.on('pusherConnected', function(){
var channelsBound = $app.data('channelsbound');
if( typeof channelsBound === 'undefined' ) {
bindMeetingChannelEvents();
if( isSignedIn ) {
bindAttendeeChannelEvents();
}
bindSessionChannelEvents(null, 0); // listen for event-wide new posts, etc.
// session channel events must be bound here even for safety,
// even if history is going to pull in new session
$app.data('channelsbound', true); //.trigger('bindChannels');
$app.data('isloading', false);
}
});
$app.on('bindSessionChannelEvents', bindSessionChannelEvents);
$app.on('click','.x-ping', initiatePing);
$app.on('pong', receivePong);
}
function bindMeetingChannelEvents() {
meetingChannel = win.pusher.subscribe(meetingChannelName);
meetingChannel.bind('announcement', function(data){
$app.trigger('displayAnnouncement', data);
});
// right now this is used for realtime leaderboards in leaderboards.js
// this can be a points update for any attendee at this meeting
// not just the current_attendee
meetingChannel.bind('points_updated', function(data){
$app.trigger('pointsUpdated', data);
});
meetingChannel.bind('event_points_updated', function(data){
$app.trigger('eventPointsUpdated', data);
});
meetingChannel.bind('attendee_joined_meeting', function(data){
$app.trigger('attendee_joined_meeting',[data]);
});
meetingChannel.bind('attendee_joined_event', function(data){
$app.trigger('attendee_joined_event',[data]);
});
meetingChannel.bind('photo_created', function(data){
$app.trigger('appendPhoto', data);
});
meetingChannel.bind('photo_removed', function(data){
$app.trigger('removePhoto', data);
});
meetingChannel.bind('photo_reposted', function(data){
$app.trigger('displayNewPhotoRepostCount', data);
});
meetingChannel.bind('remove_question_from_projection', function(j){
$app.trigger('questionRemovedFromProduction',[j]);
});
meetingChannel.bind('survey_deployed', function(data){
$app.trigger('deploySurvey',[data]);
});
meetingChannel.bind('survey_cleared', function(data){
$app.trigger('clearSurvey',[data]);
});
meetingChannel.bind('icebreaker_deployed', function(data){
$app.trigger('deployIcebreaker',[data]);
});
meetingChannel.bind('icebreaker_cleared', function(data){
$app.trigger('clearIcebreaker',[data]);
});
}
function bindAttendeeChannelEvents() {
attendeeChannel = win.pusher.subscribe(attendeeChannelName);
attendeeChannel.bind('points_earned', function(data){
$app.trigger('bumpPoints',[data]);
});
attendeeChannel.bind('badge_earned', function(data){
$app.trigger('displayNewBadge',[data]);
});
attendeeChannel.bind('mission_completed', function(data){
$app.trigger('displayNewMission',[data]);
});
attendeeChannel.bind('prize_won', function(data){
$app.trigger('displayNewPrize',[data]);
});
attendeeChannel.bind('pong', function(jres){
$app.trigger('pong', jres);
});
}
function bindSessionChannelEvents(e,eventId) {
// 3 possibilities: no channel bound, same channel, or new channel being bound
if( boundSessionChannelEventId === -1 ) {
// do nothing
} else if( boundSessionChannelEventId === eventId ) {
return;
} else { // new session - need to unbind old one
var oldSessionChannelName = getSessionChannelName(boundSessionChannelEventId);
win.pusher.unsubscribe(oldSessionChannelName);
}
var sessionChannelName = getSessionChannelName(eventId);
boundSessionChannelEventId = eventId;
sessionChannel = win.pusher.subscribe(sessionChannelName);
sessionChannel.bind('post_created', function(data) {
if( !$app.data('isloading') ) { // isotope can't take new messages while loading, so have to ignore
$app.trigger('postCreated', data);
}
});
sessionChannel.bind('question_created', function(j){
var q = j.question;
$app.trigger('update_stat',[{selector: '#sesh .questions-total', subselector: ".fig"},{count: q.event_questions_count}]);
});
// this only happens when questions are removed
sessionChannel.bind('question_count_updated', function(j){
$app.trigger('update_stat',[{selector: '#sesh .questions-total', subselector: ".fig", onlyIncrement: false},{count: j.count}]);
});
sessionChannel.bind('checkin_count_updated', function(j) {
$app.trigger('update_stat',[{selector: '.'+ j.context +'-'+ j.id +' .counter-checkins'},{count: j.count}]);
});
sessionChannel.bind('message_count_updated', function(j) {
$app.trigger('update_stat',[{selector: '.'+ j.context +'-'+ j.id +' .counter-messages'},{count: j.count}]);
win.setLedgerCount('event_total_messages', parseInt(j.count, 10));
});
sessionChannel.bind('repost_count_updated', function(j) {
$app.trigger('update_stat',[{selector: '.'+ j.context +'-'+ j.id +' .counter-remessages'},{count: j.count_parent}]);
});
sessionChannel.bind('author_repost_count_updated', function(j){
$app.trigger('authorRepostCountUpdated', j);
});
sessionChannel.bind('event_photo_count_updated', function(j) {
$app.trigger('update_stat',[{selector: '.'+ j.context +'-'+ j.id +' .photos-total', subselector: ".fig"},{count: j.count_parent}]);
});
sessionChannel.bind('message_action', function(data){
$app.trigger('completeMessageAction', [data]);
});
sessionChannel.bind('rating_updated', function(data){
$app.trigger('updateRating', [data]);
});
}
function getSessionChannelName(eventId) {
return meetingChannelName + "_session_" + eventId;
}
// PING
function initiatePing(e){
e.preventDefault();
var $btn = $(this);
if( $btn.hasClass('isPinging') ) {
stopPinging();
$btn.text('Start Pinging');
} else {
startPinging();
$btn.text('Stop Pinging');
}
$btn.toggleClass('isPinging');
}
function startPinging() {
$app.data('pinging',true);
pingInterval = setInterval(sendPing,1000);
}
function stopPinging() {
clearInterval(pingInterval);
}
function sendPing() {
var templates = lazyCompileTemplates(); // must be first
var sent = performance.now();
var id = parseInt(sent,10);
var ping = {
id: id,
sent_at: (new Date()).toTimeString().substring(0,8),
sent: sent,
rcvd_at: null,
rcvd_json: null,
rcvd_push: null,
elapsed_json: null,
elapsed_push: null
};
var html = templates.ping.call(this, ping);
$pings.prepend(html);
var jqxhr = $.ajax({
url: '/send_ping',
type: 'GET',
dataType: 'json',
data: { id: id }
}).fail(function(result){
var $ping = $pings.find('.ping-'+id);
$ping.find('.elapsed_json').toggleClass('hasError',true).text('ERROR');
}).done(function(result){
ping.rcvd_json = performance.now();
var $ping = $pings.find('.ping-'+id);
ping.elapsed_json = ping.rcvd_json - sent;
ping.elapsed_json_friendly = parseInt(ping.elapsed_json, 10) + " ms";
$ping.find('.elapsed_json').toggleClass('hasError',false).text(ping.elapsed_json_friendly);
});
}
function receivePong(e,id){
var $ping = $pings.find('.ping-'+id);
var sent = parseFloat( $ping.data('sent') );
var elapsed_push = performance.now() - sent;
var elapsed_push_friendly = parseInt(elapsed_push, 10) + " ms";
$ping.find('.elapsed_push').text(elapsed_push_friendly);
}
function hidePingButton(){
$('.x-ping').hide();
$('.not-supported').show();
}
function lazyCompileTemplates() { // don't run on init
if( !realtime_templates.hasOwnProperty('compiled') ) {
//game_templates.activity_items = Handlebars.compile( $('#activity-items-template').html() );
realtime_templates.ping = Handlebars.compile( $('#ping-template').html() );
}
return realtime_templates;
}
$(function(){
init();
});
})(jQuery, document, window);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment