add icons and chatbox
|
@ -19,17 +19,11 @@ class Message(models.Model):
|
|||
body = models.TextField(verbose_name=_('body of comment'), max_length=8192)
|
||||
|
||||
def notify_ws_clients(self):
|
||||
# inform client that there is a new message
|
||||
notification = {
|
||||
'type': 'recieve_group_message',
|
||||
'message': '{}'.format(self.id)
|
||||
}
|
||||
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):
|
||||
new_message = self.id
|
||||
|
|
|
@ -1,11 +1,31 @@
|
|||
from django.shortcuts import render
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
from .models import Message
|
||||
|
||||
|
||||
class ChatView(ListView):
|
||||
model = Message
|
||||
title = _('Chat Box')
|
||||
context_object_name = 'messages'
|
||||
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'))
|
||||
|
|
|
@ -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.urls import include, url
|
||||
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'^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',
|
||||
|
|
58
resources/chatbox.scss
Normal 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;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 797 B After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 4.8 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 8.9 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 14 KiB |
BIN
resources/icons/apple-touch-icon-114x114-precomposed.png
Normal file
After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 2 KiB After Width: | Height: | Size: 14 KiB |
BIN
resources/icons/apple-touch-icon-120x120-precomposed.png
Normal file
After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 15 KiB |
BIN
resources/icons/apple-touch-icon-144x144-precomposed.png
Normal file
After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 21 KiB |
BIN
resources/icons/apple-touch-icon-152x152-precomposed.png
Normal file
After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 23 KiB |
BIN
resources/icons/apple-touch-icon-180x180-precomposed.png
Normal file
After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 31 KiB |
BIN
resources/icons/apple-touch-icon-57x57-precomposed.png
Normal file
After Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 4.4 KiB |
BIN
resources/icons/apple-touch-icon-60x60-precomposed.png
Normal file
After Width: | Height: | Size: 5.5 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 4.8 KiB |
BIN
resources/icons/apple-touch-icon-72x72-precomposed.png
Normal file
After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 6.4 KiB |
BIN
resources/icons/apple-touch-icon-76x76-precomposed.png
Normal file
After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 7 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 28 KiB |
|
@ -1,12 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="/mstile-70x70.png"/>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<square310x310logo src="/mstile-310x310.png"/>
|
||||
<wide310x150logo src="/mstile-310x150.png"/>
|
||||
<TileColor>#00aba9</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square70x70logo src="/mstile-70x70.png"/>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<square310x310logo src="/mstile-310x310.png"/>
|
||||
<TileColor>#da532c</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
||||
|
|
Before Width: | Height: | Size: 830 B After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "DMOJ",
|
||||
"name": "LQDOJ",
|
||||
"icons": [
|
||||
{
|
||||
"src": "\/android-chrome-36x36.png",
|
||||
|
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 63 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 14 KiB |
|
@ -2,18 +2,57 @@
|
|||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<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">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</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">
|
||||
<path d="M4430 9579 c-1066 -77 -2049 -478 -2810 -1146 -900 -791 -1457 -1877
|
||||
-1597 -3115 -25 -218 -25 -828 0 -1048 126 -1122 585 -2089 1362 -2865 773
|
||||
-774 1763 -1251 2865 -1381 183 -21 681 -30 891 -15 951 68 1836 397 2584 961
|
||||
181 137 295 236 474 413 538 531 923 1151 1161 1867 129 386 200 739 231 1150
|
||||
15 201 6 734 -16 929 -126 1130 -590 2116 -1355 2881 -763 763 -1738 1226
|
||||
-2855 1355 -166 20 -744 28 -935 14z"/>
|
||||
<path d="M1101 2183 c0 -7 -1 -15 -1 -18 0 -3 -7 -19 -15 -35 -8 -16 -15 -32
|
||||
-15 -35 0 -3 0 -6 -1 -7 0 -2 -2 -10 -4 -18 -2 -8 -18 -67 -35 -130 -17 -63
|
||||
-34 -125 -37 -137 -4 -18 -9 -20 -30 -12 -18 7 -22 6 -17 -4 5 -8 2 -8 -9 2
|
||||
-13 11 -17 11 -17 1 0 -8 -3 -10 -7 -7 -3 4 -12 2 -20 -4 -7 -6 -13 -8 -13 -4
|
||||
0 4 -7 2 -15 -5 -8 -7 -15 -10 -15 -7 0 3 -15 1 -32 -4 -18 -6 -42 -12 -53
|
||||
-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>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 933 B After Width: | Height: | Size: 3.8 KiB |
|
@ -12,3 +12,4 @@
|
|||
@import "submission";
|
||||
@import "contest";
|
||||
@import "misc";
|
||||
@import "chatbox";
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
{% if request.user.is_authenticated %}
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block js_media %}
|
||||
|
@ -9,34 +10,127 @@
|
|||
<script type="text/javascript">
|
||||
$(function() {
|
||||
chatSocket.onmessage = function(e) {
|
||||
var data = JSON.parse(e.data);
|
||||
var message = data['message'];
|
||||
$('#chat-log').append(message + '\n');
|
||||
let data = JSON.parse(e.data)
|
||||
data = data['message']
|
||||
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) {
|
||||
console.error('Chat socket closed unexpectedly');
|
||||
};
|
||||
$('#chat-message-input').focus();
|
||||
$('#chat-message-input').keyup(function(e) {
|
||||
if (e.keyCode === 13) { // enter, return
|
||||
$('#chat-message-submit').click();
|
||||
|
||||
$("#chat-log").change(function() {
|
||||
$('#chat-log').scrollTop($('#chat-log')[0].scrollHeight);
|
||||
});
|
||||
|
||||
$('#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>
|
||||
{% endblock js_media %}
|
||||
|
||||
{% block body %}
|
||||
<div>
|
||||
<textarea disabled id="chat-log" rows="20" style="width: 100%"></textarea><br/>
|
||||
<input id="chat-message-input" type="text" style="width: 100%"/><br/>
|
||||
{% csrf_token %}
|
||||
<div id="chat-area">
|
||||
<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>
|
||||
<span class="message">
|
||||
<span>It’s 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 shouldn’t 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-message-submit" style="margin-top: 1em"> Send </button>
|
||||
<button id="chat-submit"> Send </button>
|
||||
{% endblock body %}
|
||||
{% endif %}
|
||||
|
|