Rewrite chat UI

This commit is contained in:
cuom1999 2021-07-24 01:36:34 -05:00
parent 57787164be
commit 0205a25689
6 changed files with 402 additions and 267 deletions

View file

@ -1,123 +0,0 @@
#loader {
display: block;
margin-left: auto;
margin-right: auto;
width: 4%;
}
#chat-log {
padding: 0;
padding-top: 2em;
width: 100%;
}
#chat-log li {
list-style-type: none;
margin: 0.5em;
}
#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;
padding-bottom: 1em;
border-bottom: 1px solid lightgray;
}
.user-time {
margin-bottom: 0.3em;
}
.time {
margin-left: 0.5em;
}
.clear {
clear: both;
}
.content-message {
word-wrap: break-word;
}
.content-message p {
margin: 0;
}
#chat-area {
height: 85vh;
/*display: flex;*/
/*flex-direction: column;*/
}
#chat-online {
border: 1px solid #ccc;
border-radius: 4px;
padding-bottom: 0 !important;
}
#chat-online-content {
margin-top: 0.5em;
margin-bottom: 0;
overflow: hidden;
overflow-wrap: break-word;
overflow-y: auto;
max-height: 77vh;
}
#chat-box {
border: 1px solid #ccc;
border-radius: 4px;
width: 100%;
overflow: hidden;
overflow-wrap: break-word;
overflow-y: scroll;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
max-height: 85%;
height: auto;
}
#chat-input {
width: 100.3%;
padding: 0.4em;
color: black;
font-family: "Segoe UI", "Lucida Grande", Arial, sans-serif;
border-top-left-radius: 0;
border-top-right-radius: 0;
height: 15%;
}
#chat-online-content {
padding: 0;
width: 100%;
}
@media (min-width: 800px) {
#chat-container {
display: flex;
width: 100%;
}
#chat-box {
}
#chat-online {
margin-left: auto;
width: 22%;
}
#chat-area {
width: 75%;
}
.chat-left-panel, .chat-right-panel {
display: block !important;
}
}

View file

@ -212,8 +212,9 @@ function count_down(label) {
}, 1000); }, 1000);
} }
function register_time(elems, limit) { function register_time(elems, limit) { // in hours
limit = limit || 300; if ('limit_time' in window) limit = window.limit_time;
else limit = limit || 300 * 24;
elems.each(function () { elems.each(function () {
var outdated = false; var outdated = false;
var $this = $(this); var $this = $(this);
@ -225,7 +226,7 @@ function register_time(elems, limit) {
if ($('body').hasClass('window-hidden')) if ($('body').hasClass('window-hidden'))
return outdated = true; return outdated = true;
outdated = false; outdated = false;
if (moment().diff(time, 'days') > limit) { if (moment().diff(time, 'hours') > limit) {
$this.text(abs); $this.text(abs);
return; return;
} }

View file

@ -306,7 +306,7 @@
{% endif %} {% endif %}
{% block bodyend %}{% endblock %} {% block bodyend %}{% endblock %}
{% block footer %}
<footer> <footer>
<span id="footer-content"> <span id="footer-content">
<br> <br>
@ -327,6 +327,7 @@
</form> </form>
</span> </span>
</footer> </footer>
{% endblock %}
</div> </div>
</body> </body>
</html> </html>

View file

@ -6,9 +6,12 @@
<script type="text/javascript" src="{{ static('mathjax_config.js') }}"></script> <script type="text/javascript" src="{{ static('mathjax_config.js') }}"></script>
<script type="text/javascript" src="{{ static('event.js') }}"></script> <script type="text/javascript" src="{{ static('event.js') }}"></script>
<script src="https://unpkg.com/@popperjs/core@2"></script>
<script type="module" src="https://unpkg.com/emoji-picker-element@1"></script>
<script type="text/javascript"> <script type="text/javascript">
window.currentPage = 1; window.currentPage = 1;
window.limit_time = 0;
window.messages_per_page = 50;
function load_page(page) { function load_page(page) {
$.get('?page=' + page) $.get('?page=' + page)
@ -21,8 +24,15 @@
let lastMsgPos = scrollTopOfBottom(container) let lastMsgPos = scrollTopOfBottom(container)
$('#loader').hide(); $('#loader').hide();
$('#chat-log').prepend(data); $('#chat-log').prepend(data);
remove_day_if_today();
$('.body-block').slice(0, window.messages_per_page).each(function() {
resize_emoji($(this));
});
register_time($('.time-with-rel'));
merge_authors();
container.scrollTop(scrollTopOfBottom(container) - lastMsgPos); container.scrollTop(scrollTopOfBottom(container) - lastMsgPos);
}, 500); }, 500);
@ -44,15 +54,6 @@
} }
})} })}
function remove_day_if_today() {
$('.message_date').each(function() {
sent_date = $(this).html()
if (sent_date === "{{today}}") {
$(this).hide();
}
})
}
window.load_dynamic_update = function (last_msg) { window.load_dynamic_update = function (last_msg) {
return new EventReceiver( return new EventReceiver(
"{{ EVENT_DAEMON_LOCATION }}", "{{ EVENT_DAEMON_POLL_LOCATION }}", "{{ EVENT_DAEMON_LOCATION }}", "{{ EVENT_DAEMON_POLL_LOCATION }}",
@ -67,16 +68,20 @@
} }
function add_new_message(message) { function add_new_message(message) {
// console.log(message);
$.get({ $.get({
url: "{{ url('chat_message_ajax') }}", url: "{{ url('chat_message_ajax') }}",
data: { data: {
message: message, message: message,
}, },
success: function (data) { success: function (data) {
$('#chat-log').append($(data)); var $data = $(data);
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight) resize_emoji($data.find('.body-block'));
$('#chat-log').append($data);
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
MathJax.Hub.Queue(["Typeset",MathJax.Hub]); MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
register_time($('.time-with-rel'));
merge_authors();
}, },
error: function (data) { error: function (data) {
if (data.status === 403) if (data.status === 403)
@ -89,8 +94,61 @@
}); });
} }
function merge_authors() {
var time_limit = 5; // minutes
var last = {
username: null,
time: null,
$content: null
};
$('.body-message').each(function() {
var username = $(this).find(".username a").text().trim();
var $body = $(this).find(".content-message .body-block");
var time = moment($(this).find(".time-with-rel").attr('data-iso'));
var $content = $(this).children('.content-message');
if (username == last.username && time.diff(last.time, 'minutes') <= time_limit) {
last.$content.append($body);
$(this).parent().remove();
}
else {
last.username = username;
last.time = time;
last.$content = $content;
}
});
}
function submit_chat() {
if ($("#chat-input").val().trim()) {
var body = $('#chat-input').val().trim();
body = body.split('\n').join('\n\n');
var message = {
body: body,
};
$('#chat-input').val('');
$.post("{{ url('post_chat_message') }}", message)
.fail(function(res) {
console.log('Fail to send message');
})
.done(function(res, status) {
$('#chat-input').focus();
})
}
}
function resize_emoji(element) {
var html = element.html();
html = html.replace(/(\p{Extended_Pictographic})/ug, `<span class="big-emoji">$1</span>`);
element.html(html);
}
$(function() { $(function() {
$('#loader').hide(); $('#loader').hide();
merge_authors();
scrollContainer($('#chat-box'), $('#loader')) scrollContainer($('#chat-box'), $('#loader'))
@ -105,7 +163,13 @@
}, },
dataType: 'json', dataType: 'json',
success: function(data){ success: function(data){
elt.closest('li').hide(); var $block = elt.parent();
if ($block.parent().find('.body-block').length > 1) {
$block.remove();
}
else {
elt.closest('li').remove();
}
}, },
fail: function(data) { fail: function(data) {
alert('Fail to delete'); alert('Fail to delete');
@ -114,25 +178,8 @@
}); });
{% endif %} {% endif %}
$("#chat-submit").click(function() { $('.body-block').each(function() {
if ($("#chat-input").val().trim()) { resize_emoji($(this));
let body = $('#chat-input').val().trim();
let img = '{{ gravatar(request.user, 32) }}';
message = {
body: body,
};
$('#chat-input').val('');
$.post("{{ url('post_chat_message') }}", message)
.fail(function(res) {
console.log('Fail to send message');
})
.done(function(res, status) {
$('#chat-input').focus();
})
}
}); });
$("#chat-log").change(function() { $("#chat-log").change(function() {
@ -159,7 +206,7 @@
} }
else { else {
e.preventDefault(); e.preventDefault();
$('#chat-submit').click(); submit_chat();
} }
return false return false
} }
@ -204,99 +251,41 @@
}, 5 * 60 * 1000); }, 5 * 60 * 1000);
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight); $('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
remove_day_if_today();
load_dynamic_update({{last_msg}}); load_dynamic_update({{last_msg}});
const button = document.querySelector('#emoji-button')
const tooltip = document.querySelector('.tooltip')
Popper.createPopper(button, tooltip)
function toggleEmoji() {
tooltip.classList.toggle('shown')
}
$('#emoji-button').on('click', function(e) {
e.preventDefault();
toggleEmoji();
});
$('emoji-picker').on('emoji-click', function(e) {
var $chat = $('#chat-input');
var text = $chat.val();
$chat.val(text + e.detail.unicode);
})
document.addEventListener('keydown', function(e) {
if (e.keyCode === 27 && $('.tooltip').hasClass('shown')) {
toggleEmoji();
}
})
}); });
</script> </script>
{% endblock js_media %} {% endblock js_media %}
{% block media %} {% block media %}
<style> {% include "chat/chat_css.html" %}
#content {
margin-top: -0.5em;
}
#refresh-button {
padding: 0;
margin-left: auto;
margin-right: 0.3em;
background: transparent;
border: none;
height: 1.5em;
width: 1.5em;
}
#refresh-button:hover {
background: lightgreen;
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
transition: 1.5s ease-in-out;
}
.status-pic {
height: 1.3em;
width: 1.3em;
border-radius: 0.3em;
}
.status-container {
position: relative;
display: inline-flex;
}
.status-circle {
position: absolute;
bottom: 0;
right: 0;
cx: 18px;
cy: 18px;
r: 4.5px;
stroke: white;
stroke-width: 1;
}
.status-row {
display: flex;
margin-bottom: 0.5em;
font-size: 15px;
}
.status-list {
padding: 0;
}
.status-section-title {
cursor: pointer;
margin-top: 0.5em;
}
::-webkit-scrollbar {
width: 20px;
}
::-webkit-scrollbar-track {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: #d6dee1;
border-radius: 20px;
border: 6px solid transparent;
background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
background-color: #a8bbbf;
}
@media (min-width: 800px) {
#page-container {
position:fixed;
overflow:hidden;
}
}
#page-container {
width: 100%;
}
</style>
{% endblock media %} {% endblock media %}
{% block footer %}{% endblock %}
{% block body %} {% block body %}
{% csrf_token %}
{% block before_posts %}{% endblock %}
<div id="mobile" class="tabs"> <div id="mobile" class="tabs">
<ul> <ul>
<li id="chat-tab" class="tab active"><a href="#"> <li id="chat-tab" class="tab active"><a href="#">
@ -307,16 +296,6 @@
</div> </div>
<div id="chat-container"> <div id="chat-container">
<div id="chat-area" class="chat-left-panel">
<div id="chat-box">
<img src="http://opengraphicdesign.com/wp-content/uploads/2009/01/loader64.gif" id="loader">
<ul id="chat-log">
{% include 'chat/message_list.html' %}
</ul>
</div>
<textarea id="chat-input" placeholder="{{_('Enter your message')}}"></textarea>
</div>
<button id="chat-submit" style="display:none;"> Send </button>
<div id="chat-online" class="chat-right-panel sidebox"> <div id="chat-online" class="chat-right-panel sidebox">
<h3 style="display:flex"> <h3 style="display:flex">
{{_('Online Users')}} {{_('Online Users')}}
@ -330,6 +309,20 @@
{% include "chat/online_status.html" %} {% include "chat/online_status.html" %}
</div> </div>
</div> </div>
<div id="chat-area" class="chat-left-panel" style="width:100%">
<div id="chat-box">
<img src="http://opengraphicdesign.com/wp-content/uploads/2009/01/loader64.gif" id="loader">
<ul id="chat-log">
{% include 'chat/message_list.html' %}
</ul>
</div>
<div style="height: 15%">
<a id="emoji-button" href="#" title="{{_('Emoji')}}"><i class="icofont-slightly-smile"></i></a>
<textarea id="chat-input" placeholder="{{_('Enter your message')}}"></textarea>
</div>
<div class="tooltip" role="tooltip">
<emoji-picker></emoji-picker>
</div>
</div>
</div> </div>
{% endblock body %} {% endblock body %}

View file

@ -0,0 +1,262 @@
<style>
#content {
margin: -1em 1em 0 0;
}
#chat-log p {
margin: 0;
padding-top: 0.1em;
padding-bottom: 0.1em;
}
.chatbtn_remove_mess {
float: right;
margin-right: 1em;
}
#refresh-button {
padding: 0;
margin-left: auto;
margin-right: 0.3em;
background: transparent;
border: none;
height: 1.5em;
width: 1.5em;
}
#refresh-button:hover {
background: lightgreen;
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
transition: 1.5s ease-in-out;
}
.status-pic {
height: 1.3em;
width: 1.3em;
border-radius: 0.3em;
}
.status-container {
position: relative;
display: inline-flex;
}
.status-circle {
position: absolute;
bottom: 0;
right: 0;
cx: 18px;
cy: 18px;
r: 4.5px;
stroke: white;
stroke-width: 1;
}
.status-row {
display: flex;
margin-bottom: 0.5em;
font-size: 15px;
}
.status-list {
padding: 0;
padding-left: 1em;
}
.status-section-title {
cursor: pointer;
margin-top: 0.5em;
}
::-webkit-scrollbar {
width: 20px;
}
::-webkit-scrollbar-track {
background-color: transparent;
}
::-webkit-scrollbar-thumb {
background-color: #d6dee1;
border-radius: 20px;
border: 6px solid transparent;
background-clip: content-box;
}
::-webkit-scrollbar-thumb:hover {
background-color: #a8bbbf;
}
#page-container {
width: 100%;
}
.body-message img{
max-height: 12em;
}
.tooltip:not(.shown) {
display: none;
}
textarea {
resize: none;
}
.tooltip {
left: 120vh !important;
transform: translate(100px, 0) !important;
position: absolute;
}
#emoji-button {
position: absolute;
right: 1em;
font-size: 2em;
color: lightgray;
}
#emoji-button:hover {
color: gray;
}
#loader {
display: block;
margin-left: auto;
margin-right: auto;
width: 4%;
}
#chat-log {
padding: 0;
padding-top: 2em;
width: 100%;
font-size: 14px;
}
#chat-log li {
list-style-type: none;
margin: 0.5em;
}
#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;
padding-bottom: 0.5em;
border-bottom: 1px dotted lightgray;
}
.user-time {
margin-bottom: 0.3em;
}
.time {
margin-left: 0.5em;
}
.big-emoji {
font-size: 16px;
}
.clear {
clear: both;
}
.content-message {
word-wrap: break-word;
}
.content-message p {
margin: 0;
}
#chat-online {
border-right: 1px solid #ccc;
padding-bottom: 0 !important;
min-width: 25%;
border-bottom: 0;
}
#chat-online-content {
margin-top: 0.5em;
margin-bottom: 0;
overflow: hidden;
overflow-wrap: break-word;
overflow-y: auto;
max-height: 77vh;
}
#chat-box {
/*border: 1px solid #ccc;*/
/*border-top-right-radius: 4px;*/
width: 100%;
overflow: hidden;
overflow-wrap: break-word;
overflow-y: scroll;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
max-height: 85%;
height: auto;
}
#chat-input {
width: 100%;
padding: 0.4em;
padding-bottom: 0.6em;
border: 0;
color: black;
font-family: "Segoe UI", "Lucida Grande", Arial, sans-serif;
border-top-left-radius: 0;
border-top-right-radius: 0;
height: 100%;
font-size: 14px;
}
#chat-online-content {
padding: 0;
width: 100%;
}
#content {
width: 100%;
}
#content-body {
padding-bottom: 0;
}
#page-container {
min-height: 0;
}
.sidebox h3 {
border-radius: 0;
margin: -1px -5.5px 0 -5.8px;
}
.body-block {
border-radius: 4px;
padding-left: 0.2em;
}
.body-block:hover {
background: #eee;
}
@media (min-width: 800px) {
#page-container {
position:fixed;
overflow:hidden;
}
#chat-container {
display: flex;
width: 100%;
height: 90vh;
border: 1px solid #ccc;
/*border-radius: 0 4px 0 0;*/
border-bottom: 0;
}
#chat-box {
}
#chat-online {
margin: 0;
}
.chat-left-panel, .chat-right-panel {
display: block !important;
}
}
</style>

View file

@ -10,17 +10,18 @@
</a> </a>
</span> </span>
<span class="time"> <span class="time">
{{ message.time|date('TIME_FORMAT') }} {{ relative_time(message.time, abs=_('{time}'), rel=_('{time}'), format=_('g:i a d/m/Y')) }}
<span class="message_date">{{ message.time|date('d-m-Y') }}</span>
</span> </span>
</div>
<span class="content-message">
<div class="body-block" title="{{ message.time|date('g:i a') }}">
{% if request.user.is_staff %} {% if request.user.is_staff %}
<a class="chatbtn_remove_mess" value="{{message.id}}" style="color:red; cursor: pointer;"> <a class="chatbtn_remove_mess" value="{{message.id}}" style="color:red; cursor: pointer;">
{{_('Delete')}} {{_('Delete')}}
</a> </a>
{% endif %} {% endif %}
</div>
<span class="content-message">
{{message.body | markdown('comment', MATH_ENGINE)|reference|str|safe }} {{message.body | markdown('comment', MATH_ENGINE)|reference|str|safe }}
</div>
</span> </span>
</div> </div>
<div class="clear"></div> <div class="clear"></div>