Browse Source

Add angularized chatroom

Thomas Dy 11 years ago
parent
commit
159fecf9b0

+ 21 - 6
app/controllers/Application.scala

@@ -12,14 +12,14 @@ import akka.actor._
 import scala.concurrent.duration._
 
 object Application extends Controller {
-  
+
   /**
    * Just display the home page.
    */
   def index = Action { implicit request =>
-    Ok(views.html.index())
+    Ok(views.html.chatRoomNg())
   }
-  
+
   /**
    * Display the chat room page.
    */
@@ -36,14 +36,29 @@ object Application extends Controller {
   def chatRoomJs(username: String) = Action { implicit request =>
     Ok(views.js.chatRoom(username))
   }
-  
+
   /**
    * Handles the chat websocket.
    */
   def chat(username: String) = WebSocket.async[JsValue] { request  =>
 
     ChatRoom.join(username)
-    
+
+  }
+
+  val routeCache = {
+    import routes._
+    val jsRoutesClass = classOf[routes.javascript]
+    val controllers = jsRoutesClass.getFields().map(_.get(null))
+    controllers.flatMap { controller =>
+      controller.getClass().getDeclaredMethods().map { action =>
+        action.invoke(controller).asInstanceOf[play.core.Router.JavascriptReverseRoute]
   }
-  
+      }
+    }
+
+  def javascriptRoutes = Action { implicit request =>
+    Ok(Routes.javascriptRouter("jsRoutes")(routeCache:_*)).as("text/javascript")
+  }
+
 }

+ 49 - 0
app/views/chatRoomNg.scala.html

@@ -0,0 +1,49 @@
+@()
+<!DOCTYPE html>
+
+<html ng-app="taboo">
+    <head>
+        <title>Websocket Chat-Room</title>
+        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/bootstrap.css")">
+        <link rel="stylesheet" media="screen" href="@routes.Assets.at("stylesheets/main.css")">
+        <link rel="shortcut icon" type="image/png" href="@routes.Assets.at("images/favicon.png")">
+    </head>
+    <body>
+
+        <div class="topbar">
+            <div class="fill">
+                <div class="container" ng-controller="LoginCtrl">
+                    <a class="brand">Websocket Chat-Room</a>
+
+                    <p class="pull-right" ng-show="service.isConnected()">
+                        Logged in as {{service.username}} —
+                        <a ng-click="service.disconnect()">Disconnect</a>
+                    </p>
+
+                    <form class="pull-right" ng-hide="service.isConnected()">
+                        <input id="username" name="username" class="input-small" type="text" ng-model="username" placeholder="Username">
+                        <button class="btn" type="submit" ng-click="service.connect(username); username=''">Sign in</button>
+                    </form>
+
+                </div>
+            </div>
+        </div>
+
+        <div class="container" ng-controller="ViewCtrl">
+
+            <div class="content" ng-include="partial('chatRoom')">
+            </div>
+
+            <footer>
+                <p> </p>
+            </footer>
+
+        </div>
+
+        <script src="@routes.Application.javascriptRoutes" type="text/javascript"></script>
+        <script src="@routes.Assets.at("components/jquery/jquery.min.js")" type="text/javascript"></script>
+        <script src="@routes.Assets.at("components/angular/angular.min.js")" type="text/javascript"></script>
+        <script src="@routes.Assets.at("javascripts/chatRoomNg.js")" type="text/javascript"></script>
+
+    </body>
+</html>

+ 1 - 0
conf/routes

@@ -7,6 +7,7 @@ GET     /                                controllers.Application.index
 GET     /room                            controllers.Application.chatRoom(username: Option[String])
 GET     /room/chat                       controllers.Application.chat(username)
 GET     /assets/javascripts/chatroom.js  controllers.Application.chatRoomJs(username: String)
+GET     /jsRoutes                        controllers.Application.javascriptRoutes
 
 # Map static resources from the /public folder to the /assets URL path
 GET     /assets/*file                    controllers.Assets.at(path="/public", file)

+ 73 - 0
public/javascripts/chatRoomNg.js

@@ -0,0 +1,73 @@
+angular.module('tabooServices', [])
+.factory('connectionService', function($rootScope) {
+  var WS = window['MozWebSocket'] ? MozWebSocket : WebSocket;
+  var chatSocket = null;
+
+  var service = {
+    username: '',
+    messages: [],
+    members: [],
+    error: null,
+    isConnected: function() {
+      return this.username != '';
+    },
+  };
+
+  service.connect = function(username) {
+    chatSocket = new WS(jsRoutes.controllers.Application.chat(username).webSocketURL());
+    chatSocket.onmessage = onEvent;
+    service.username = username;
+  }
+
+  service.disconnect = function() {
+    service.username = '';
+    service.messages = [];
+    service.members = [];
+    chatSocket.close();
+    chatSocket = null;
+  }
+
+  service.send = function(message) {
+    chatSocket.send(JSON.stringify({text: message}));
+  }
+
+  function onEvent(event) {
+    var message = JSON.parse(event.data);
+    if(message.error) {
+      service.error = message;
+    }
+    else {
+      service.messages.push(message);
+      service.members = message.members;
+    }
+    $rootScope.$apply();
+  }
+
+  return service;
+});
+
+angular.module('taboo', ['tabooServices']);
+
+function partial(template) {
+  return jsRoutes.controllers.Assets.at('partials/'+template+'.html').url;
+}
+
+function ViewCtrl($scope) {
+  $scope.partial = partial;
+}
+
+function LoginCtrl($scope, connectionService) {
+  $scope.service = connectionService;
+}
+
+function ChatCtrl($scope, connectionService) {
+  $scope.service = connectionService;
+
+  $scope.onType = function(event) {
+    if(event.keyCode == 13) {
+      connectionService.send($scope.text);
+      $scope.text = '';
+      event.originalEvent.preventDefault();
+    }
+  }
+}

+ 29 - 0
public/partials/chatRoom.html

@@ -0,0 +1,29 @@
+<div ng-controller="ChatCtrl">
+  <div class="page-header">
+    <h1>Welcome to the chat room <small>You are chatting as {{service.username}}</small></h1>
+  </div>
+
+  <div id="onError" class="alert-message error">
+    <p>
+    <strong>Oops!</strong> <span></span>
+    </p>
+  </div>
+
+  <div class="row">
+    <div class="span10" id="main">
+      <div id="messages">
+        <div class="message {{message.kind}} {{message.user == service.username ? 'me' : ''}}" ng-repeat="message in service.messages">
+          <span>{{message.user}}</span>
+          <p>{{message.message}}</p>
+        </div>
+      </div>
+      <textarea ng-model="text" id="talk" ng-keypress="onType($event)"></textarea>
+    </div>
+    <div class="span4">
+      <h2>Members</h2>
+      <ul id="members">
+        <li ng-repeat="member in service.members">{{member}}</li>
+      </ul>
+    </div>
+  </div>
+</div>