593 lines
No EOL
16 KiB
HTML
593 lines
No EOL
16 KiB
HTML
<script type="text/javascript">
|
|
let isMobile = window.matchMedia("only screen and (max-width: 799px)").matches;
|
|
|
|
function load_next_page(last_id, refresh_html=false) {
|
|
if (refresh_html) {
|
|
window.lock = true;
|
|
$('#chat-log').html('');
|
|
$('#loader').show();
|
|
}
|
|
var param = {
|
|
'last_id': last_id,
|
|
'only_messages': true,
|
|
}
|
|
$.get("{{ url('chat', '') }}" + window.room_id, param)
|
|
.fail(function() {
|
|
console.log("Fail to load page, last_id = " + last_id);
|
|
window.lock = false;
|
|
})
|
|
.done(function(data) {
|
|
if (refresh_html) {
|
|
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
|
}
|
|
var time = refresh_html ? 0 : 200;
|
|
|
|
setTimeout(function() {
|
|
$(".has_next").remove();
|
|
let $chat_box = $('#chat-box');
|
|
let lastMsgPos = scrollTopOfBottom($chat_box)
|
|
|
|
$('#loader').hide();
|
|
|
|
if (refresh_html) {
|
|
$('#chat-log').append(data);
|
|
}
|
|
else {
|
|
$('#chat-log').prepend(data);
|
|
}
|
|
|
|
postProcessMessages();
|
|
|
|
if (!refresh_html) {
|
|
$chat_box.scrollTop(scrollTopOfBottom($chat_box) - lastMsgPos);
|
|
}
|
|
else {
|
|
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
|
}
|
|
window.lock = false;
|
|
window.has_next = parseInt($(".has_next").attr("value"));
|
|
}, time);
|
|
})
|
|
}
|
|
|
|
function postProcessMessages() {
|
|
register_time($('.time-with-rel'));
|
|
renderKatex();
|
|
populateCopyButton();
|
|
merge_authors();
|
|
}
|
|
|
|
function scrollTopOfBottom(container) {
|
|
return container[0].scrollHeight - container.innerHeight()
|
|
}
|
|
|
|
function scrollContainer(container, loader) {
|
|
container.scroll(function() {
|
|
if (container.scrollTop() == 0) {
|
|
if (!window.lock && window.has_next) {
|
|
loader.show();
|
|
var message_ids = $('.message').map(function() {
|
|
return parseInt($(this).attr('message-id'));
|
|
}).get();
|
|
load_next_page(Math.min(...message_ids));
|
|
}
|
|
}
|
|
})}
|
|
|
|
function refresh_status(refresh_chat_info=false) {
|
|
$.get("{{url('online_status_ajax')}}")
|
|
.fail(function() {
|
|
console.log("Fail to get online status");
|
|
})
|
|
.done(function(data) {
|
|
if (data.status == 403) {
|
|
console.log("Fail to retrieve data");
|
|
}
|
|
else {
|
|
$('#chat-online-list').html(data).find('.toggle').each(function () {
|
|
register_toggle($(this));
|
|
});
|
|
register_click_space();
|
|
register_setting(false);
|
|
color_selected_room();
|
|
}
|
|
})
|
|
|
|
var data = {
|
|
'user': window.other_user_id,
|
|
};
|
|
|
|
if (refresh_chat_info) {
|
|
$('#chat-info').html('');
|
|
}
|
|
|
|
$.get("{{url('user_online_status_ajax')}}", data)
|
|
.fail(function() {
|
|
console.log("Fail to get user online status");
|
|
})
|
|
.done(function(data) {
|
|
$('#chat-info').html(data);
|
|
register_time($('.time-with-rel'));
|
|
register_setting(true);
|
|
})
|
|
}
|
|
|
|
function add_message(data) {
|
|
var $data = $(data);
|
|
|
|
$('#chat-log').append($data);
|
|
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
|
postProcessMessages();
|
|
}
|
|
|
|
function add_new_message(message, room, is_self_author) {
|
|
function callback(update) {
|
|
if (!document['hidden']) {
|
|
if (update) update_last_seen();
|
|
refresh_status();
|
|
}
|
|
else if (!is_self_author) {
|
|
window.unread_message++;
|
|
document.title = "(" + window.unread_message + ") " + "{{ _('New message(s)') }}";
|
|
}
|
|
}
|
|
|
|
if (room == window.room_id) {
|
|
$.get({
|
|
url: "{{ url('chat_message_ajax') }}",
|
|
data: {
|
|
message: message,
|
|
},
|
|
success: function (data) {
|
|
add_message(data);
|
|
callback(true);
|
|
},
|
|
error: function (data) {
|
|
console.log('Could not add new message');
|
|
}
|
|
});
|
|
}
|
|
else {
|
|
callback(false);
|
|
}
|
|
}
|
|
|
|
function check_new_message(message, tmp_id, room) {
|
|
if (room == room_id) {
|
|
$.get({
|
|
url: "{{ url('chat_message_ajax') }}",
|
|
data: {
|
|
message: message,
|
|
},
|
|
success: function (data) {
|
|
var $body_block = $(data).find('.body-block');
|
|
if ($('#message-'+tmp_id).length) {
|
|
$('#message-'+tmp_id).replaceWith(data);
|
|
}
|
|
else if ($('#body-block-'+tmp_id).length) {
|
|
$('#body-block-'+tmp_id).replaceWith($body_block);
|
|
}
|
|
else {
|
|
add_new_message(message, room, true);
|
|
}
|
|
remove_unread_current_user();
|
|
postProcessMessages();
|
|
},
|
|
error: function (data) {
|
|
console.log('Fail to check message');
|
|
var $body = $('#body-block-'+tmp_id + ' p');
|
|
$body.css('text-decoration', 'line-through');
|
|
$body.css('text-decoration-color', 'red');
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
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 == window.user.name) {
|
|
$(this).find('.message-text').each(function() {
|
|
$(this).removeClass('message-text-other').addClass('message-text-myself');
|
|
});
|
|
}
|
|
|
|
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 add_message_from_template(body, tmp_id) {
|
|
if (window.room_id) {
|
|
$("#last_msg-" + window.room_id).html(body);
|
|
}
|
|
var html = message_template;
|
|
html = html.replaceAll('$body', body).replaceAll('$id', tmp_id);
|
|
var $html = $(html);
|
|
$html.find('.time-with-rel').attr('data-iso', (new Date()).toISOString());
|
|
add_message($html[0].outerHTML);
|
|
}
|
|
|
|
function submit_chat() {
|
|
{% if last_msg and not request.profile.mute %}
|
|
if ($("#chat-input").val().trim()) {
|
|
$('#chat-input-container').height('auto');
|
|
var body = $('#chat-input').val().trim();
|
|
|
|
var message = {
|
|
body: body,
|
|
room: window.room_id,
|
|
tmp_id: Date.now(),
|
|
};
|
|
|
|
$('#chat-input').val('');
|
|
$('#chat-input').css('height', '70%');
|
|
|
|
add_message_from_template(body, message.tmp_id);
|
|
|
|
$.post("{{ url('post_chat_message') }}", message)
|
|
.fail(function(res) {
|
|
console.log('Fail to send message');
|
|
var $body = $('#message-text-'+ message.tmp_id);
|
|
$body.css('text-decoration', 'line-through');
|
|
$body.css('background', 'red');
|
|
})
|
|
.done(function(res, status) {
|
|
$('#empty_msg').hide();
|
|
$('#chat-input').focus();
|
|
})
|
|
}
|
|
{% endif %}
|
|
}
|
|
|
|
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 insert_char_after_cursor(elem, char) {
|
|
var val = elem.value;
|
|
if (typeof elem.selectionStart == "number" && typeof elem.selectionEnd == "number") {
|
|
var start = elem.selectionStart;
|
|
var prefix = elem.value.slice(0, start);
|
|
var prefix_added = prefix + char;
|
|
var chars = [...val];
|
|
chars.splice([...prefix].length, 0, char);
|
|
elem.value = chars.join('');
|
|
elem.selectionStart = elem.selectionEnd = prefix_added.length;
|
|
} else if (document.selection && document.selection.createRange) {
|
|
var range = document.selection.createRange();
|
|
elem.focus();
|
|
range.text = char;
|
|
range.collapse(false);
|
|
range.select();
|
|
}
|
|
}
|
|
|
|
function color_selected_room() {
|
|
$(".status-row").removeClass("selected-status-row");
|
|
$("#click_space_" + window.other_user_id).addClass("selected-status-row");
|
|
}
|
|
|
|
function show_right_panel() {
|
|
if (isMobile) {
|
|
$('.chat-left-panel').hide();
|
|
$('#chat-area').css('display', 'flex');
|
|
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
|
}
|
|
}
|
|
|
|
function hide_right_panel() {
|
|
if (isMobile) {
|
|
$('.chat-left-panel').show();
|
|
$('#chat-area').hide();
|
|
}
|
|
}
|
|
|
|
function load_room(encrypted_user) {
|
|
if (window.lock_click_space) return;
|
|
|
|
function callback() {
|
|
history.replaceState(null, '', "{{url('chat', '')}}" + window.room_id);
|
|
load_next_page(null, true);
|
|
update_last_seen();
|
|
refresh_status(true);
|
|
|
|
show_right_panel();
|
|
$('#chat-input').focus();
|
|
$('#chat-input').val('').trigger('input');
|
|
}
|
|
window.lock_click_space = true;
|
|
if (encrypted_user) {
|
|
$.get("{{url('get_or_create_room')}}" + `?other=${encrypted_user}`)
|
|
.done(function(data) {
|
|
window.room_id = data.room;
|
|
window.other_user_id = data.other_user_id;
|
|
color_selected_room();
|
|
callback();
|
|
$('#chat-input').attr('maxlength', 5000);
|
|
})
|
|
.fail(function() {
|
|
console.log('Fail to get_or_create_room');
|
|
})
|
|
}
|
|
else {
|
|
window.room_id = '';
|
|
window.other_user_id = '';
|
|
color_selected_room();
|
|
callback();
|
|
$('#chat-input').attr('maxlength', 200);
|
|
}
|
|
window.lock_click_space = false;
|
|
}
|
|
|
|
function register_click_space() {
|
|
$('.click_space').on('click', function(e) {
|
|
if ($(this).attr('id') == 'click_space_' + window.other_user_id) {
|
|
show_right_panel();
|
|
return;
|
|
}
|
|
var other_user = $(this).attr('value');
|
|
load_room(other_user);
|
|
});
|
|
$('#lobby_row').on('click', function(e) {
|
|
if (window.room_id) {
|
|
load_room(null);
|
|
}
|
|
else {
|
|
show_right_panel();
|
|
}
|
|
});
|
|
}
|
|
|
|
function update_last_seen() {
|
|
var data = {
|
|
room: window.room_id
|
|
};
|
|
|
|
$.post("{{ url('update_last_seen') }}", data)
|
|
.fail(function(data) {
|
|
console.log('Fail to update last seen');
|
|
})
|
|
.done(function(data) {
|
|
|
|
})
|
|
}
|
|
|
|
function remove_unread_current_user() {
|
|
if (window.other_user_id) {
|
|
$("#unread-count-" + window.other_user_id).hide();
|
|
}
|
|
else {
|
|
$('#unread-count-lobby').hide();
|
|
}
|
|
}
|
|
|
|
function register_setting(is_on_user_status_bar) {
|
|
let $setting_button = is_on_user_status_bar ? $('.user-setting-button') : $('.setting-button');
|
|
$setting_button.on('click', function(e) {
|
|
e.stopPropagation();
|
|
$('.setting-content').not($(this).siblings('.setting-content')).hide();
|
|
$(this).siblings('.setting-content').toggle();
|
|
});
|
|
$('.setting-content a').on('click', function(e) {
|
|
e.stopPropagation();
|
|
var href = $(this).attr('href');
|
|
href += '?next=' + window.location.pathname;
|
|
$(this).attr('href', href);
|
|
})
|
|
$(document).on('click', function() {
|
|
$('.setting-content').hide();
|
|
});
|
|
}
|
|
$(function() {
|
|
$('#loader').hide();
|
|
update_last_seen();
|
|
merge_authors();
|
|
window.has_next = parseInt($(".has_next").attr("value"));
|
|
|
|
scrollContainer($('#chat-box'), $('#loader'))
|
|
|
|
{% if request.user.is_staff %}
|
|
$(document).on("click", ".chat_remove", function() {
|
|
var elt = $(this);
|
|
$.ajax({
|
|
url: "{{ url('delete_chat_message') }}",
|
|
type: 'post',
|
|
data: {
|
|
message: elt.attr('value'),
|
|
},
|
|
dataType: 'json',
|
|
success: function(data){
|
|
var $block = elt.parent();
|
|
if ($block.parent().find('.body-block').length > 1) {
|
|
$block.remove();
|
|
}
|
|
else {
|
|
elt.closest('li').remove();
|
|
}
|
|
},
|
|
fail: function(data) {
|
|
console.log('Fail to delete');
|
|
},
|
|
});
|
|
});
|
|
$(document).on("click", ".chat_mute", function() {
|
|
if (confirm("{{_('Mute this user and delete all messages?')}}")) {
|
|
var elt = $(this);
|
|
$.ajax({
|
|
url: "{{ url('mute_chat_message') }}",
|
|
type: 'post',
|
|
data: {
|
|
message: elt.attr('value'),
|
|
},
|
|
dataType: 'json',
|
|
success: function(data){
|
|
window.location.reload();
|
|
},
|
|
fail: function(data) {
|
|
console.log('Fail to delete');
|
|
},
|
|
});
|
|
}
|
|
});
|
|
{% endif %}
|
|
|
|
$("#chat-log").show();
|
|
$("#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) {
|
|
insert_char_after_cursor(this, "\n");
|
|
}
|
|
else {
|
|
e.preventDefault();
|
|
submit_chat();
|
|
}
|
|
return false
|
|
}
|
|
return true
|
|
});
|
|
|
|
setInterval(refresh_status, 2 * 60 * 1000);
|
|
|
|
$('#chat-box').scrollTop($('#chat-box')[0].scrollHeight);
|
|
|
|
const button = document.querySelector('#emoji-button');
|
|
const tooltip = document.querySelector('.tooltip');
|
|
const popper = Popper.createPopper(button, tooltip, {
|
|
placement: isMobile ? 'auto-end' : 'left',
|
|
});
|
|
|
|
function toggleEmoji() {
|
|
tooltip.classList.toggle('shown');
|
|
popper.update();
|
|
}
|
|
$('#emoji-button').on('click', function(e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
toggleEmoji();
|
|
});
|
|
|
|
// Đóng bảng emoji khi click bất kỳ chỗ nào trên màn hình
|
|
document.addEventListener("click", function(e) {
|
|
if (!tooltip.contains(e.target)) {
|
|
tooltip.classList.remove('shown'); // Ẩn bảng emoji
|
|
}
|
|
});
|
|
|
|
$('emoji-picker').on('emoji-click', function(e) {
|
|
var $chat = $('#chat-input').get(0);
|
|
insert_char_after_cursor($chat, e.detail.unicode);
|
|
$chat.focus();
|
|
})
|
|
|
|
register_click_space();
|
|
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.keyCode === 27 && $('.tooltip').hasClass('shown')) {
|
|
toggleEmoji();
|
|
}
|
|
})
|
|
|
|
$('#search-handle').replaceWith($('<select>').attr({
|
|
id: 'search-handle',
|
|
name: 'other',
|
|
onchange: 'form.submit()'
|
|
}));
|
|
|
|
var in_user_redirect = false;
|
|
$('#search-handle').select2({
|
|
placeholder: '<i class="fa fa-search"></i> {{ _('Search by handle...') }}',
|
|
ajax: {
|
|
url: '{{ url('chat_user_search_select2_ajax') }}',
|
|
delay: 250,
|
|
cache: true,
|
|
},
|
|
minimumInputLength: 1,
|
|
escapeMarkup: function (markup) {
|
|
return markup;
|
|
},
|
|
templateResult: function (data, container) {
|
|
return $('<span>')
|
|
.append($('<img>', {
|
|
'class': 'user-search-image', src: data.gravatar_url,
|
|
width: 24, height: 24
|
|
}))
|
|
.append($('<span>', {'class': data.display_rank + ' user-search-name'}).text(data.text))
|
|
.append($('<a>', {href: '/user/' + data.text, 'class': 'user-redirect'})
|
|
.append($('<i>', {'class': 'fa fa-mail-forward'}))
|
|
.mouseover(function () {
|
|
in_user_redirect = true;
|
|
}).mouseout(function () {
|
|
in_user_redirect = false;
|
|
}));
|
|
}
|
|
}).on('select2:selecting', function () {
|
|
return !in_user_redirect;
|
|
});
|
|
|
|
$("#chat-input").on("keyup", function() {
|
|
$("#chat-input").scrollTop($("#chat-input")[0].scrollHeight);
|
|
});
|
|
|
|
// https://stackoverflow.com/questions/42121565/detecting-class-change-without-setinterval
|
|
if (typeof(MutationObserver) !== undefined) {
|
|
var observer = new MutationObserver(function (event) {
|
|
if (!document['hidden'] && window.unread_message > 0) {
|
|
update_last_seen();
|
|
refresh_status();
|
|
window.unread_message = 0;
|
|
document.title = "{{_('Chat Box')}}";
|
|
}
|
|
})
|
|
|
|
observer.observe(document.body, {
|
|
attributes: true,
|
|
attributeFilter: ['class'],
|
|
childList: false,
|
|
characterData: false
|
|
})
|
|
}
|
|
register_setting(true);
|
|
register_setting(false);
|
|
color_selected_room();
|
|
|
|
$('#chat-input').on('input', function() {
|
|
if (this.scrollHeight > this.clientHeight) {
|
|
this.style.height = (this.scrollHeight) + 'px';
|
|
$(this).css('border-radius', '30px');
|
|
} else {
|
|
$(this).css('height', '70%');
|
|
}
|
|
});
|
|
|
|
$('#submit-button').on('click', submit_chat);
|
|
register_copy_clipboard($("#chat-input"), () => {
|
|
$('#chat-input').trigger('input');
|
|
});
|
|
});
|
|
</script> |