almost chatbox
This commit is contained in:
parent
dd34f474a5
commit
92d94af520
7 changed files with 107 additions and 40 deletions
|
@ -2,6 +2,9 @@ import json
|
||||||
from channels.generic.websocket import AsyncWebsocketConsumer
|
from channels.generic.websocket import AsyncWebsocketConsumer
|
||||||
from .models import Message
|
from .models import Message
|
||||||
from .views import format_time
|
from .views import format_time
|
||||||
|
from django.urls import reverse
|
||||||
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
|
||||||
|
|
||||||
from judge.models.profile import Profile
|
from judge.models.profile import Profile
|
||||||
|
|
||||||
|
@ -14,7 +17,7 @@ class ChatConsumer(AsyncWebsocketConsumer):
|
||||||
# Join room group
|
# Join room group
|
||||||
await self.channel_layer.group_add(
|
await self.channel_layer.group_add(
|
||||||
self.room_group_name,
|
self.room_group_name,
|
||||||
self.channel_name
|
self.channel_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
await self.accept()
|
await self.accept()
|
||||||
|
@ -23,7 +26,7 @@ class ChatConsumer(AsyncWebsocketConsumer):
|
||||||
# Leave room group
|
# Leave room group
|
||||||
await self.channel_layer.group_discard(
|
await self.channel_layer.group_discard(
|
||||||
self.room_group_name,
|
self.room_group_name,
|
||||||
self.channel_name
|
self.channel_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Receive message from WebSocket
|
# Receive message from WebSocket
|
||||||
|
@ -58,6 +61,5 @@ def save_data_and_get_time(message):
|
||||||
.get(id=message['author_id']),
|
.get(id=message['author_id']),
|
||||||
)
|
)
|
||||||
new_message.save()
|
new_message.save()
|
||||||
|
HttpResponseRedirect(reverse('chat'))
|
||||||
return new_message.time
|
return new_message.time
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,19 +1,44 @@
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
from django.views.generic import ListView
|
from django.views.generic import ListView
|
||||||
|
from django.http import HttpResponse, HttpResponseRedirect
|
||||||
|
from django.shortcuts import render
|
||||||
|
from django.core.paginator import Paginator
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
|
from judge.jinja2.gravatar import gravatar
|
||||||
from .models import Message
|
from .models import Message
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
def format_time(time):
|
def format_time(time):
|
||||||
return time.strftime('%H:%M %p %d-%m-%Y')
|
return time.strftime('%H:%M %p %d-%m-%Y')
|
||||||
|
|
||||||
|
|
||||||
|
def format_messages(messages):
|
||||||
|
msg_list = [{
|
||||||
|
'time': format_time(msg.time),
|
||||||
|
'author': str(msg.author),
|
||||||
|
'body': msg.body,
|
||||||
|
'image': gravatar(msg.author, 32),
|
||||||
|
} for msg in messages]
|
||||||
|
return json.dumps(msg_list)
|
||||||
|
|
||||||
|
|
||||||
class ChatView(ListView):
|
class ChatView(ListView):
|
||||||
model = Message
|
model = Message
|
||||||
context_object_name = 'message'
|
context_object_name = 'message'
|
||||||
template_name = 'chat/chat.html'
|
template_name = 'chat/chat.html'
|
||||||
title = _('Chat Box')
|
title = _('Chat Box')
|
||||||
paginate_by = 50
|
paginate_by = 50
|
||||||
|
paginator = Paginator(Message.objects.all(), paginate_by)
|
||||||
|
|
||||||
|
def get(self, request, *args, **kwargs):
|
||||||
|
page = request.GET.get('page')
|
||||||
|
if (page == None):
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
cur_page = self.paginator.get_page(page)
|
||||||
|
return HttpResponse(format_messages(cur_page.object_list))
|
||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
|
|
@ -4,7 +4,7 @@ from django.conf.urls import include, url
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.auth import views as auth_views
|
from django.contrib.auth import views as auth_views
|
||||||
from django.contrib.sitemaps.views import sitemap
|
from django.contrib.sitemaps.views import sitemap
|
||||||
from django.http import Http404, HttpResponsePermanentRedirect
|
from django.http import Http404, HttpResponsePermanentRedirect, HttpResponseRedirect
|
||||||
from django.templatetags.static import static
|
from django.templatetags.static import static
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.functional import lazystr
|
from django.utils.functional import lazystr
|
||||||
|
@ -369,7 +369,9 @@ urlpatterns = [
|
||||||
url(r'^custom_checker_sample/', about.custom_checker_sample, name='custom_checker_sample'),
|
url(r'^custom_checker_sample/', about.custom_checker_sample, name='custom_checker_sample'),
|
||||||
|
|
||||||
url(r'^chat/', include([
|
url(r'^chat/', include([
|
||||||
url(r'^$', login_required(ChatView.as_view()), name='chat'),
|
url(r'^$',
|
||||||
|
login_required(ChatView.as_view()),
|
||||||
|
name='chat'),
|
||||||
|
|
||||||
])),
|
])),
|
||||||
]
|
]
|
||||||
|
|
|
@ -219,11 +219,11 @@ header {
|
||||||
|
|
||||||
#nav-shadow {
|
#nav-shadow {
|
||||||
height: 2px;
|
height: 2px;
|
||||||
background: linear-gradient(#63c8f9, transparent);
|
background: linear-gradient(#7dc7ff, transparent);
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav-container {
|
#nav-container {
|
||||||
background: linear-gradient(#c1e9fd, #63c8f9);
|
background: #7dc7ff;
|
||||||
|
|
||||||
// opacity: 0.77;
|
// opacity: 0.77;
|
||||||
// filter: alpha(opacity=77)
|
// filter: alpha(opacity=77)
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loader {
|
#loader {
|
||||||
display: block;
|
display: block;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
|
@ -16,6 +17,7 @@
|
||||||
|
|
||||||
#chat-log {
|
#chat-log {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
padding-top: 2em;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,8 +63,9 @@
|
||||||
.clear {
|
.clear {
|
||||||
clear: both;
|
clear: both;
|
||||||
}
|
}
|
||||||
.message {
|
.content-message {
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
|
white-space: pre-line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -305,8 +305,8 @@ ul.pagination {
|
||||||
.active-page > {
|
.active-page > {
|
||||||
a {
|
a {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
color: #FFF;
|
color: black;
|
||||||
background-color: $highlight_blue;
|
background-color: #7dc7ff;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(function() {
|
$(function() {
|
||||||
|
let currentPage = 1;
|
||||||
|
|
||||||
$('#loader').hide();
|
$('#loader').hide();
|
||||||
|
|
||||||
chatSocket.onmessage = function(e) {
|
chatSocket.onmessage = function(e) {
|
||||||
|
@ -15,52 +17,86 @@
|
||||||
loadMessage(data['body'],
|
loadMessage(data['body'],
|
||||||
data['author'],
|
data['author'],
|
||||||
data['time'],
|
data['time'],
|
||||||
data['image'])
|
data['image'],
|
||||||
|
true)
|
||||||
|
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
||||||
};
|
};
|
||||||
|
|
||||||
function loadMessage(content, user, time, image) {
|
function encodeHTML(content) {
|
||||||
li = `<li class="infinite-item">
|
return content.replace(/[\u00A0-\u9999<>\&]/gim, function(i) {
|
||||||
|
return '&#'+i.charCodeAt(0)+';';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadMessage(content, user, time, image, isNew) {
|
||||||
|
if (isNew) content = encodeHTML(content)
|
||||||
|
li = `<li class="message">
|
||||||
<img src="${image}" class="profile-pic">
|
<img src="${image}" class="profile-pic">
|
||||||
<div class="body-message">
|
<div class="body-message">
|
||||||
<div class="user-time">
|
<div class="user-time">
|
||||||
<a href="#" class="user">
|
<a href="{{ url('user_page') }}/${user}" class="user">
|
||||||
${user}
|
${user}
|
||||||
</a>
|
</a>
|
||||||
<span class="time">${time}</span>
|
<span class="time">${time}</span>
|
||||||
</div>
|
</div>
|
||||||
<span class="message">
|
<span class="content-message">${content} </span>
|
||||||
<span>${content}</span>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</li>`
|
</li>`
|
||||||
ul = $('#chat-log')
|
ul = $('#chat-log')
|
||||||
|
if (isNew) {
|
||||||
ul.append(li)
|
ul.append(li)
|
||||||
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
}
|
||||||
|
else {
|
||||||
|
ul.prepend(li)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(function init_chatlog() {
|
(function init_chatlog() {
|
||||||
ul = $('#chat-log')
|
ul = $('#chat-log')
|
||||||
{% for msg in message|reverse %}
|
{% for msg in message %}
|
||||||
loadMessage('{{msg.body}}', '{{msg.author}}', '{{msg.time}}', '{{gravatar(msg.author, 32)}}')
|
loadMessage(`{{msg.body}}`, `{{msg.author}}`, `{{msg.time}}`, `{{gravatar(msg.author, 32)}}`)
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
||||||
})()
|
})()
|
||||||
|
|
||||||
$('#chat-box').scroll(function() {
|
function scrollTopOfBottom(container) {
|
||||||
if ($('#chat-box').scrollTop() == 0) {
|
return container[0].scrollHeight - container.innerHeight()
|
||||||
console.log('Hi')
|
}
|
||||||
$('#loader').show()
|
|
||||||
|
function scrollContainer(container, loader) {
|
||||||
|
container.scroll(function() {
|
||||||
|
if (container.scrollTop() == 0) {
|
||||||
|
if (currentPage < {{paginator.num_pages}}) {
|
||||||
|
currentPage++;
|
||||||
|
loader.show();
|
||||||
|
$.ajax({
|
||||||
|
url: `{{request.path}}?page=${currentPage}`,
|
||||||
|
success: function(data) {
|
||||||
|
let lastMsg = $('.message:first')
|
||||||
|
let lastMsgPos = scrollTopOfBottom(container)
|
||||||
|
|
||||||
|
data = JSON.parse(data)
|
||||||
|
setTimeout( () => {
|
||||||
|
for (msg of data) {
|
||||||
|
loadMessage(msg.body, msg.author, msg.time, msg.image)
|
||||||
|
}
|
||||||
|
|
||||||
|
loader.hide()
|
||||||
|
|
||||||
|
// scroll to last msg
|
||||||
|
container.scrollTop(
|
||||||
|
scrollTopOfBottom(container) - lastMsgPos
|
||||||
|
)
|
||||||
|
}, 500)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// var infinite = new Waypoint.Infinite({
|
}
|
||||||
// element: $('.infinite-container')[0],
|
}
|
||||||
// onBeforePageLoad: function () {
|
})}
|
||||||
// $('.loading').show();
|
|
||||||
// },
|
scrollContainer($('#chat-box'), $('#loader'))
|
||||||
// onAfterPageLoad: function ($items) {
|
|
||||||
// $('.loading').hide();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
$("#chat-submit").click(function() {
|
$("#chat-submit").click(function() {
|
||||||
if ($("#chat-input").val().trim()) {
|
if ($("#chat-input").val().trim()) {
|
||||||
|
@ -74,7 +110,6 @@
|
||||||
'author_id': {{request.profile.id}},
|
'author_id': {{request.profile.id}},
|
||||||
}
|
}
|
||||||
|
|
||||||
// $.post("send/", message)
|
|
||||||
chatSocket.send(JSON.stringify({
|
chatSocket.send(JSON.stringify({
|
||||||
'message': message
|
'message': message
|
||||||
}));
|
}));
|
||||||
|
@ -126,7 +161,7 @@
|
||||||
<div id="chat-area">
|
<div id="chat-area">
|
||||||
<div id="chat-box">
|
<div id="chat-box">
|
||||||
<img src="http://opengraphicdesign.com/wp-content/uploads/2009/01/loader64.gif" id="loader">
|
<img src="http://opengraphicdesign.com/wp-content/uploads/2009/01/loader64.gif" id="loader">
|
||||||
<ul id="chat-log" class="infinite-container waypoint">
|
<ul id="chat-log">
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{{_('Your message')}}
|
{{_('Your message')}}
|
||||||
|
|
Loading…
Reference in a new issue