Browse Source

add chat window

romanmatiasko 10 years ago
parent
commit
ab5610f339

+ 35 - 0
public/images/chat.svg

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+
+<!-- The icon can be used freely in both personal and commercial projects with no attribution required, but always appreciated. 
+You may NOT sub-license, resell, rent, redistribute or otherwise transfer the icon without express written permission from iconmonstr.com -->
+
+
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+
+	 width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
+
+<path id="speech-bubble-14-icon" fill="#299cad" d="M440.704,391.771C454.312,375.362,462,354.216,462,332.679c0-35.26-19.864-65.01-49.435-83.766
+
+	c4.186-13.053,6.395-26.594,6.395-40.27c0-90.207-87.645-155.312-184.479-155.312C137.037,53.331,50,118.929,50,208.644
+
+	c0,31.822,11.358,63.066,31.465,87.309c0.849,28.41-15.719,69.156-30.643,98.842c39.998-7.295,96.866-23.416,122.654-39.357
+
+	c15.134,3.717,29.826,6.027,44.007,7.1c17.877,50.588,80.211,89.32,160.944,69.494c17.455,10.789,55.943,21.699,83.016,26.639
+
+	C451.342,438.577,440.129,410.999,440.704,391.771z M172.431,318.04c-34.595,20.203-65.042,28.264-65.042,28.264
+
+	s10.299-27.762,14.588-59.699c-21.101-21.508-36.05-43.32-36.05-77.961c0-65.83,66.641-119.387,148.554-119.387
+
+	c81.912,0,148.554,53.557,148.554,119.387C383.034,276.784,304.718,353.12,172.431,318.04z M418.856,421.499
+
+	c0,0-19.577-5.182-41.82-18.172c-65.705,17.422-110.659-7.877-127.746-40.469c70.42-4.076,124.766-40.012,151.465-87.078
+
+	c19.564,14.066,31.901,34.5,31.901,57.207c0,22.273-9.612,36.297-23.179,50.127C412.234,403.649,418.856,421.499,418.856,421.499z"
+
+	/>
+
+</svg>
+

+ 58 - 3
public/javascripts/play.js

@@ -122,9 +122,6 @@ function movePiece(from, to, promotion, rcvd) {
       else if ($chess.insufficient_material())
         result = "Draw. (Insufficient Material)";
       fs.text(result);
-      
-      $('.resign').hide();
-      alert(result);
     }
 
     /* Add all moves to the table */
@@ -147,6 +144,11 @@ function movePiece(from, to, promotion, rcvd) {
         'move': move
       });
     }
+
+    if ($chess.game_over()) {
+      $('.resign').hide();
+      alert(result);
+    }
   }
 }
 
@@ -166,6 +168,8 @@ $(document).ready(function () {
       $('.chess_board.white').remove();
       $('.chess_board.black').show();
     }
+
+    $('#sendMessage').find('input').addClass($side === 'b' ? 'black' : 'white');
   });
 
   $socket.on('move', function (data) {
@@ -186,6 +190,24 @@ $(document).ready(function () {
     alert("This game already has two players. You have to create a new one.");
     window.location = '/';
   });
+
+  $socket.on('receive-message', function (data) {
+    var chat = $('ul#chat');
+    var chat_node = $('ul#chat')[0];
+    var messageSnd = $("#messageSnd")[0];
+
+    chat.append('<li class="' + data.color + ' left" >' + data.message + '</li>');
+
+    if (chat.is(':visible') && chat_node.scrollHeight > 300) {
+      setTimeout(function() { chat_node.scrollTop = chat_node.scrollHeight; }, 50);
+    } else if (!chat.is(':visible') && !$('.new-message').is(':visible')) {
+      $('#bubble').before('<span class="new-message">You have a new message!</span>');
+    }
+
+    if ($('#sounds').is(':checked')) {
+      messageSnd.play();
+    }
+  });
 });
 
 /* gameplay */
@@ -238,4 +260,37 @@ $(document).ready(function () {
     alert('You resigned.');
     window.location = '/';
   });
+
+  $('a.chat').click(function (e) {
+    $('#chat-wrapper').toggle();
+    $('.new-message').remove();
+    var chat_node = $('ul#chat')[0];
+    if (chat_node.scrollHeight > 300) {
+      setTimeout(function() { chat_node.scrollTop = chat_node.scrollHeight; }, 50);
+    }
+  });
+
+  $('#chat-wrapper .close').click(function (e) {
+    $('#chat-wrapper').hide();
+  });
+
+  $('#sendMessage').submit(function (e) {
+    e.preventDefault();
+    var input = $(this).find('input');
+    var message = input.val();
+    var color = $side === 'b' ? 'black' : 'white';
+
+    if (!/^\W*$/.test(message)) {
+      input.val('');
+      $('ul#chat').append('<li class="' + color + ' right" >' + message + '</li>');
+
+      var chat_node = $('ul#chat')[0];
+      if (chat_node.scrollHeight > 300) {
+        setTimeout(function() { chat_node.scrollTop = chat_node.scrollHeight; }, 50);
+      }
+
+      $socket.emit('send-message', { 'message': message, 'color': color });
+    }
+  });
+
 });

BIN
public/sounds/message.mp3


+ 108 - 2
public/stylesheets/style.css

@@ -99,10 +99,22 @@ h3 {
 .last-target {
   background: #77d1df !important; }
 
-.about-in-play {
+.chat {
+  text-decoration: none;
+  color: #248a99;
   margin-right: 1em;
   line-height: 50px;
-  float: right !important; }
+  float: right !important;
+  cursor: pointer;
+  font-weight: 600; }
+  .chat:hover {
+    color: #299cad; }
+    .chat:hover .new-message {
+      color: #d12521; }
+  .chat img {
+    vertical-align: middle; }
+  .chat .new-message {
+    color: #d12521; }
 
 .fork {
   float: left;
@@ -258,6 +270,100 @@ footer {
   margin: 0px 0px 5px 0px;
   float: left; }
 
+/* Chat */
+#chat-wrapper {
+  display: none;
+  position: absolute;
+  width: 270px;
+  right: 10px;
+  top: 99px;
+  border: 4px solid #fff;
+  background: #e6e3e0; }
+  #chat-wrapper h4 {
+    font-family: 'Cherry Swash';
+    font-size: 1.225rem;
+    height: 3em;
+    line-height: 3em;
+    margin: 5px 5%;
+    text-align: center;
+    color: #423443; }
+  #chat-wrapper a.close {
+    position: absolute;
+    top: 0;
+    right: 0;
+    background: #423443;
+    color: #fff;
+    font-size: 1.125rem;
+    padding: 0 7px;
+    text-decoration: none;
+    font-weight: 600;
+    margin: 1em 5%;
+    cursor: pointer; }
+    #chat-wrapper a.close:hover {
+      text-decoration: none;
+      background: #503f51; }
+  #chat-wrapper > span {
+    font-size: .9rem;
+    margin: 5px 5%;
+    display: block; }
+
+ul#chat {
+  position: relative;
+  top: 0;
+  max-height: 300px;
+  width: 100%;
+  overflow-y: scroll;
+  list-style-type: none; }
+  ul#chat li {
+    font-size: .9rem;
+    padding: 10px;
+    margin: 5px auto;
+    width: 90%;
+    border-radius: 5px;
+    position: relative; }
+    ul#chat li:before {
+      position: absolute;
+      content: '';
+      top: 10px; }
+  ul#chat li.black {
+    background: #444;
+    color: #fff; }
+  ul#chat li.white {
+    background: #fff;
+    color: #444; }
+  ul#chat li.left:before {
+    left: 0;
+    margin-left: -7px;
+    border-bottom: 7px solid transparent;
+    border-top: 7px solid transparent; }
+  ul#chat li.black.left:before {
+    border-right: 7px solid #444; }
+  ul#chat li.white.left:before {
+    border-right: 7px solid #fff; }
+  ul#chat li.right:before {
+    right: 0;
+    margin-right: -7px;
+    border-bottom: 7px solid transparent;
+    border-top: 7px solid transparent; }
+  ul#chat li.black.right:before {
+    border-left: 7px solid #444; }
+  ul#chat li.white.right:before {
+    border-left: 7px solid #fff; }
+
+#sendMessage input {
+  width: 100%;
+  padding: 15px 10px;
+  border: none;
+  outline: none;
+  font-size: .9rem;
+  border: 4px solid #e6e3e0; }
+#sendMessage input.black {
+  background: #444;
+  color: #fff; }
+#sendMessage input.white {
+  background: #fff;
+  color: #444; }
+
 /* Chessboard */
 #board_moves_wrapper {
   width: 100%;

+ 138 - 1
public/stylesheets/style.scss

@@ -2,6 +2,7 @@ $dark-purple: #423443;
 $blue: #2eafc2;
 $red: #d12521;
 $grey: #dad7d2;
+$dark-grey: #261e26;
 
 @mixin all-transition{
   -moz-transition: all 0.2s ease-in-out;
@@ -104,10 +105,26 @@ h3 {
 .last-target{
   background: lighten($blue, 20%) !important;
 }
-.about-in-play {
+.chat{
+  text-decoration: none;
+  color: darken($blue, 10%);
   margin-right: 1em;
   line-height: 50px;
   float: right !important;
+  cursor: pointer;
+  font-weight: 600;
+  &:hover{
+    color: darken($blue, 5%);
+    .new-message{
+      color: $red;
+    }
+  }
+  img{
+    vertical-align: middle;
+  }
+  .new-message{
+    color: $red;
+  }
 }
 .fork{
   float: left;
@@ -270,6 +287,126 @@ footer {
   float: left;
 }
 
+/* Chat */
+#chat-wrapper{
+  display: none;
+  position: absolute;
+  width: 270px;
+  right: 10px;
+  top: 99px;
+  border: 4px solid #fff;
+  background: lighten($grey, 5%);
+
+  h4{
+    font-family: 'Cherry Swash';
+    font-size: 1.225rem;
+    height: 3em;
+    line-height: 3em;
+    margin: 5px 5%;
+    text-align: center;
+    color: $dark-purple;
+  }
+
+  a.close{
+    position: absolute;
+    top: 0;
+    right: 0;
+    background: $dark-purple;
+    color: #fff;
+    font-size: 1.125rem;
+    padding: 0 7px;
+    text-decoration: none;
+    font-weight: 600;
+    margin: 1em 5%;
+    cursor: pointer;
+
+    &:hover{
+      text-decoration: none;
+      background: lighten($dark-purple, 5%);
+    }
+  }
+
+  > span{
+    font-size: .9rem;
+    margin: 5px 5%;
+    display: block;
+  }
+}
+
+ul#chat{
+  position: relative;
+  top: 0;
+  max-height: 300px;
+  width: 100%;
+  overflow-y: scroll;
+  list-style-type: none;
+
+  li{
+    font-size: .9rem;
+    padding: 10px;
+    margin: 5px auto;
+    width: 90%;
+    border-radius: 5px;
+    position: relative;
+
+    &:before{
+      position: absolute;
+      content: '';
+      top: 10px;
+    }
+  }
+  li.black{
+    background: #444;
+    color: #fff;
+  }
+  li.white{
+    background: #fff;
+    color: #444;
+  }
+  li.left:before{
+    left: 0;
+    margin-left: -7px;
+    border-bottom: 7px solid transparent;
+    border-top: 7px solid transparent;
+  }
+  li.black.left:before{
+    border-right: 7px solid #444;
+  }
+  li.white.left:before{
+    border-right: 7px solid #fff;
+  }
+  li.right:before{
+    right: 0;
+    margin-right: -7px;
+    border-bottom: 7px solid transparent;
+    border-top: 7px solid transparent;
+  }
+  li.black.right:before{
+    border-left: 7px solid #444;
+  }
+  li.white.right:before{
+    border-left: 7px solid #fff;
+  }
+}
+#sendMessage{
+  input{
+    width: 100%;
+    padding: 15px 10px;
+    border: none;
+    outline: none;
+    font-size: .9rem;
+    border: 4px solid lighten($grey, 5%);
+  }
+  input.black{
+    background: #444;
+    color: #fff;
+  }
+  input.white{
+    background: #fff;
+    color: #444;
+  }
+}
+
 /* Chessboard */
 
 #board_moves_wrapper {

+ 23 - 4
server.js

@@ -131,16 +131,21 @@ io.sockets.on('connection', function (socket) {
     });
   });
 
-  socket.on('resign', function(data) {
+  socket.on('resign', function (data) {
     cancelGame('opponent-resigned', socket);
   });
 
-  socket.on('disconnect', function () {
+  socket.on('disconnect', function (data) {
     cancelGame('opponent-disconnected', socket);
   });
+
+  socket.on('send-message', function (data) {
+    var opponent = getOpponent(socket);
+    opponent.socket.emit('receive-message', data);
+  });
 });
 
-function cancelGame(event, socket) {
+function getOpponent(socket) {
   for (var token in games) {
     var game = games[token];
 
@@ -149,10 +154,24 @@ function cancelGame(event, socket) {
 
       if (player.socket == socket) {
         var opponent = game.players[Math.abs(j - 1)];
+        return opponent;
+      }
+    }
+  }
+}
 
+function cancelGame(event, socket) {
+  for (var token in games) {
+    var game = games[token];
+
+    for (var j in game.players) {
+      var player = game.players[j];
+
+      if (player.socket == socket) {
+        var opponent = game.players[Math.abs(j - 1)];
         delete games[token];
         opponent.socket.emit(event);
       }
     }
   }
-}
+}

+ 2 - 5
views/about.jade

@@ -14,13 +14,10 @@ block content
     a(href='http://socket.io/') Socket.IO
     |  . Reti Chess also uses 
     a(href='https://github.com/jhlywa/chess.js') chess.js
-    |  for move validation and check/mate/draw detection. 
-  
-  h3 Why another online chess?
-  p The project may be useful resource for poeple willing to learn Node.js and Socket.IO. Read the source code, fork it, add more functionality and learn something. Besides programming, playing chess is also fun!
+    |  for move validation and check/mate/draw detection.
 
   h3 Why Reti?
-  p The project is named after famous Czechoslovakian chess player Richard Réti. After him is also named a chess opening which begins with the move: 1. Nf3.
+  p The project is named after famous Czechoslovakian chess player Richard Réti. After him is also named a chess opening which begins with the moves: 1. Nf3 d5, 2. d4.
 
   h3 What features chess supports?
   p This is a very lightweight version of chess. You can only play real-time against the human, an AI is not available. Reti Chess doesn't have any timer, the time for a move is unlimited. Although, if you reload the window or disconnect from the game, the game will be cancelled.

+ 0 - 3
views/index.jade

@@ -1,8 +1,5 @@
 extends layout
 
-block ribbon
-  a(href='https://github.com/romanmatiasko/reti-chess', class='fork clearfix')
-
 block content
   script(type='text/javascript', src='/javascripts/start.js')
   h1.knight

+ 3 - 4
views/layout.jade

@@ -21,7 +21,6 @@ html
     //if IE
       script(src='http://html5shiv.googlecode.com/svn/trunk/html5.js')
   body
-    block ribbon
     
     #container_wrapper.clearfix
       #container.clearfix
@@ -29,8 +28,8 @@ html
         
     footer
       #footer.clearfix
-        p.center 2013. Reti Chess is available under 
-          a(href='http://opensource.org/licenses/MIT') the MIT License (MIT)
+        p.center 2013 - 2014. Reti Chess is available under 
+          a(href='http://opensource.org/licenses/MIT')  the MIT License (MIT)
           . Fork me on 
-          a(href='http://github.com/romanmatiasko/reti-chess') Github
+          a(href='http://github.com/romanmatiasko/reti-chess')  Github
           .

+ 13 - 1
views/play.jade

@@ -4,7 +4,9 @@ block content
   header.clearfix
     a.button(href='/') New game
     a.button.resign Resign
-    a.about-in-play(href='/about/') About Reti Chess
+    a.chat
+      img#bubble(src='/images/chat.svg', width='50', height='50')
+      | Chat
 
   script(type='text/javascript')
     $token = '#{token}';
@@ -12,6 +14,16 @@ block content
   audio(id='moveSnd', preload='auto')
     source(src='/sounds/move.mp3')
     source(src='/sounds/move.ogg')
+  audio(id='messageSnd', preload='auto')
+    source(src='/sounds/message.mp3')
+
+  #chat-wrapper
+    h4 Chat
+    a.close x
+    ul#chat
+    span Write your message:
+    form#sendMessage
+      input
 
   #board_moves_wrapper.clearfix
     label(id='sounds_label')