Simplify project structure
- harmonize module and directory names - optimize Gradle settings - remove unused Grails sample Resolves: #1447
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
#server.servlet.session.timeout=1m
|
||||
spring.h2.console.enabled=true
|
||||
@@ -0,0 +1,5 @@
|
||||
insert into user(id,email,password,first_name,last_name) values (0,'rob','password','Rob','Winch');
|
||||
insert into user(id,email,password,first_name,last_name) values (1,'luke','password','Luke','Taylor');
|
||||
insert into user(id,email,password,first_name,last_name) values (2,'eve','password','Luke','Taylor');
|
||||
|
||||
update user set password = '$2a$10$FBAKClV1zBIOOC9XMXf3AO8RoGXYVYsfvUdoLxGkd/BnXEn4tqT3u';
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,152 @@
|
||||
|
||||
function ApplicationModel(stompClient) {
|
||||
var self = this;
|
||||
|
||||
self.friends = ko.observableArray();
|
||||
self.username = ko.observable();
|
||||
self.conversation = ko.observable(new ImConversationModel(stompClient,this.username));
|
||||
self.notifications = ko.observableArray();
|
||||
self.csrfToken = ko.computed(function() {
|
||||
return JSON.parse($.ajax({
|
||||
type: 'GET',
|
||||
url: 'csrf',
|
||||
dataType: 'json',
|
||||
success: function() { },
|
||||
data: {},
|
||||
async: false
|
||||
}).responseText);
|
||||
}, this);
|
||||
|
||||
self.connect = function() {
|
||||
var headers = {};
|
||||
var csrf = self.csrfToken();
|
||||
headers[csrf.headerName] = csrf.token;
|
||||
stompClient.connect(headers, function(frame) {
|
||||
|
||||
console.log('Connected ' + frame);
|
||||
self.username(frame.headers['user-name']);
|
||||
|
||||
// self.friendSignin({"username": "luke"});
|
||||
|
||||
stompClient.subscribe("/user/queue/errors", function(message) {
|
||||
self.pushNotification("Error " + message.body);
|
||||
});
|
||||
stompClient.subscribe("/app/users", function(message) {
|
||||
var friends = JSON.parse(message.body);
|
||||
|
||||
for(var i=0;i<friends.length;i++) {
|
||||
self.friendSignin({"username": friends[i]});
|
||||
}
|
||||
});
|
||||
stompClient.subscribe("/topic/friends/signin", function(message) {
|
||||
var friends = JSON.parse(message.body);
|
||||
|
||||
for(var i=0;i<friends.length;i++) {
|
||||
self.friendSignin(new ImFriend({"username": friends[i]}));
|
||||
}
|
||||
});
|
||||
stompClient.subscribe("/topic/friends/signout", function(message) {
|
||||
var friends = JSON.parse(message.body);
|
||||
|
||||
for(var i=0;i<friends.length;i++) {
|
||||
self.friendSignout(new ImFriend({"username": friends[i]}));
|
||||
}
|
||||
});
|
||||
stompClient.subscribe("/user/queue/messages", function(message) {
|
||||
self.conversation().receiveMessage(JSON.parse(message.body));
|
||||
});
|
||||
}, function(error) {
|
||||
self.pushNotification(error)
|
||||
console.log("STOMP protocol error " + error);
|
||||
});
|
||||
}
|
||||
|
||||
self.pushNotification = function(text) {
|
||||
self.notifications.push({notification: text});
|
||||
if (self.notifications().length > 5) {
|
||||
self.notifications.shift();
|
||||
}
|
||||
}
|
||||
|
||||
self.logout = function() {
|
||||
stompClient.disconnect();
|
||||
window.location.href = "../logout.html";
|
||||
}
|
||||
|
||||
self.friendSignin = function(friend) {
|
||||
self.friends.push(friend);
|
||||
}
|
||||
|
||||
self.friendSignout = function(friend) {
|
||||
var r = self.friends.remove(
|
||||
function(item) {
|
||||
item.username == friend.username
|
||||
}
|
||||
);
|
||||
self.friends(r);
|
||||
}
|
||||
}
|
||||
|
||||
function ImFriend(data) {
|
||||
var self = this;
|
||||
|
||||
self.username = data.username;
|
||||
}
|
||||
|
||||
function ImConversationModel(stompClient,from) {
|
||||
var self = this;
|
||||
self.stompClient = stompClient;
|
||||
self.from = from;
|
||||
self.to = ko.observable(new ImFriend('null'));
|
||||
self.draft = ko.observable('')
|
||||
|
||||
self.messages = ko.observableArray();
|
||||
|
||||
self.receiveMessage = function(message) {
|
||||
var elem = $('#chat');
|
||||
var isFromSelf = self.from() == message.from;
|
||||
var isFromTo = self.to().username == message.from;
|
||||
if(!(isFromTo || isFromSelf)) {
|
||||
self.chat(new ImFriend({"username":message.from}))
|
||||
}
|
||||
|
||||
var atBottom = (elem[0].scrollHeight - elem.scrollTop() == elem.outerHeight());
|
||||
|
||||
self.messages.push(new ImModel(message));
|
||||
|
||||
if (atBottom)
|
||||
elem.scrollTop(elem[0].scrollHeight);
|
||||
};
|
||||
|
||||
self.chat = function(to) {
|
||||
self.to(to);
|
||||
self.draft('');
|
||||
self.messages.removeAll()
|
||||
$('#trade-dialog').modal();
|
||||
}
|
||||
|
||||
self.send = function() {
|
||||
var data = {
|
||||
"created" : new Date(),
|
||||
"from" : self.from(),
|
||||
"to" : self.to().username,
|
||||
"message" : self.draft()
|
||||
};
|
||||
var destination = "/app/im"; // /queue/messages-user1
|
||||
stompClient.send(destination, {}, JSON.stringify(data));
|
||||
self.draft('');
|
||||
}
|
||||
};
|
||||
|
||||
function ImModel(data) {
|
||||
var self = this;
|
||||
|
||||
self.created = new Date(data.created);
|
||||
self.to = data.to;
|
||||
self.message = data.message;
|
||||
self.from = data.from;
|
||||
self.messageFormatted = ko.computed(function() {
|
||||
return self.created.getHours() + ":" + self.created.getMinutes() + ":" + self.created.getSeconds() + " - " + self.from + " - " + self.message;
|
||||
})
|
||||
};
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
<html xmlns:th="https://www.thymeleaf.org" xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect" layout:decorate="~{layout}">
|
||||
<head>
|
||||
<title>View All</title>
|
||||
</head>
|
||||
<body>
|
||||
<div layout:fragment="content">
|
||||
<div class="container">
|
||||
<div id="heading" class="masthead">
|
||||
<h3 class="muted">Chat Application</h3>
|
||||
</div>
|
||||
<div id="main-content">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody data-bind="foreach: friends()">
|
||||
<tr>
|
||||
<td data-bind="text: username"></td>
|
||||
<td class="trade-buttons">
|
||||
<button class="btn btn-primary" data-bind="click: $root.conversation().chat">Chat</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div id="trade-dialog" class="modal hide fade" tabindex="-1">
|
||||
<div class="modal-body">
|
||||
<div>Chat with <span data-bind="text: conversation().to().username"></span></div>
|
||||
<div id="chat" style="height: 5em;max-height: 200px;overflow:scroll" data-bind="foreach: conversation().messages()">
|
||||
<div data-bind="text: messageFormatted"></div>
|
||||
</div>
|
||||
<form class="form-horizontal" data-bind="submit: conversation().send">
|
||||
<textarea data-bind="value: conversation().draft"></textarea>
|
||||
<button class="btn btn-primary" type="submit">Send</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="alert alert-warning">
|
||||
<h5>Notifications</h5>
|
||||
<ul data-bind="foreach: notifications">
|
||||
<li data-bind="text: notification"></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 3rd party -->
|
||||
<script th:src="@{/webjars/jquery/jquery.min.js}" src="/webjars/jquery/jquery.min.js"></script>
|
||||
<script th:src="@{/webjars/bootstrap/js/bootstrap.min.js}" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
|
||||
<script th:src="@{/webjars/knockout/knockout.js}" src="/webjars/knockout/knockout.js"></script>
|
||||
<script th:src="@{/webjars/sockjs-client/sockjs.min.js}" src="/webjars/sockjs-client/sockjs.min.js"></script>
|
||||
<script th:src="@{/webjars/stomp-websocket/stomp.min.js}" src="/webjars/stomp-websocket/stomp.min.js"></script>
|
||||
|
||||
<!-- application -->
|
||||
<script th:src="@{/js/message.js}" src="../static/js/message.js"></script>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var socket = new SockJS('/messages');
|
||||
var stompClient = Stomp.over(socket);
|
||||
|
||||
var appModel = new ApplicationModel(stompClient);
|
||||
ko.applyBindings(appModel);
|
||||
|
||||
appModel.connect();
|
||||
|
||||
})();
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,124 @@
|
||||
<!DOCTYPE html SYSTEM "https://www.thymeleaf.org/dtd/xhtml1-strict-thymeleaf-spring4-3.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
xmlns:th="https://www.thymeleaf.org"
|
||||
xmlns:layout="https://github.com/ultraq/thymeleaf-layout-dialect">
|
||||
<head>
|
||||
<title layout:title-pattern="$LAYOUT_TITLE - $CONTENT_TITLE">Spring Session Sample</title>
|
||||
<link rel="icon" type="image/x-icon" th:href="@{/favicon.ico}" href="../static/favicon.ico"/>
|
||||
<link th:href="@{/webjars/bootstrap/css/bootstrap.min.css}" href="/webjars/bootstrap/css/bootstrap.min.css" rel="stylesheet"></link>
|
||||
<style type="text/css">
|
||||
/* Sticky footer styles
|
||||
-------------------------------------------------- */
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
/* The html and body elements cannot have any padding or margin. */
|
||||
}
|
||||
|
||||
/* Wrapper for page content to push down footer */
|
||||
#wrap {
|
||||
min-height: 100%;
|
||||
height: auto !important;
|
||||
height: 100%;
|
||||
/* Negative indent footer by it's height */
|
||||
margin: 0 auto -60px;
|
||||
}
|
||||
|
||||
/* Set the fixed height of the footer here */
|
||||
#push,
|
||||
#footer {
|
||||
height: 60px;
|
||||
}
|
||||
#footer {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
/* Lastly, apply responsive CSS fixes as necessary */
|
||||
@media (max-width: 767px) {
|
||||
#footer {
|
||||
margin-left: -20px;
|
||||
margin-right: -20px;
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Custom page CSS
|
||||
-------------------------------------------------- */
|
||||
/* Not required for template or sticky footer method. */
|
||||
|
||||
.container {
|
||||
width: auto;
|
||||
max-width: 680px;
|
||||
}
|
||||
.container .credit {
|
||||
margin: 20px 0;
|
||||
text-align: center;
|
||||
}
|
||||
a {
|
||||
color: green;
|
||||
}
|
||||
.navbar-form {
|
||||
margin-left: 1em;
|
||||
}
|
||||
</style>
|
||||
<link th:href="@{/webjars/bootstrap/css/bootstrap-responsive.min.css}" href="/webjars/bootstrap/css/bootstrap-responsive.min.css" rel="stylesheet"></link>
|
||||
|
||||
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
|
||||
<!--[if lt IE 9]>
|
||||
<script th:src="@{/webjars/html5shiv/html5shiv.min.js}" src="/webjars/html5shiv/html5shiv.min.js"></script>
|
||||
<![endif]-->
|
||||
</head>
|
||||
|
||||
|
||||
<body>
|
||||
<div id="wrap">
|
||||
<div class="navbar navbar-inverse navbar-static-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<a class="brand" th:href="@{/}"><img th:src="@{/images/logo.png}" alt="Spring Security Sample"/></a>
|
||||
|
||||
<div class="nav-collapse collapse"
|
||||
th:with="currentUser=${#httpServletRequest.userPrincipal?.principal}">
|
||||
<div th:if="${currentUser != null}">
|
||||
<form class="navbar-form pull-right" th:action="@{/logout}" method="post">
|
||||
<input type="submit" value="Log out" />
|
||||
</form>
|
||||
<p id="un" class="navbar-text pull-right" th:text="${currentUser.username}">
|
||||
sample_user
|
||||
</p>
|
||||
</div>
|
||||
<ul class="nav">
|
||||
<li><a th:href="@{/}">IM</a></li>
|
||||
<li><a th:href="@{/h2-console/}">H2</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Begin page content -->
|
||||
<div class="container">
|
||||
<div class="alert alert-success"
|
||||
th:if="${globalMessage}"
|
||||
th:text="${globalMessage}">
|
||||
Some Success message
|
||||
</div>
|
||||
<div layout:fragment="content">
|
||||
Fake content
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="push"><!-- --></div>
|
||||
</div>
|
||||
|
||||
<div id="footer">
|
||||
<div class="container">
|
||||
<p class="muted credit">Visit the <a href="https://projects.spring.io/spring-session/">Spring Session</a> site for more <a href="https://github.com/spring-projects/spring-session/tree/master/samples">samples</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user