Last active
March 18, 2016 17:24
-
-
Save kbohinski/cb3fee469351f3a40cf5 to your computer and use it in GitHub Desktop.
PubNub Demos http://kboh.codes/pubnub
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
/** | |
* @author Kevin Bohinski <bohinsk1@tcnj.edu> | |
* @version 1.0 | |
* @since 2016-3-13 | |
* | |
* Project Name: PubNub SoundCloud Demo | |
* Description: • Demonstrate understanding of PubNub | |
* | |
* Filename: index.html | |
* Description: HTML File, with embedded JS for PubNub. | |
* Last Modified: 2016-3-17 | |
*/ | |
--> | |
<!doctype html> | |
<html lang="en"> | |
<head> | |
<!-- HTML meta key, value, pairs --> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<!-- HTML meta author, description, and title --> | |
<meta name="author" content="https://keybase.io/kbohinski"> | |
<meta name="description" content="PubNub SoundCloud!"> | |
<title>PubNub SoundCloud!</title> | |
<!-- CDN stylesheets to clean up display --> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/> | |
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootswatch/3.3.4/paper/bootstrap.min.css"/> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"/> | |
<!-- Bootstrap's required javascript --> | |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> | |
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> | |
<!-- IE9 bootstrap support --> | |
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> | |
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> | |
<!--[if lt IE 9]> | |
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> | |
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> | |
<![endif]--> | |
<!-- JS --> | |
<!-- CDN in the PubNub & SoundCloud JS SDK --> | |
<script src="http://cdn.pubnub.com/pubnub-3.14.3.min.js"></script> | |
<script src="https://w.soundcloud.com/player/api.js"></script> | |
<script src="https://cdn.rawgit.com/broofa/node-uuid/master/uuid.js"></script> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>PubNub SoundCloud!</h1> | |
<ul style="padding-top: 65px; padding-bottom: 65px;"> | |
<li><a href="/pubnub/tictactoe.html">PubNub Tic-Tac-Toe</a></li> | |
<li><a href="https://gist.github.com/kbohinski/cb3fee469351f3a40cf5">Source</a></li> | |
</ul> | |
<div class="row"> | |
<div class="col-xs-12"> | |
<iframe id="song" width="100%" height="600" scrolssling="no" frameborder="no" | |
src="https://w.soundcloud.com/player/?url=https://soundcloud.com/ideaot/macklerena4&auto_play=false&hide_related=false&show_comments=true&show_user=true&show_reposts=false&visual=true"></iframe> | |
</div> | |
</div> | |
<div id="messages"></div> | |
</div> | |
</body> | |
<script type="text/javascript"> | |
/* Uses ECMAScript's strict mode */ | |
"use strict"; | |
/* Wrap in an IIFE to avoid pollution of the global namespace. */ | |
let iife = (function () { | |
/* Set user id and last message to avoid collisions */ | |
let userId = uuid.v4(); | |
let last = {time: 0}; | |
/* Set PubNub Keys */ | |
let PUBNUB_PUB_KEY = 'pub-c-a0d12b56-2353-4a7c-b021-d0bab6fcfbdf'; | |
let PUBNUB_SUB_KEY = 'sub-c-9682eaf8-ec9d-11e5-8112-02ee2ddab7fe'; | |
/* Setup SoundCloud object */ | |
let soundcloud = SC.Widget('song'); | |
let SONG_URL = 'https://soundcloud.com/ideaot/macklerena'; | |
let ms_delay = 250; | |
/* Setup Date object for millisecond calculations */ | |
let d = new Date(); | |
/* Load in song */ | |
soundcloud.load(SONG_URL, { | |
'auto_play': false, | |
'visual': true | |
}); | |
/** | |
* Helper function to add a message to the DOM. | |
* | |
* @param time : Position in song from start (milliseconds) | |
* @param from : Who the message was from | |
* @param type : Type of the message | |
*/ | |
function addMessage(time, from, type) { | |
/* Check if the message to add is from ourselves */ | |
if (from === userId) { | |
from = 'You'; | |
} else { | |
from = 'Someone Else: ' + from; | |
} | |
/* Grab div to put messages into */ | |
let messages = document.getElementById('messages'); | |
/* Make new node to add to the DOM */ | |
let newNode = document.createElement('DIV'); | |
newNode.innerHTML = '<div class="panel panel-default"><div class="panel-body"><p><b>' + type + '</b></p><p>' + time + '</p><span class="text-muted">' + from + '</span></div></div>'; | |
/* Insert new node */ | |
messages.insertBefore(newNode, messages.childNodes[0]); | |
} | |
/** | |
* Helper function to check if the milliseconds changed significantly to prevent an infinite loop. | |
* | |
* @param lastTime : The time from the last message | |
* @param newTime : The time from the incoming message | |
* @returns {boolean} : If the difference is significant. | |
*/ | |
function checkRange(lastTime, newTime) { | |
if (lastTime === undefined) { | |
return true; | |
} else { | |
return (Math.abs(lastTime - newTime) > 10); | |
} | |
} | |
/** | |
* Helper function to check if the song is playing | |
* | |
* @returns {boolean} : If the song is playing | |
*/ | |
function isPlaying() { | |
soundcloud.isPaused(function (status) { | |
return !status; | |
}); | |
} | |
/* Instantiate a new instance of PubNub */ | |
let pub_nub = PUBNUB.init({ | |
publish_key: PUBNUB_PUB_KEY, | |
subscribe_key: PUBNUB_SUB_KEY, | |
uuid: userId, | |
error: function (error) { | |
console.log('Error:', error); | |
} | |
}); | |
/* Subscribe to the channel */ | |
pub_nub.subscribe({ | |
channel: 'audiosync_' + SONG_URL, | |
message: function (m) { | |
/* Handle incoming messages */ | |
if (m.type === 'seek') { | |
if ((m.from !== userId) && checkRange(last.time, m.time)) { | |
ms_delay = d.getTime - m.timeSent; | |
soundcloud.seekTo(parseFloat(m.time.toFixed(1) + ms_delay)); | |
} | |
addMessage(m.time.toFixed(1), m.from, m.type); | |
} else if (m.type === 'play' && !isPlaying() && last.type !== 'play') { | |
soundcloud.play(); | |
addMessage('Status', m.from, m.type); | |
} else if (m.type === 'pause' && isPlaying() && last.type !== 'pause') { | |
soundcloud.pause(); | |
addMessage('Status', m.from, m.type); | |
} | |
last = m; | |
}, | |
error: function (error) { | |
console.log('Error: ' + JSON.stringify(error)); | |
} | |
}); | |
/* Whenever the user seeks within the song, change the song position on the other browser */ | |
soundcloud.bind(SC.Widget.Events.SEEK, function (time) { | |
/* Check to see if position in song changed */ | |
if (last.time.toFixed(1) !== time.currentPosition.toFixed(1)) { | |
pub_nub.publish({ | |
channel: 'audiosync_' + SONG_URL, | |
message: { | |
type: 'seek', | |
time: time.currentPosition, | |
from: userId, | |
timeSent: d.getTime() | |
} | |
}); | |
} | |
}); | |
/* Whenever the user plays, play the song on the other browser */ | |
soundcloud.bind(SC.Widget.Events.PLAY, function () { | |
if (last.type !== 'play') { | |
pub_nub.publish({ | |
channel: 'audiosync_' + SONG_URL, | |
message: { | |
type: 'play', | |
time: 0, | |
from: userId | |
} | |
}); | |
} | |
}); | |
/* Whenever the user pauses, pause the song on the other browser */ | |
soundcloud.bind(SC.Widget.Events.PAUSE, function () { | |
if (last.type !== 'pause') { | |
pub_nub.publish({ | |
channel: 'audiosync_' + SONG_URL, | |
message: { | |
type: 'pause', | |
time: 0, | |
from: userId | |
} | |
}); | |
} | |
}); | |
/* Return public interface so it can be used outside of the IIFE */ | |
return { | |
pn: pub_nub, | |
sc: soundcloud | |
}; | |
})(); | |
</script> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
/** | |
* @author Kevin Bohinski <bohinsk1@tcnj.edu> | |
* @version 1.0 | |
* @since 2016-3-13 | |
* | |
* Project Name: PubNub Tic-Tac-Toe Demo | |
* Description: • Demonstrate understanding of PubNub | |
* | |
* Filename: tictactoe.html | |
* Description: HTML File, with embedded JS for PubNub. | |
* Last Modified: 2016-3-17 | |
*/ | |
--> | |
<!doctype html> | |
<html lang="en"> | |
<head> | |
<!-- HTML meta key, value, pairs --> | |
<meta charset="UTF-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<!-- HTML meta author, description, and title --> | |
<meta name="author" content="https://keybase.io/kbohinski"> | |
<meta name="description" content="PubNub Tic-Tac-Toe!"> | |
<title>PubNub Tic-Tac-Toe!</title> | |
<!-- CDN stylesheets to clean up display --> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css"/> | |
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootswatch/3.3.4/paper/bootstrap.min.css"/> | |
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css"/> | |
<!-- Bootstrap's required javascript --> | |
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> | |
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script> | |
<!-- IE9 bootstrap support --> | |
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> | |
<!-- WARNING: Respond.js doesn't work if you view the page via file:// --> | |
<!--[if lt IE 9]> | |
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script> | |
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> | |
<![endif]--> | |
<!-- CSS --> | |
<style> | |
.btn-fix { | |
width: 100%; | |
height: 100%; | |
display: table-cell; | |
font-size: 20px; | |
} | |
#form { | |
padding-bottom: 65px; | |
} | |
#messages { | |
padding-top: 65px; | |
} | |
.alert h2 { | |
color: white; | |
} | |
</style> | |
<!-- JS --> | |
<!-- CDN in the PubNub JS SDK --> | |
<script src="http://cdn.pubnub.com/pubnub-3.14.3.min.js"></script> | |
<script src="https://cdn.rawgit.com/broofa/node-uuid/master/uuid.js"></script> | |
</head> | |
<body> | |
<div class="container"> | |
<h1>PubNub Tic-Tac-Toe!</h1> | |
<ul style="padding-top: 65px; padding-bottom: 65px;"> | |
<li><a href="/pubnub/index.html">PubNub SoundCloud</a></li> | |
<li><a href="https://gist.github.com/kbohinski/cb3fee469351f3a40cf5">Source</a></li> | |
</ul> | |
<div id="room-info" class="alert alert-info"><p><strong>Room Number:</strong></p> | |
<div id="room"></div> | |
<p>Use this room number to allow others to enter your room.</p> | |
</div> | |
<div id="xoAlert" class="alert alert-danger"><p><strong>Red/Blue:</strong></p> | |
<div id="xo"></div> | |
</div> | |
<form id="form"> | |
<div class="form-group"> | |
<label for="roomid">If you wish to enter another room, enter the room number here. Otherwise, just press | |
start!</label> | |
<input id="roomid" name="roomid" class="form-control" type="text"> | |
</div> | |
<div class="form-group"> | |
<input name="submit" value="Start!" class="btn btn-primary" type="submit" id="submit"> | |
</div> | |
</form> | |
<div id="board"> | |
<div class="row"> | |
<div class="col-xs-4"> | |
<a href="#" id="00" class="btn btn-default btn-fix">-</a> | |
</div> | |
<div class="col-xs-4"> | |
<a href="#" id="10" class="btn btn-default btn-fix">-</a> | |
</div> | |
<div class="col-xs-4"> | |
<a href="#" id="20" class="btn btn-default btn-fix">-</a> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-xs-4"> | |
<a href="#" id="01" class="btn btn-default btn-fix">-</a> | |
</div> | |
<div class="col-xs-4"> | |
<a href="#" id="11" class="btn btn-default btn-fix">-</a> | |
</div> | |
<div class="col-xs-4"> | |
<a href="#" id="21" class="btn btn-default btn-fix">-</a> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-xs-4"> | |
<a href="#" id="02" class="btn btn-default btn-fix">-</a> | |
</div> | |
<div class="col-xs-4"> | |
<a href="#" id="12" class="btn btn-default btn-fix">-</a> | |
</div> | |
<div class="col-xs-4"> | |
<a href="#" id="22" class="btn btn-default btn-fix">-</a> | |
</div> | |
</div> | |
</div> | |
<div id="messages"></div> | |
</div> | |
</body> | |
<script type="text/javascript"> | |
/* Uses ECMAScript's strict mode */ | |
"use strict"; | |
/* Wrap in an IIFE to avoid pollution of the global namespace. */ | |
let iife = (function () { | |
/* Fix width on page load */ | |
window.onload = function () { | |
resizeBoxes(); | |
}; | |
/** | |
* Helper function to fix box size | |
*/ | |
function resizeBoxes() { | |
for (let x = 0; x < 3; x++) { | |
for (let y = 0; y < 3; y++) { | |
$('#' + x.toString() + y.toString()).height($('#' + x.toString() + y.toString()).parent().width()); | |
$('#' + x.toString() + y.toString()).width($('#' + x.toString() + y.toString()).parent().width()); | |
} | |
} | |
} | |
/* Set user info and last message to avoid collisions */ | |
let userId = uuid.v4(); | |
let xo = 'red'; | |
let ROOM_ID = Math.floor(Math.random() * 9000) + 1000; | |
let last = {from: 'blue'}; | |
/* Display room id and if they are x or o */ | |
let roomDisplay = document.getElementById('room'); | |
let xoDisplay = document.getElementById('xo'); | |
roomDisplay.innerHTML = ROOM_ID; | |
xoDisplay.innerHTML = 'You are playing as : ' + xo; | |
/* Set PubNub Keys */ | |
let PUBNUB_PUB_KEY = 'pub-c-a0d12b56-2353-4a7c-b021-d0bab6fcfbdf'; | |
let PUBNUB_SUB_KEY = 'sub-c-9682eaf8-ec9d-11e5-8112-02ee2ddab7fe'; | |
/* Instantiate a new instance of PubNub */ | |
let pub_nub = PUBNUB.init({ | |
publish_key: PUBNUB_PUB_KEY, | |
subscribe_key: PUBNUB_SUB_KEY, | |
uuid: userId, | |
error: function (error) { | |
console.log('Error:', error); | |
} | |
}); | |
/* Subscribe to current room, to see if other user has joined and is starting the game */ | |
pub_nub.subscribe({ | |
channel: 'tictactoe_' + ROOM_ID, | |
message: function (m) { | |
handleMessage(m); | |
}, | |
error: function (error) { | |
console.log('Error: ' + JSON.stringify(error)); | |
} | |
}); | |
/* If the user switches the room, switch it, and start the game on both ends */ | |
let submit = document.getElementById('submit'); | |
submit.addEventListener('click', function (e) { | |
/* Prevent link from being navigated to */ | |
e.preventDefault(); | |
/* If it is a different room, change some displays */ | |
if (document.getElementById('roomid').value !== ROOM_ID && document.getElementById('roomid').value !== '') { | |
ROOM_ID = document.getElementById('roomid').value; | |
roomDisplay.innerHTML = ROOM_ID; | |
xo = 'blue'; | |
xoDisplay.innerHTML = 'You are playing as : ' + xo; | |
document.getElementById('xoAlert').style.backgroundColor = '#2196F3'; | |
} | |
/* Subscribe, and send a message to start the game */ | |
pub_nub.subscribe({ | |
channel: 'tictactoe_' + ROOM_ID, | |
message: function (m) { | |
handleMessage(m); | |
}, | |
error: function (error) { | |
console.log('Error: ' + JSON.stringify(error)); | |
} | |
}); | |
pub_nub.publish({ | |
channel: 'tictactoe_' + ROOM_ID, | |
message: { | |
type: 'start', | |
from: xo | |
} | |
}); | |
handleMessage({type: 'start', from: xo}); | |
}, false); | |
/** | |
* Helper function to add a message to the DOM. | |
* | |
* @param value : Value of the message | |
* @param from : Who the message was from | |
* @param type : Type of the message | |
*/ | |
function addMessage(value, from, type) { | |
/* Check if the message to add is from ourselves */ | |
if (from === xo) { | |
from = 'You'; | |
} else { | |
from = 'Someone Else: ' + from; | |
} | |
/* Grab div to put messages into */ | |
let messages = document.getElementById('messages'); | |
/* Make new node to add to the DOM */ | |
let newNode = document.createElement('DIV'); | |
newNode.innerHTML = '<div class="panel panel-default"><div class="panel-body"><p><b>' + type + '</b></p><p>' + value + '</p><span class="text-muted">' + from + '</span></div></div>'; | |
/* Insert new node */ | |
messages.insertBefore(newNode, messages.childNodes[0]); | |
} | |
/** | |
* Helper function to handle incoming PubNub messages. | |
* Checks to see if game is being started, or a move was made. | |
* On new move, checks for a win condition. | |
* | |
* @param m : The message | |
*/ | |
function handleMessage(m) { | |
/* Add message to DOM for display */ | |
addMessage(m.node, m.from, m.type); | |
if (m.type === 'start') { | |
/* Start the game, change some displays */ | |
document.getElementById('form').innerHTML = ''; | |
document.getElementById('room-info').innerHTML = '<b>The game has started.</b><br>Red goes first.'; | |
/* Set this so red goes first */ | |
last = {from: 'blue'}; | |
} else { | |
/* Dont listen to cheaters :) */ | |
if (m.from !== last.from) { | |
/* Get the button they pressed, and change its color and value */ | |
let el = document.getElementById(m.node); | |
let red = 'btn btn-danger disabled btn-fix'; | |
let blue = 'btn btn-primary disabled btn-fix'; | |
if (m.from === 'red') { | |
el.className = red; | |
el.innerHTML = 'X'; | |
} else { | |
el.className = blue; | |
el.innerHTML = 'O'; | |
} | |
/* Check for vertical or horizontal win conditions */ | |
let checkVer = false; | |
let checkHor = false; | |
for (let x = 0; x < 3; x++) { | |
let el0 = document.getElementById('' + x.toString() + '0').className; | |
let el1 = document.getElementById('' + x.toString() + '1').className; | |
let el2 = document.getElementById('' + x.toString() + '2').className; | |
if (el0 === red && el1 === red && el2 === red) { | |
checkVer = true; | |
break; | |
} else if (el0 === blue && el1 === blue && el2 === blue) { | |
checkVer = true; | |
break; | |
} | |
el0 = document.getElementById('0' + x.toString()).className; | |
el1 = document.getElementById('1' + x.toString()).className; | |
el2 = document.getElementById('2' + x.toString()).className; | |
if (el0 === red && el1 === red && el2 === red) { | |
checkHor = true; | |
break; | |
} else if (el0 === blue && el1 === blue && el2 === blue) { | |
checkHor = true; | |
break; | |
} | |
} | |
/* Check for diagonal win conditions */ | |
let ul = document.getElementById('00').className; | |
let ur = document.getElementById('20').className; | |
let c = document.getElementById('11').className; | |
let ll = document.getElementById('02').className; | |
let lr = document.getElementById('22').className; | |
/* On a win, let the user know the game is over, and unsub them. */ | |
if (checkHor || checkVer || (ul === red && c === red && lr === red) || (ul === blue && c === blue && lr === blue) || (ur === red && c === red && ll === red) || (ur === blue && c === blue && ll === blue)) { | |
document.getElementById('room-info').innerHTML = '<h2><b>Game over!</b></h2><br><h2>' + m.from + ' wins!</h2>'; | |
pub_nub.unsubscribe({ | |
channel: 'tictactoe_' + ROOM_ID | |
}); | |
} | |
/* Resizes the buttons so they look pretty */ | |
resizeBoxes(); | |
} | |
} | |
/* Saves the last message to check for cheaters */ | |
last = m; | |
} | |
/* Attach the event listener to all the buttons */ | |
let buttons = document.querySelectorAll(".row .btn"); | |
for (let i = 0; i < buttons.length; i++) { | |
buttons[i].addEventListener('click', function buttonChecked(e) { | |
/* Prevent link from being navigated to */ | |
e.preventDefault(); | |
/* Determine which button was actually clicked */ | |
let el = e.target; | |
/* Send a message to let the other player's browser know */ | |
pub_nub.publish({ | |
channel: 'tictactoe_' + ROOM_ID, | |
message: { | |
type: 'pressed', | |
node: el.id, | |
from: xo | |
} | |
}); | |
}, false); | |
} | |
/* Return public interface so it can be used outside of the IIFE */ | |
return { | |
pn: pub_nub | |
}; | |
})(); | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment