add icons and chatbox

This commit is contained in:
cuom1999 2020-03-18 23:13:55 -06:00
parent 9e95fd21a7
commit cb8eb2689c
43 changed files with 254 additions and 46 deletions

View file

@ -19,17 +19,11 @@ class Message(models.Model):
body = models.TextField(verbose_name=_('body of comment'), max_length=8192) body = models.TextField(verbose_name=_('body of comment'), max_length=8192)
def notify_ws_clients(self): def notify_ws_clients(self):
# inform client that there is a new message
notification = { notification = {
'type': 'recieve_group_message', 'type': 'recieve_group_message',
'message': '{}'.format(self.id) 'message': '{}'.format(self.id)
} }
channel_layer = get_channel_layer() channel_layer = get_channel_layer()
# print("user.id {}".format(self.user.id))
# print("user.id {}".format(self.recipient.id))
async_to_sync(channel_layer.group_send)("{}".format(self.user.id), notification)
async_to_sync(channel_layer.group_send)("{}".format(self.recipient.id), notification)
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
new_message = self.id new_message = self.id

View file

@ -1,11 +1,31 @@
from django.shortcuts import render from django.http import HttpResponseRedirect
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.urls import reverse
from django.utils import timezone
from .models import Message from .models import Message
class ChatView(ListView): class ChatView(ListView):
model = Message model = Message
title = _('Chat Box') context_object_name = 'messages'
template_name = 'chat/chat.html' template_name = 'chat/chat.html'
title = _('Chat Box')
def get_context_data(self, **kwargs):
context = super(ChatView, self).get_context_data(**kwargs)
context['title'] = self.title
return context
def get_queryset(self):
return None
def send(request):
new_message = Message(body=request.POST['message'],
author=request.profile,
time=timezone.now())
new_message.save()
return HttpResponseRedirect(reverse('chat'))

View file

@ -1,4 +1,4 @@
from chat_box.views import ChatView from chat_box.views import ChatView, send
from django.conf import settings from django.conf import settings
from django.conf.urls import include, url from django.conf.urls import include, url
from django.contrib import admin from django.contrib import admin
@ -367,7 +367,10 @@ 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/', ChatView.as_view(), name='chat'), url(r'^chat/', include([
url(r'^$', ChatView.as_view(), name='chat'),
url(r'send$', send, name='send_message')
])),
] ]
favicon_paths = ['apple-touch-icon-180x180.png', 'apple-touch-icon-114x114.png', 'android-chrome-72x72.png', favicon_paths = ['apple-touch-icon-180x180.png', 'apple-touch-icon-114x114.png', 'android-chrome-72x72.png',

58
resources/chatbox.scss Normal file
View file

@ -0,0 +1,58 @@
#chat-log {
padding: 0;
border: 1px solid #ccc;
border-radius: 4px;
height: 20em;
width: 100%;
overflow: hidden;
overflow-wrap: break-word;
overflow-y: scroll;
}
#chat-log li {
list-style-type: none;
margin: 0.5em;
}
#chat-input {
width: 100%;
padding: 0.4em;
color: black;
}
#chat-submit {
margin-top: 1em;
}
.profile-pic {
height: 2.6em;
width: 2.6em;
border-radius: 0.3em;
margin-top: 0.1em;
float: left;
}
.body-message {
padding-left: 3em;
}
.user-time {
margin-bottom: 0.3em;
}
.time {
margin-left: 0.5em;
}
.user {
font-weight: bold;
}
.clear {
clear: both;
}
.message {
word-wrap: break-word;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 797 B

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View file

@ -5,8 +5,7 @@
<square70x70logo src="/mstile-70x70.png"/> <square70x70logo src="/mstile-70x70.png"/>
<square150x150logo src="/mstile-150x150.png"/> <square150x150logo src="/mstile-150x150.png"/>
<square310x310logo src="/mstile-310x310.png"/> <square310x310logo src="/mstile-310x310.png"/>
<wide310x150logo src="/mstile-310x150.png"/> <TileColor>#da532c</TileColor>
<TileColor>#00aba9</TileColor>
</tile> </tile>
</msapplication> </msapplication>
</browserconfig> </browserconfig>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 830 B

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,5 +1,5 @@
{ {
"name": "DMOJ", "name": "LQDOJ",
"icons": [ "icons": [
{ {
"src": "\/android-chrome-36x36.png", "src": "\/android-chrome-36x36.png",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View file

@ -2,18 +2,57 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg" <svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="960.000000pt" height="960.000000pt" viewBox="0 0 960.000000 960.000000" width="223.000000pt" height="223.000000pt" viewBox="0 0 223.000000 223.000000"
preserveAspectRatio="xMidYMid meet"> preserveAspectRatio="xMidYMid meet">
<metadata> <metadata>
Created by potrace 1.11, written by Peter Selinger 2001-2013 Created by potrace 1.11, written by Peter Selinger 2001-2013
</metadata> </metadata>
<g transform="translate(0.000000,960.000000) scale(0.100000,-0.100000)" <g transform="translate(0.000000,223.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none"> fill="#000000" stroke="none">
<path d="M4430 9579 c-1066 -77 -2049 -478 -2810 -1146 -900 -791 -1457 -1877 <path d="M1101 2183 c0 -7 -1 -15 -1 -18 0 -3 -7 -19 -15 -35 -8 -16 -15 -32
-1597 -3115 -25 -218 -25 -828 0 -1048 126 -1122 585 -2089 1362 -2865 773 -15 -35 0 -3 0 -6 -1 -7 0 -2 -2 -10 -4 -18 -2 -8 -18 -67 -35 -130 -17 -63
-774 1763 -1251 2865 -1381 183 -21 681 -30 891 -15 951 68 1836 397 2584 961 -34 -125 -37 -137 -4 -18 -9 -20 -30 -12 -18 7 -22 6 -17 -4 5 -8 2 -8 -9 2
181 137 295 236 474 413 538 531 923 1151 1161 1867 129 386 200 739 231 1150 -13 11 -17 11 -17 1 0 -8 -3 -10 -7 -7 -3 4 -12 2 -20 -4 -7 -6 -13 -8 -13 -4
15 201 6 734 -16 929 -126 1130 -590 2116 -1355 2881 -763 763 -1738 1226 0 4 -7 2 -15 -5 -8 -7 -15 -10 -15 -7 0 3 -15 1 -32 -4 -18 -6 -42 -12 -53
-2855 1355 -166 20 -744 28 -935 14z"/> -14 -11 -3 -32 -7 -47 -11 -16 -3 -28 -10 -28 -15 0 -5 -3 -8 -7 -8 -23 4 -43
-2 -38 -11 3 -5 1 -10 -5 -10 -6 0 -8 -5 -4 -12 5 -7 2 -9 -7 -6 -11 4 -14 -5
-15 -36 -4 -92 -9 -116 -26 -122 -10 -3 -18 -10 -18 -16 0 -6 -3 -8 -6 -5 -4
4 -19 -2 -33 -12 -22 -15 -46 -27 -71 -36 -32 -11 -86 -40 -97 -51 -8 -8 -19
-12 -24 -9 -5 4 -9 -6 -10 -22 -1 -38 -7 -126 -12 -193 -3 -30 -8 -107 -12
-170 -11 -168 -14 -181 -46 -175 -10 2 -19 -1 -19 -7 0 -6 -11 -8 -25 -6 -13
3 -24 2 -23 -1 2 -20 -3 -31 -12 -26 -6 4 -7 -1 -3 -11 4 -12 3 -15 -5 -10 -8
5 -10 2 -6 -9 4 -9 13 -14 20 -11 7 3 16 0 20 -6 4 -7 3 -8 -4 -4 -8 5 -12 0
-12 -13 0 -12 5 -21 12 -21 9 0 9 -3 0 -12 -7 -7 -12 -17 -12 -22 0 -6 5 -4
11 4 8 12 10 9 6 -13 -3 -18 0 -30 8 -34 8 -2 16 -12 19 -20 6 -14 4 -14 -10
-2 -16 13 -16 12 -4 -11 7 -14 18 -28 24 -32 8 -6 6 -11 -4 -18 -9 -6 -10 -10
-3 -10 6 0 13 -10 15 -22 2 -15 13 -24 35 -30 23 -6 37 -19 52 -51 33 -67 199
-247 228 -247 7 0 16 -6 20 -13 4 -7 26 -21 48 -32 22 -11 42 -22 45 -25 7 -7
53 -27 64 -28 5 0 12 -5 15 -11 4 -5 19 -12 35 -15 15 -3 34 -10 41 -16 10 -8
14 -7 18 2 4 10 6 10 6 1 1 -7 6 -13 12 -13 5 0 7 6 3 12 -5 9 -2 9 9 -1 9 -7
17 -10 17 -5 0 5 5 2 10 -6 7 -11 10 -11 10 -2 0 7 5 10 10 7 6 -4 8 -11 5
-16 -4 -5 -1 -9 4 -9 6 0 11 7 11 16 0 8 4 13 10 9 5 -3 7 -13 4 -23 -4 -10
-3 -13 3 -6 8 11 52 12 69 1 5 -3 16 -2 24 3 8 5 22 5 32 -1 12 -6 18 -6 18 1
0 5 5 10 11 10 5 0 7 -6 3 -12 -5 -9 -2 -9 9 1 13 10 17 10 17 1 0 -9 4 -9 17
1 15 12 16 12 8 -1 -7 -13 -6 -13 7 -2 13 10 17 10 21 0 4 -10 6 -10 6 0 1 6
9 12 19 12 10 0 24 6 31 12 11 11 12 10 6 -2 -8 -13 -7 -13 8 -1 9 7 17 11 17
7 0 -3 16 0 35 8 19 8 35 12 35 9 0 -3 7 0 15 7 8 7 15 10 15 6 0 -3 32 10 70
30 39 21 70 41 70 45 0 4 9 11 21 14 24 8 52 29 82 62 11 12 25 19 31 16 6 -3
8 -3 4 2 -4 4 9 22 28 40 18 18 34 37 34 44 0 6 4 11 10 11 5 0 24 25 41 55
17 30 35 55 41 55 5 0 7 4 4 9 -3 5 1 14 9 21 8 7 12 16 9 21 -3 5 -2 9 3 8
24 -4 43 2 37 13 -4 7 -3 8 5 4 12 -8 44 18 34 28 -4 3 -1 6 5 6 6 0 9 7 6 15
-4 8 1 17 10 21 14 5 14 9 4 22 -7 9 -8 13 -2 9 12 -7 38 39 29 53 -3 4 5 10
18 14 18 5 19 8 7 15 -12 9 -12 11 3 17 9 3 14 10 11 15 -3 5 0 9 5 9 6 0 11
6 11 14 0 8 6 17 13 19 7 4 6 6 -4 6 -9 1 -20 8 -23 17 -4 9 -13 14 -21 10 -8
-3 -15 -1 -15 4 0 6 -6 10 -14 10 -17 0 -41 28 -41 49 0 9 -4 22 -8 29 -5 6
-4 12 1 12 5 0 6 17 2 40 -5 25 -4 40 3 40 6 0 6 5 0 13 -5 6 -9 56 -9 109 1
54 -3 98 -7 98 -5 0 -5 5 -1 12 4 7 6 35 5 62 -2 28 -4 64 -5 80 -1 16 -7 31
-14 34 -7 2 -10 8 -7 13 4 5 -1 6 -10 3 -8 -4 -25 0 -38 8 -12 8 -41 20 -64
28 -24 7 -43 17 -43 22 0 4 -3 8 -7 7 -16 -2 -53 14 -53 22 0 5 -3 8 -7 7 -10
-4 -73 23 -74 31 -2 9 -7 42 -14 86 -3 22 -8 51 -11 65 -4 14 -7 44 -8 67 0
22 -4 39 -8 36 -5 -2 -8 0 -8 6 0 10 -93 57 -130 65 -3 1 -15 7 -27 14 -13 7
-23 9 -23 5 0 -4 -4 -3 -8 2 -11 16 -102 56 -113 50 -5 -4 -12 1 -15 10 -5 13
-9 14 -14 4 -7 -10 -11 -9 -22 2 -8 8 -15 17 -16 22 -1 4 -3 9 -3 12 -1 3 -3
10 -4 15 -1 6 -4 12 -5 15 -1 3 -3 8 -4 13 -18 83 -32 132 -37 132 -4 0 -10 8
-12 18 -3 9 -5 11 -6 5z"/>
</g> </g>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -12,3 +12,4 @@
@import "submission"; @import "submission";
@import "contest"; @import "contest";
@import "misc"; @import "misc";
@import "chatbox";

View file

@ -1,3 +1,4 @@
{% if request.user.is_authenticated %}
{% extends "base.html" %} {% extends "base.html" %}
{% block js_media %} {% block js_media %}
@ -9,34 +10,127 @@
<script type="text/javascript"> <script type="text/javascript">
$(function() { $(function() {
chatSocket.onmessage = function(e) { chatSocket.onmessage = function(e) {
var data = JSON.parse(e.data); let data = JSON.parse(e.data)
var message = data['message']; data = data['message']
$('#chat-log').append(message + '\n'); console.log(data)
loadMessage(data['content'],
data['sender'],
data['time'],
data['image'])
}; };
function loadMessage(content, user, time, image) {
li = `<li>
<img src="${image}" class="profile-pic">
<div class="body-message">
<div class="user-time">
<a href="#" class="user">
${user}
</a>
<span class="time">${time}</span>
</div>
<span class="message">
<span>${content}</span>
</span>
</div>
<div class="clear"></div>
</li>`
ul = $('#chat-log')
ul.append(li)
$('#chat-log').scrollTop($('#chat-log')[0].scrollHeight);
}
$("#chat-submit").click(function() {
if ($("#chat-input").val().trim()) {
let content = $('#chat-input').val().trim();
let img = '{{ gravatar(request.user, 32) }}'
message = {
'content': content,
'image': img,
'time': calcTime(6), // HCM City
'sender': '{{ request.user }}'
}
chatSocket.send(JSON.stringify({
'message': message,
}))
// $.post('/chat/send', message)
$('#chat-input').val('').focus();
}
});
function calcTime(offset) {
utc = new Date().getTime()
nd = new Date(utc + (3600000*offset));
return nd.toLocaleString();
}
chatSocket.onclose = function(e) { chatSocket.onclose = function(e) {
console.error('Chat socket closed unexpectedly'); console.error('Chat socket closed unexpectedly');
}; };
$('#chat-message-input').focus();
$('#chat-message-input').keyup(function(e) { $("#chat-log").change(function() {
if (e.keyCode === 13) { // enter, return $('#chat-log').scrollTop($('#chat-log')[0].scrollHeight);
$('#chat-message-submit').click(); });
$('#chat-input').focus();
$('#chat-input').keydown(function(e) {
if (e.keyCode === 13) {
if (e.ctrlKey || e.shiftKey) {
var val = this.value;
if (typeof this.selectionStart == "number" && typeof this.selectionEnd == "number") {
var start = this.selectionStart;
this.value = val.slice(0, start) + "\n" + val.slice(this.selectionEnd);
this.selectionStart = this.selectionEnd = start + 1;
} else if (document.selection && document.selection.createRange) {
this.focus();
var range = document.selection.createRange();
range.text = "\r\n";
range.collapse(false);
range.select();
} }
}
else {
e.preventDefault();
$('#chat-submit').click();
}
return false
}
return true
}); });
$("#chat-message-submit").click(function() {
var message = "{{ request.user }}: " + $('input#chat-message-input').val();
chatSocket.send(JSON.stringify({
'message': message,
}));
$('input#chat-message-input').val('');
});
}); });
</script> </script>
{% endblock js_media %} {% endblock js_media %}
{% block body %} {% block body %}
<div> {% csrf_token %}
<textarea disabled id="chat-log" rows="20" style="width: 100%"></textarea><br/> <div id="chat-area">
<input id="chat-message-input" type="text" style="width: 100%"/><br/> <ul id="chat-log">
<li>
<img src="https://via.placeholder.com/150" class="profile-pic">
<div class="body-message">
<div class="user-time">
<a href="#" class="user">
cuom1999
</a>
<span class="time">12:00:00</span>
</div> </div>
<button id="chat-message-submit" style="margin-top: 1em"> Send </button> <span class="message">
<span>Its possible that a request can come in via POST with an empty POST dictionary if, say, a form is requested via the POST HTTP method but does not include form data. Therefore, you shouldnt use if request.POST to check for use of the POST method; instead, use if request.method == "POST" (see HttpRequest.method).</span>
</span>
</div>
<div class="clear"></div>
</li>
</ul>
{{_('Your message')}}
<textarea rows="6" id="chat-input"></textarea>
</div>
<button id="chat-submit"> Send </button>
{% endblock body %} {% endblock body %}
{% endif %}