-
Notifications
You must be signed in to change notification settings - Fork 6.7k
firetactoe pull request #558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| runtime: python27 | ||
| api_version: 1 | ||
| threadsafe: true | ||
|
|
||
| handlers: | ||
| - url: /.* | ||
| script: firetactoe.application | ||
|
|
||
| libraries: | ||
| - name: pycrypto | ||
| version: latest | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Always use explicit versions. Latest sometimes isn't the latest, and even if it were we don't want the sample to suddenly break. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| from google.appengine.ext import vendor | ||
|
|
||
| # Add any libraries installed in the "lib" folder. | ||
| vendor.add('lib') |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,304 @@ | ||
| <html> | ||
| <head> | ||
|
|
||
| <script src="https://www.gstatic.com/firebasejs/3.3.2/firebase.js"></script> | ||
| <!-- <script src="https://www.gstatic.com/firebasejs/3.3.0/firebase-database.js"></script> --> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If this isn't necessary, remove it. |
||
| <script> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move all this to a separate .js file. |
||
| // Initialize Firebase object | ||
| var config = { | ||
| apiKey: "AIzaSyB_pwNiBi8Q3iakJitkQHtEQ5SZWmp9EiY", | ||
| authDomain: "imposing-mind-131903.firebaseapp.com", | ||
| databaseURL: "https://imposing-mind-131903.firebaseio.com" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably best to put placeholders here, preferably put all this stuff in a single file that gets pulled in somehow. |
||
| storageBucket: "imposing-mind-131903.appspot.com" | ||
| }; | ||
| firebase.initializeApp(config); | ||
| </script> | ||
|
|
||
| <style type='text/css'> | ||
| body { | ||
| font-family: 'Helvetica'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. think we should also factor out css and js into separate files. |
||
| } | ||
|
|
||
| #board { | ||
| width:152px; | ||
| height: 152px; | ||
| margin: 20px auto; | ||
| } | ||
|
|
||
| #display-area { | ||
| text-align: center; | ||
| } | ||
|
|
||
| #this-game { | ||
| font-size: 9pt; | ||
| } | ||
|
|
||
| #winner { | ||
| } | ||
|
|
||
| table { | ||
| border-collapse: collapse; | ||
| } | ||
|
|
||
| td { | ||
| width: 50px; | ||
| height: 50px; | ||
| font-family: "Helvetica"; | ||
| font-size: 16pt; | ||
| text-align: center; | ||
| vertical-align: middle; | ||
| margin:0px; | ||
| padding: 0px; | ||
| } | ||
|
|
||
| div.cell { | ||
| float: left; | ||
| width: 50px; | ||
| height: 50px; | ||
| border: none; | ||
| margin: 0px; | ||
| padding: 0px; | ||
| } | ||
|
|
||
| div.mark { | ||
| position: absolute; | ||
| top: 15px; | ||
| } | ||
|
|
||
| div.l { | ||
| border-right: 1pt solid black; | ||
| } | ||
|
|
||
| div.c { | ||
| } | ||
|
|
||
| div.r { | ||
| border-left: 1pt solid black; | ||
| } | ||
|
|
||
| div.t { | ||
| border-bottom: 1pt solid black; | ||
| } | ||
|
|
||
| div.m { | ||
| } | ||
|
|
||
| div.b { | ||
| border-top: 1pt solid black; | ||
| } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <script type='text/javascript'> | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please move this to a js file, probably can combine it with the snippet above. |
||
| var state = { | ||
| game_key: '{{ game_key }}', | ||
| me: '{{ me }}' | ||
| }; | ||
|
|
||
| // This is our Firebase realtime DB path that we'll listen to for updates | ||
| // We'll initialize this later in openChannel() | ||
| var channel = null; | ||
|
|
||
| updateGame = function() { | ||
| for (i = 0; i < 9; i++) { | ||
| var square = document.getElementById(i); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I feel that jquery would make this section slightly more readable, please feel free to use it if you feel the same. |
||
| square.innerHTML = state.board[i]; | ||
| if (state.winner != '' && state.winningBoard != '') { | ||
| if (state.winningBoard[i] == state.board[i]) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Believe we should be using triple =. Have you run this through jslint? |
||
| if (state.winner == state.me) { | ||
| square.style.background = "green"; | ||
| } else { | ||
| square.style.background = "red"; | ||
| } | ||
| } else { | ||
| square.style.background = "white"; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| var display = { | ||
| 'other-player': 'none', | ||
| 'your-move': 'none', | ||
| 'their-move': 'none', | ||
| 'you-won': 'none', | ||
| 'you-lost': 'none', | ||
| 'board': 'block', | ||
| 'this-game': 'block', | ||
| }; | ||
|
|
||
| if (!state.userO || state.userO == '') { | ||
| display['other-player'] = 'block'; | ||
| display['board'] = 'none'; | ||
| display['this-game'] = 'none'; | ||
| } else if (state.winner == state.me) { | ||
| display['you-won'] = 'block'; | ||
| } else if (state.winner != '') { | ||
| display['you-lost'] = 'block'; | ||
| } else if (isMyMove()) { | ||
| display['your-move'] = 'block'; | ||
| } else { | ||
| display['their-move'] = 'block'; | ||
| } | ||
|
|
||
| for (var label in display) { | ||
| document.getElementById(label).style.display = display[label]; | ||
| } | ||
| }; | ||
|
|
||
| isMyMove = function() { | ||
| return (state.winner == "") && | ||
| (state.moveX == (state.userX == state.me)); | ||
| } | ||
|
|
||
| myPiece = function() { | ||
| return state.userX == state.me ? 'X' : 'O'; | ||
| } | ||
|
|
||
| // This message sends POST requests back to the App Engine server | ||
| sendMessage = function(path, opt_param) { | ||
| path += '?g=' + state.game_key; | ||
| if (opt_param) { | ||
| path += '&' + opt_param; | ||
| } | ||
| var xhr = new XMLHttpRequest(); | ||
| xhr.open('POST', path, true); | ||
| xhr.send(); | ||
| }; | ||
|
|
||
| // Send the user's latest move back to the server | ||
| moveInSquare = function(id) { | ||
| if (isMyMove() && state.board[id] == ' ') { | ||
| sendMessage('/move', 'i=' + id); | ||
| } | ||
| } | ||
|
|
||
| highlightSquare = function(id) { | ||
| if (state.winner != "") { | ||
| return; | ||
| } | ||
| for (i = 0; i < 9; i++) { | ||
| if (i == id && isMyMove()) { | ||
| if (state.board[i] = ' ') { | ||
| color = 'lightBlue'; | ||
| } else { | ||
| color = 'lightGrey'; | ||
| } | ||
| } else { | ||
| color = 'white'; | ||
| } | ||
|
|
||
| document.getElementById(i).style['background'] = color; | ||
| } | ||
| } | ||
|
|
||
| // This method lets the server know that the user has opened the channel | ||
| // After this method is called, the server may begin to send updates | ||
| onOpened = function() { | ||
| sendMessage('/opened'); | ||
| }; | ||
|
|
||
| // This deletes the data associated with the Firebase path | ||
| // it is critical that this data be deleted since it costs money | ||
| deleteChannel = function() { | ||
| sendMessage('/delete'); | ||
| }; | ||
|
|
||
| // This method is called every time an event is fired from Firebase | ||
| // it updates the entire game state and checks for a winner | ||
| // if a player has won the game, this function calls the server to delete | ||
| // the data stored in Firebase | ||
| onMessage = function(m) { | ||
| newState = m; | ||
| state.board = newState.board || state.board; | ||
| state.userX = newState.userX || state.userX; | ||
| state.userO = newState.userO || state.userO; | ||
| state.moveX = newState.moveX; | ||
| state.winner = newState.winner || ""; | ||
| state.winningBoard = newState.winningBoard || ""; | ||
| updateGame(); | ||
| // now check to see if there is a winner // | ||
| if (channel && state.winner != '' && state.winningBoard != '') { | ||
| channel.off(); //stop listening on this path | ||
| deleteChannel(); //delete the data we wrote | ||
| } | ||
| } | ||
|
|
||
| // This function opens a realtime communication channel with Firebase | ||
| // It logs in securely using the client token passed from the server | ||
| // then it sets up a listener on the proper database path (also passed by server) | ||
| // finally, it calls onOpened() to let the server know it is ready to receive messages | ||
| openChannel = function() { | ||
| var token = '{{ token }}'; // secure token passed from the server // | ||
| var channel_id = '{{ channel_id }}'; // id of the 'channel' we'll be listening to // | ||
|
|
||
| // sign into Firebase with the token passed from the server | ||
| firebase.auth().signInWithCustomToken(token).catch(function(error) { | ||
| console.log("Login Failed!", error.code); | ||
| console.log("Error message: ", error.message); | ||
| }); | ||
|
|
||
| // setup a database reference at path /channels/channel_id | ||
| channel = firebase.database().ref('channels/' + channel_id); | ||
| // add a listener to the path that fires any time the value of the data changes | ||
| channel.on('value', function(data) { | ||
| onMessage(data.val()); | ||
| }); | ||
| onOpened(); | ||
| // let the server know that the channel is open | ||
| } | ||
|
|
||
| // This function opens a communication channel with the server | ||
| // then it adds listeners to all the squares on the board | ||
| // next it pulls down the initial game state from template values | ||
| // finally it updates the game state with those values by calling onMessage() | ||
| initialize = function() { | ||
| openChannel(); | ||
| var i; | ||
| for (i = 0; i < 9; i++) { | ||
| var square = document.getElementById(i); | ||
| square.onmouseover = new Function('highlightSquare(' + i + ')'); | ||
| square.onclick = new Function('moveInSquare(' + i + ')'); | ||
| } | ||
| initial_message = {{ initial_message|safe }}; // use the |safe flag to get unescaped json to render // | ||
| onMessage(initial_message); | ||
| } | ||
|
|
||
| setTimeout(initialize, 100); | ||
|
|
||
| </script> | ||
| <div id='display-area'> | ||
| <h2>Firebase-enabled Tic Tac Toe</h2> | ||
| <div id='other-player' style='display:none'> | ||
| Waiting for another player to join.<br> | ||
| Send them this link to play:<br> | ||
| <div id='game-link'><a href='{{ game_link }}'>{{ game_link }}</a></div> | ||
| </div> | ||
| <div id='your-move' style='display:none'> | ||
| Your move! Click a square to place your piece. | ||
| </div> | ||
| <div id='their-move' style='display:none'> | ||
| Waiting for other player to move... | ||
| </div> | ||
| <div id='you-won'> | ||
| You won this game! | ||
| </div> | ||
| <div id='you-lost'> | ||
| You lost this game. | ||
| </div> | ||
| <div id='board'> | ||
| <div class='t l cell'><table><tr><td id='0'></td></tr></td></table></div> | ||
| <div class='t c cell'><table><tr><td id='1'></td></tr></td></table></div> | ||
| <div class='t r cell'><table><tr><td id='2'></td></tr></td></table></div> | ||
| <div class='m l cell'><table><tr><td id='3'></td></tr></td></table></div> | ||
| <div class='m c cell'><table><tr><td id='4'></td></tr></td></table></div> | ||
| <div class='m r cell'><table><tr><td id='5'></td></tr></td></table></div> | ||
| <div class='b l cell'><table><tr><td id='6'></td></tr></td></table></div> | ||
| <div class='b c cell'><table><tr><td id='7'></td></tr></td></table></div> | ||
| <div class='b r cell'><table><tr><td id='8'></td></tr></td></table></div> | ||
| </div> | ||
| <div id='this-game' float='top'> | ||
| Quick link to this game: <span id='this-game-link'><a href='{{ game_link }}'>{{ game_link }}</a></span> | ||
| </div> | ||
| </div> | ||
| </body> | ||
| </html> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Github won't let me comment on a binary file): Please remove .DS_Store. I'd recommend adding it to your global gitignore.