⚝
One Hat Cyber Team
⚝
Your IP:
216.73.216.1
Server IP:
185.238.29.86
Server:
Linux server2 6.8.12-6-pve #1 SMP PREEMPT_DYNAMIC PMX 6.8.12-6 (2024-12-19T19:05Z) x86_64
Server Software:
nginx/1.18.0
PHP Version:
8.1.31
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
var
/
www
/
work
/
public
/
js
/
chatify
/
Edit File: code.js
/** *------------------------------------------------------------- * Global variables *------------------------------------------------------------- */ var messenger, typingTimeout, typingNow = 0, temporaryMsgId = 0, defaultAvatarInSettings = null, messengerColor, dark_mode, messages_page = 1; const messagesContainer = $(".messenger-messagingView .m-body"), messengerTitleDefault = $(".messenger-headTitle").text(), messageInputContainer = $(".messenger-sendCard"), messageInput = $("#message-form .m-send"), auth_id = $("meta[name=url]").attr("data-user"), url = $("meta[name=url]").attr("content"), messengerTheme = $("meta[name=messenger-theme]").attr("content"), defaultMessengerColor = $("meta[name=messenger-color]").attr("content"), csrfToken = $('meta[name="csrf-token"]').attr("content"); const getMessengerId = () => $("meta[name=id]").attr("content"); const setMessengerId = (id) => $("meta[name=id]").attr("content", id); /** *------------------------------------------------------------- * Pusher initialization *------------------------------------------------------------- */ Pusher.logToConsole = chatify.pusher.debug; const pusher = new Pusher(chatify.pusher.key, { encrypted: chatify.pusher.options.encrypted, cluster: chatify.pusher.options.cluster, wsHost: chatify.pusher.options.host, wsPort: chatify.pusher.options.port, wssPort: chatify.pusher.options.port, forceTLS: chatify.pusher.options.useTLS, authEndpoint: chatify.pusherAuthEndpoint, auth: { headers: { "X-CSRF-TOKEN": csrfToken, }, }, }); /** *------------------------------------------------------------- * Re-usable methods *------------------------------------------------------------- */ const escapeHtml = (unsafe) => { return unsafe .replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); }; function actionOnScroll(selector, callback, topScroll = false) { $(selector).on("scroll", function () { let element = $(this).get(0); const condition = topScroll ? element.scrollTop == 0 : element.scrollTop + element.clientHeight >= element.scrollHeight; if (condition) { callback(); } }); } function routerPush(title, url) { $("meta[name=url]").attr("content", url); return window.history.pushState({}, title || document.title, url); } function updateSelectedContact(user_id) { $(document).find(".messenger-list-item").removeClass("m-list-active"); $(document) .find( ".messenger-list-item[data-contact=" + (user_id || getMessengerId()) + "]" ) .addClass("m-list-active"); } /** *------------------------------------------------------------- * Global Templates *------------------------------------------------------------- */ // Loading svg function loadingSVG(size = "25px", className = "", style = "") { return ` <svg style="${style}" class="loadingSVG ${className}" xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 40 40" stroke="#ffffff"> <g fill="none" fill-rule="evenodd"> <g transform="translate(2 2)" stroke-width="3"> <circle stroke-opacity=".1" cx="18" cy="18" r="18"></circle> <path d="M36 18c0-9.94-8.06-18-18-18" transform="rotate(349.311 18 18)"> <animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur=".8s" repeatCount="indefinite"></animateTransform> </path> </g> </g> </svg> `; } function loadingWithContainer(className) { return `<div class="${className}" style="text-align:center;padding:15px">${loadingSVG( "25px", "", "margin:auto" )}</div>`; } // loading placeholder for users list item function listItemLoading(items) { let template = ""; for (let i = 0; i < items; i++) { template += ` <div class="loadingPlaceholder"> <div class="loadingPlaceholder-wrapper"> <div class="loadingPlaceholder-body"> <table class="loadingPlaceholder-header"> <tr> <td style="width: 45px;"><div class="loadingPlaceholder-avatar"></div></td> <td> <div class="loadingPlaceholder-name"></div> <div class="loadingPlaceholder-date"></div> </td> </tr> </table> </div> </div> </div> `; } return template; } // loading placeholder for avatars function avatarLoading(items) { let template = ""; for (let i = 0; i < items; i++) { template += ` <div class="loadingPlaceholder"> <div class="loadingPlaceholder-wrapper"> <div class="loadingPlaceholder-body"> <table class="loadingPlaceholder-header"> <tr> <td style="width: 45px;"> <div class="loadingPlaceholder-avatar" style="margin: 2px;"></div> </td> </tr> </table> </div> </div> </div> `; } return template; } // While sending a message, show this temporary message card. function sendTempMessageCard(message, id) { return ` <div class="message-card mc-sender" data-id="${id}"> <div class="message-card-content"> <div class="message"> ${message} <sub> <span class="far fa-clock"></span> </sub> </div> </div> </div> `; } // upload image preview card. function attachmentTemplate(fileType, fileName, imgURL = null) { if (fileType != "image") { return ( ` <div class="attachment-preview"> <span class="fas fa-times cancel"></span> <p style="padding:0px 30px;"><span class="fas fa-file"></span> ` + escapeHtml(fileName) + `</p> </div> ` ); } else { return ( ` <div class="attachment-preview"> <span class="fas fa-times cancel"></span> <div class="image-file chat-image" style="background-image: url('` + imgURL + `');"></div> <p><span class="fas fa-file-image"></span> ` + escapeHtml(fileName) + `</p> </div> ` ); } } // Active Status Circle function activeStatusCircle() { return `<span class="activeStatus"></span>`; } /** *------------------------------------------------------------- * Css Media Queries [For responsive design] *------------------------------------------------------------- */ $(window).resize(function () { cssMediaQueries(); }); function cssMediaQueries() { if (window.matchMedia("(min-width: 980px)").matches) { $(".messenger-listView").removeAttr("style"); } if (window.matchMedia("(max-width: 980px)").matches) { $("body") .find(".messenger-list-item") .find("tr[data-action]") .attr("data-action", "1"); $("body").find(".favorite-list-item").find("div").attr("data-action", "1"); } else { $("body") .find(".messenger-list-item") .find("tr[data-action]") .attr("data-action", "0"); $("body").find(".favorite-list-item").find("div").attr("data-action", "0"); } } /** *------------------------------------------------------------- * App Modal *------------------------------------------------------------- */ let app_modal = function ({ show = true, name, data = 0, buttons = true, header = null, body = null, }) { const modal = $(".app-modal[data-name=" + name + "]"); // header header ? modal.find(".app-modal-header").html(header) : ""; // body body ? modal.find(".app-modal-body").html(body) : ""; // buttons buttons == true ? modal.find(".app-modal-footer").show() : modal.find(".app-modal-footer").hide(); // show / hide if (show == true) { modal.show(); $(".app-modal-card[data-name=" + name + "]").addClass("app-show-modal"); $(".app-modal-card[data-name=" + name + "]").attr("data-modal", data); } else { modal.hide(); $(".app-modal-card[data-name=" + name + "]").removeClass("app-show-modal"); $(".app-modal-card[data-name=" + name + "]").attr("data-modal", data); } }; /** *------------------------------------------------------------- * Slide to bottom on [action] - e.g. [message received, sent, loaded] *------------------------------------------------------------- */ function scrollToBottom(container) { $(container) .stop() .animate({ scrollTop: $(container)[0].scrollHeight, }); } /** *------------------------------------------------------------- * click and drag to scroll - function *------------------------------------------------------------- */ function hScroller(scroller) { const slider = document.querySelector(scroller); let isDown = false; let startX; let scrollLeft; slider.addEventListener("mousedown", (e) => { isDown = true; startX = e.pageX - slider.offsetLeft; scrollLeft = slider.scrollLeft; }); slider.addEventListener("mouseleave", () => { isDown = false; }); slider.addEventListener("mouseup", () => { isDown = false; }); slider.addEventListener("mousemove", (e) => { if (!isDown) return; e.preventDefault(); const x = e.pageX - slider.offsetLeft; const walk = (x - startX) * 1; slider.scrollLeft = scrollLeft - walk; }); } /** *------------------------------------------------------------- * Disable/enable message form fields, messaging container... * on load info or if needed elsewhere. * * Default : true *------------------------------------------------------------- */ function disableOnLoad(disable = true) { if (disable) { // hide star button $(".add-to-favorite").hide(); // hide send card $(".messenger-sendCard").hide(); // add loading opacity to messages container messagesContainer.css("opacity", ".5"); // disable message form fields messageInput.attr("readonly", "readonly"); $("#message-form button").attr("disabled", "disabled"); $(".upload-attachment").attr("disabled", "disabled"); } else { // show star button if (getMessengerId() != auth_id) { $(".add-to-favorite").show(); } // show send card $(".messenger-sendCard").show(); // remove loading opacity to messages container messagesContainer.css("opacity", "1"); // enable message form fields messageInput.removeAttr("readonly"); $("#message-form button").removeAttr("disabled"); $(".upload-attachment").removeAttr("disabled"); } } /** *------------------------------------------------------------- * Error message card *------------------------------------------------------------- */ function errorMessageCard(id) { messagesContainer .find(".message-card[data-id=" + id + "]") .addClass("mc-error"); messagesContainer .find(".message-card[data-id=" + id + "]") .find("svg.loadingSVG") .remove(); messagesContainer .find(".message-card[data-id=" + id + "] p") .prepend('<span class="fas fa-exclamation-triangle"></span>'); } /** *------------------------------------------------------------- * Fetch id data (user/group) and update the view *------------------------------------------------------------- */ function IDinfo(id) { // clear temporary message id temporaryMsgId = 0; // clear typing now typingNow = 0; // show loading bar NProgress.start(); // disable message form disableOnLoad(); if (messenger != 0) { // get shared photos getSharedPhotos(id); // Get info $.ajax({ url: url + "/idInfo", method: "POST", data: { _token: csrfToken, id }, dataType: "JSON", success: (data) => { if (!data?.fetch) { NProgress.done(); NProgress.remove(); return; } // avatar photo $(".messenger-infoView") .find(".avatar") .css("background-image", 'url("' + data.user_avatar + '")'); $(".header-avatar").css( "background-image", 'url("' + data.user_avatar + '")' ); // Show shared and actions $(".messenger-infoView-btns .delete-conversation").show(); $(".messenger-infoView-shared").show(); // fetch messages fetchMessages(id, true); // focus on messaging input messageInput.focus(); // update info in view $(".messenger-infoView .info-name").text(data.fetch.name); $(".m-header-messaging .user-name").text(data.fetch.name); // Star status data.favorite > 0 ? $(".add-to-favorite").addClass("favorite") : $(".add-to-favorite").removeClass("favorite"); // form reset and focus $("#message-form").trigger("reset"); cancelAttachment(); messageInput.focus(); }, error: () => { console.error("Couldn't fetch user data!"); // remove loading bar NProgress.done(); NProgress.remove(); }, }); } else { // remove loading bar NProgress.done(); NProgress.remove(); } } /** *------------------------------------------------------------- * Send message function *------------------------------------------------------------- */ function sendMessage() { temporaryMsgId += 1; let tempID = `temp_${temporaryMsgId}`; let hasFile = !!$(".upload-attachment").val(); const inputValue = $.trim(messageInput.val()); if (inputValue.length > 0 || hasFile) { const formData = new FormData($("#message-form")[0]); formData.append("id", getMessengerId()); formData.append("temporaryMsgId", tempID); formData.append("_token", csrfToken); $.ajax({ url: $("#message-form").attr("action"), method: "POST", data: formData, dataType: "JSON", processData: false, contentType: false, beforeSend: () => { // remove message hint $(".messages").find(".message-hint").hide(); // append a temporary message card if (hasFile) { messagesContainer .find(".messages") .append( sendTempMessageCard( inputValue + "\n" + loadingSVG("28px"), tempID ) ); } else { messagesContainer .find(".messages") .append(sendTempMessageCard(inputValue, tempID)); } // scroll to bottom scrollToBottom(messagesContainer); messageInput.css({ height: "42px" }); // form reset and focus $("#message-form").trigger("reset"); cancelAttachment(); messageInput.focus(); }, success: (data) => { if (data.error > 0) { // message card error status errorMessageCard(tempID); console.error(data.error_msg); } else { // update contact item updateContactItem(getMessengerId()); // temporary message card const tempMsgCardElement = messagesContainer.find( `.message-card[data-id=${data.tempID}]` ); // add the message card coming from the server before the temp-card tempMsgCardElement.before(data.message); // then, remove the temporary message card tempMsgCardElement.remove(); // scroll to bottom scrollToBottom(messagesContainer); // send contact item updates sendContactItemUpdates(true); } }, error: () => { // message card error status errorMessageCard(tempID); // error log console.error( "Failed sending the message! Please, check your server response." ); }, }); } return false; } /** *------------------------------------------------------------- * Fetch messages from database *------------------------------------------------------------- */ let messagesPage = 1; let noMoreMessages = false; let messagesLoading = false; function setMessagesLoading(loading = false) { if (!loading) { messagesContainer.find(".messages").find(".loading-messages").remove(); NProgress.done(); NProgress.remove(); } else { messagesContainer .find(".messages") .prepend(loadingWithContainer("loading-messages")); } messagesLoading = loading; } function fetchMessages(id, newFetch = false) { if (newFetch) { messagesPage = 1; noMoreMessages = false; } if (messenger != 0 && !noMoreMessages && !messagesLoading) { const messagesElement = messagesContainer.find(".messages"); setMessagesLoading(true); $.ajax({ url: url + "/fetchMessages", method: "POST", data: { _token: csrfToken, id: id, page: messagesPage, }, dataType: "JSON", success: (data) => { setMessagesLoading(false); if (messagesPage == 1) { messagesElement.html(data.messages); scrollToBottom(messagesContainer); } else { const lastMsg = messagesElement.find( messagesElement.find(".message-card")[0] ); const curOffset = lastMsg.offset().top - messagesContainer.scrollTop(); messagesElement.prepend(data.messages); messagesContainer.scrollTop(lastMsg.offset().top - curOffset); } // trigger seen event makeSeen(true); // Pagination lock & messages page noMoreMessages = messagesPage >= data?.last_page; if (!noMoreMessages) messagesPage += 1; // Enable message form if messenger not = 0; means if data is valid if (messenger != 0) { disableOnLoad(false); } }, error: (error) => { setMessagesLoading(false); console.error(error); }, }); } } /** *------------------------------------------------------------- * Cancel file attached in the message. *------------------------------------------------------------- */ function cancelAttachment() { $(".messenger-sendCard").find(".attachment-preview").remove(); $(".upload-attachment").replaceWith( $(".upload-attachment").val("").clone(true) ); } /** *------------------------------------------------------------- * Cancel updating avatar in settings *------------------------------------------------------------- */ function cancelUpdatingAvatar() { $(".upload-avatar-preview").css("background-image", defaultAvatarInSettings); $(".upload-avatar").replaceWith($(".upload-avatar").val("").clone(true)); } /** *------------------------------------------------------------- * Pusher channels and event listening.. *------------------------------------------------------------- */ // subscribe to the channel const channelName = "private-chatify"; var channel = pusher.subscribe(`${channelName}.${auth_id}`); var clientSendChannel; var clientListenChannel; function initClientChannel() { if (getMessengerId()) { clientSendChannel = pusher.subscribe(`${channelName}.${getMessengerId()}`); clientListenChannel = pusher.subscribe(`${channelName}.${auth_id}`); } } initClientChannel(); // Listen to messages, and append if data received channel.bind("messaging", function (data) { if (data.from_id == getMessengerId() && data.to_id == auth_id) { $(".messages").find(".message-hint").remove(); messagesContainer.find(".messages").append(data.message); scrollToBottom(messagesContainer); makeSeen(true); // remove unseen counter for the user from the contacts list $(".messenger-list-item[data-contact=" + getMessengerId() + "]") .find("tr>td>b") .remove(); } playNotificationSound( "new_message", !(data.from_id == getMessengerId() && data.to_id == auth_id) ); }); // listen to typing indicator clientListenChannel.bind("client-typing", function (data) { if (data.from_id == getMessengerId() && data.to_id == auth_id) { data.typing == true ? messagesContainer.find(".typing-indicator").show() : messagesContainer.find(".typing-indicator").hide(); } // scroll to bottom scrollToBottom(messagesContainer); }); // listen to seen event clientListenChannel.bind("client-seen", function (data) { if (data.from_id == getMessengerId() && data.to_id == auth_id) { if (data.seen == true) { $(".message-time") .find(".fa-check") .before('<span class="fas fa-check-double seen"></span> '); $(".message-time").find(".fa-check").remove(); } } }); // listen to contact item updates event clientListenChannel.bind("client-contactItem", function (data) { if (data.to == auth_id) { if (data.update) { updateContactItem(data.from); } else { console.error("Can not update contact item!"); } } }); // listen on message delete event clientListenChannel.bind("client-messageDelete", function (data) { $("body").find(`.message-card[data-id=${data.id}]`).remove(); }); // listen on delete conversation event clientListenChannel.bind("client-deleteConversation", function (data) { if (data.from == getMessengerId() && data.to == auth_id) { $("body").find(`.messages`).html(""); $(".messages").find(".message-hint").show(); } }); // ------------------------------------- // presence channel [User Active Status] var activeStatusChannel = pusher.subscribe("presence-activeStatus"); // Joined activeStatusChannel.bind("pusher:member_added", function (member) { setActiveStatus(1); $(".messenger-list-item[data-contact=" + member.id + "]") .find(".activeStatus") .remove(); $(".messenger-list-item[data-contact=" + member.id + "]") .find(".avatar") .before(activeStatusCircle()); }); // Leaved activeStatusChannel.bind("pusher:member_removed", function (member) { setActiveStatus(0); $(".messenger-list-item[data-contact=" + member.id + "]") .find(".activeStatus") .remove(); }); function handleVisibilityChange() { if (!document.hidden) { makeSeen(true); } } document.addEventListener("visibilitychange", handleVisibilityChange, false); /** *------------------------------------------------------------- * Trigger typing event *------------------------------------------------------------- */ function isTyping(status) { return clientSendChannel.trigger("client-typing", { from_id: auth_id, // Me to_id: getMessengerId(), // Messenger typing: status, }); } /** *------------------------------------------------------------- * Trigger seen event *------------------------------------------------------------- */ function makeSeen(status) { if (document?.hidden) { return; } // remove unseen counter for the user from the contacts list $(".messenger-list-item[data-contact=" + getMessengerId() + "]") .find("tr>td>b") .remove(); // seen $.ajax({ url: url + "/makeSeen", method: "POST", data: { _token: csrfToken, id: getMessengerId() }, dataType: "JSON", }); return clientSendChannel.trigger("client-seen", { from_id: auth_id, // Me to_id: getMessengerId(), // Messenger seen: status, }); } /** *------------------------------------------------------------- * Trigger contact item updates *------------------------------------------------------------- */ function sendContactItemUpdates(status) { return clientSendChannel.trigger("client-contactItem", { from: auth_id, // Me to: getMessengerId(), // Messenger update: status, }); } /** *------------------------------------------------------------- * Trigger message delete *------------------------------------------------------------- */ function sendMessageDeleteEvent(messageId) { return clientSendChannel.trigger("client-messageDelete", { id: messageId, }); } /** *------------------------------------------------------------- * Trigger delete conversation *------------------------------------------------------------- */ function sendDeleteConversationEvent() { return clientSendChannel.trigger("client-deleteConversation", { from: auth_id, to: getMessengerId(), }); } /** *------------------------------------------------------------- * Check internet connection using pusher states *------------------------------------------------------------- */ function checkInternet(state, selector) { let net_errs = 0; const messengerTitle = $(".messenger-headTitle"); switch (state) { case "connected": if (net_errs < 1) { messengerTitle.text(messengerTitleDefault); selector.addClass("successBG-rgba"); selector.find("span").hide(); selector.slideDown("fast", function () { selector.find(".ic-connected").show(); }); setTimeout(function () { $(".internet-connection").slideUp("fast"); }, 3000); } break; case "connecting": messengerTitle.text($(".ic-connecting").text()); selector.removeClass("successBG-rgba"); selector.find("span").hide(); selector.slideDown("fast", function () { selector.find(".ic-connecting").show(); }); net_errs = 1; break; // Not connected default: messengerTitle.text($(".ic-noInternet").text()); selector.removeClass("successBG-rgba"); selector.find("span").hide(); selector.slideDown("fast", function() { selector.find(".ic-noInternet").show(); }); net_errs = 1; break; } } /** *------------------------------------------------------------- * Get contacts *------------------------------------------------------------- */ let contactsPage = 1; let contactsLoading = false; let noMoreContacts = false; function setContactsLoading(loading = false) { if (!loading) { $(".listOfContacts").find(".loading-contacts").remove(); } else { $(".listOfContacts").append( `<div class="loading-contacts">${listItemLoading(4)}</div>` ); } contactsLoading = loading; } function getContacts(user_id) { if (typeof user_id == 'undefined') user_id = ''; if (!contactsLoading && !noMoreContacts) { setContactsLoading(true); $.ajax({ url: url + '/getContacts?user_id=' + user_id, method: "GET", data: { _token: csrfToken, page: contactsPage }, dataType: "JSON", success: (data) => { setContactsLoading(false); if (contactsPage < 2) { $(".listOfContacts").html(data.contacts); } else { $(".listOfContacts").append(data.contacts); } updateSelectedContact(); // update data-action required with [responsive design] cssMediaQueries(); // Pagination lock & messages page noMoreContacts = contactsPage >= data?.last_page; if (!noMoreContacts) contactsPage += 1; }, error: (error) => { setContactsLoading(false); console.error(error); }, }); } } /** *------------------------------------------------------------- * Update contact item *------------------------------------------------------------- */ function updateContactItem(user_id) { if (user_id != auth_id) { $.ajax({ url: url + "/updateContacts", method: "POST", data: { _token: csrfToken, user_id, }, dataType: "JSON", success: (data) => { $(".listOfContacts") .find(".messenger-list-item[data-contact=" + user_id + "]") .remove(); if (data.contactItem) $(".listOfContacts").prepend(data.contactItem); if (user_id == getMessengerId()) updateSelectedContact(user_id); // show/hide message hint (empty state message) const totalContacts = $(".listOfContacts").find(".messenger-list-item")?.length || 0; if (totalContacts > 0) { $(".listOfContacts").find(".message-hint").hide(); } else { $(".listOfContacts").find(".message-hint").show(); } // update data-action required with [responsive design] cssMediaQueries(); }, error: (error) => { console.error(error); }, }); } } /** *------------------------------------------------------------- * Star *------------------------------------------------------------- */ function star(user_id) { if (getMessengerId() != auth_id) { $.ajax({ url: url + "/star", method: "POST", data: { _token: csrfToken, user_id: user_id }, dataType: "JSON", success: (data) => { data.status > 0 ? $(".add-to-favorite").addClass("favorite") : $(".add-to-favorite").removeClass("favorite"); }, error: () => { console.error("Server error, check your response"); }, }); } } /** *------------------------------------------------------------- * Get favorite list *------------------------------------------------------------- */ function getFavoritesList() { $(".messenger-favorites").html(avatarLoading(4)); $.ajax({ url: url + "/favorites", method: "POST", data: { _token: csrfToken }, dataType: "JSON", success: (data) => { if (data.count > 0) { $(".favorites-section").show(); $(".messenger-favorites").html(data.favorites); } else { $(".favorites-section").hide(); } // update data-action required with [responsive design] cssMediaQueries(); }, error: () => { console.error("Server error, check your response"); }, }); } /** *------------------------------------------------------------- * Get shared photos *------------------------------------------------------------- */ function getSharedPhotos(user_id) { $.ajax({ url: url + "/shared", method: "POST", data: { _token: csrfToken, user_id: user_id }, dataType: "JSON", success: (data) => { $(".shared-photos-list").html(data.shared); }, error: () => { console.error("Server error, check your response"); }, }); } /** *------------------------------------------------------------- * Search in messenger *------------------------------------------------------------- */ let searchPage = 1; let noMoreDataSearch = false; let searchLoading = false; let searchTempVal = ""; function setSearchLoading(loading = false) { if (!loading) { $(".search-records").find(".loading-search").remove(); } else { $(".search-records").append( `<div class="loading-search">${listItemLoading(4)}</div>` ); } searchLoading = loading; } function messengerSearch(input) { if (input != searchTempVal) { searchPage = 1; noMoreDataSearch = false; searchLoading = false; } searchTempVal = input; if (!searchLoading && !noMoreDataSearch) { if (searchPage < 2) { $(".search-records").html(""); } setSearchLoading(true); $.ajax({ url: url + "/search", method: "GET", data: { _token: csrfToken, input: input, page: searchPage }, dataType: "JSON", success: (data) => { setSearchLoading(false); if (searchPage < 2) { $(".search-records").html(data.records); } else { $(".search-records").append(data.records); } // update data-action required with [responsive design] cssMediaQueries(); // Pagination lock & messages page noMoreDataSearch = searchPage >= data?.last_page; if (!noMoreDataSearch) searchPage += 1; }, error: (error) => { setSearchLoading(false); console.error(error); }, }); } } /** *------------------------------------------------------------- * Delete Conversation *------------------------------------------------------------- */ function deleteConversation(id) { $.ajax({ url: url + "/deleteConversation", method: "POST", data: { _token: csrfToken, id: id }, dataType: "JSON", beforeSend: () => { // hide delete modal app_modal({ show: false, name: "delete", }); // Show waiting alert modal app_modal({ show: true, name: "alert", buttons: false, body: loadingSVG("32px", null, "margin:auto"), }); }, success: (data) => { // delete contact from the list $(".listOfContacts") .find(".messenger-list-item[data-contact=" + id + "]") .remove(); // refresh info IDinfo(id); if (!data.deleted) return alert("Error occurred, messages can not be deleted!"); // Hide waiting alert modal app_modal({ show: false, name: "alert", buttons: true, body: "", }); sendDeleteConversationEvent(); // update contact list item sendContactItemUpdates(true); }, error: () => { console.error("Server error, check your response"); }, }); } /** *------------------------------------------------------------- * Delete Message By ID *------------------------------------------------------------- */ function deleteMessage(id) { $.ajax({ url: url + "/deleteMessage", method: "POST", data: { _token: csrfToken, id: id }, dataType: "JSON", beforeSend: () => { // hide delete modal app_modal({ show: false, name: "delete", }); // Show waiting alert modal app_modal({ show: true, name: "alert", buttons: false, body: loadingSVG("32px", null, "margin:auto"), }); }, success: (data) => { $(".messages").find(`.message-card[data-id=${id}]`).remove(); if (!data.deleted) console.error("Error occurred, message can not be deleted!"); sendMessageDeleteEvent(id); // Hide waiting alert modal app_modal({ show: false, name: "alert", buttons: true, body: "", }); }, error: () => { console.error("Server error, check your response"); }, }); } /** *------------------------------------------------------------- * Update Settings *------------------------------------------------------------- */ function updateSettings() { const formData = new FormData($("#update-settings")[0]); if (messengerColor) { formData.append("messengerColor", messengerColor); } if (dark_mode) { formData.append("dark_mode", dark_mode); } $.ajax({ url: url + "/updateSettings", method: "POST", data: formData, dataType: "JSON", processData: false, contentType: false, beforeSend: () => { // close settings modal app_modal({ show: false, name: "settings", }); // Show waiting alert modal app_modal({ show: true, name: "alert", buttons: false, body: loadingSVG("32px", null, "margin:auto"), }); }, success: (data) => { if (data.error) { // Show error message in alert modal app_modal({ show: true, name: "alert", buttons: true, body: data.msg, }); } else { // Hide alert modal app_modal({ show: false, name: "alert", buttons: true, body: "", }); // reload the page location.reload(true); } }, error: () => { console.error("Server error, check your response"); }, }); } /** *------------------------------------------------------------- * Set Active status *------------------------------------------------------------- */ function setActiveStatus(status) { $.ajax({ url: url + "/setActiveStatus", method: "POST", data: { _token: csrfToken, status: status }, dataType: "JSON", success: (data) => { // Nothing to do }, error: () => { console.error("Server error, check your response"); }, }); } /** *------------------------------------------------------------- * On DOM ready *------------------------------------------------------------- */ $(document).ready(function () { // get contacts list getContacts(window.tmp_user_id); // get contacts list getFavoritesList(); // Clear typing timeout clearTimeout(typingTimeout); // NProgress configurations NProgress.configure({ showSpinner: false, minimum: 0.7, speed: 500 }); // make message input autosize. autosize($(".m-send")); // check if pusher has access to the channel [Internet status] pusher.connection.bind("state_change", function (states) { let selector = $(".internet-connection"); checkInternet(states.current, selector); // listening for pusher:subscription_succeeded channel.bind("pusher:subscription_succeeded", function () { // On connection state change [Updating] and get [info & msgs] if (getMessengerId() != 0) { if ( $(".messenger-list-item") .find("tr[data-action]") .attr("data-action") == "1" ) { $(".messenger-listView").hide(); } IDinfo(getMessengerId()); } }); }); // tabs on click, show/hide... $(".messenger-listView-tabs a").on("click", function () { var dataView = $(this).attr("data-view"); $(".messenger-listView-tabs a").removeClass("active-tab"); $(this).addClass("active-tab"); $(".messenger-tab").hide(); $(".messenger-tab[data-view=" + dataView + "]").show(); }); // set item active on click $("body").on("click", ".messenger-list-item", function () { $(".messenger-list-item").removeClass("m-list-active"); $(this).addClass("m-list-active"); const userID = $(this).attr("data-contact"); routerPush(document.title, `${url}/${userID}`); updateSelectedContact(userID); }); // show info side button $(".messenger-infoView nav a , .show-infoSide").on("click", function () { $(".messenger-infoView").toggle(); }); // make favorites card dragable on click to slide. hScroller(".messenger-favorites"); // click action for list item [user/group] $("body").on("click", ".messenger-list-item", function () { if ($(this).find("tr[data-action]").attr("data-action") == "1") { $(".messenger-listView").hide(); } const dataId = $(this).find("p[data-id]").attr("data-id"); setMessengerId(dataId); IDinfo(dataId); }); // click action for favorite button $("body").on("click", ".favorite-list-item", function () { if ($(this).find("div").attr("data-action") == "1") { $(".messenger-listView").hide(); } const uid = $(this).find("div.avatar").attr("data-id"); setMessengerId(uid); IDinfo(uid); updateSelectedContact(uid); routerPush(document.title, `${url}/${uid}`); }); // list view buttons $(".listView-x").on("click", function () { $(".messenger-listView").hide(); }); $(".show-listView").on("click", function () { routerPush(document.title, `${url}/`); $(".messenger-listView").show(); }); // click action for [add to favorite] button. $(".add-to-favorite").on("click", function () { star(getMessengerId()); }); // calling Css Media Queries cssMediaQueries(); // message form on submit. $("#message-form").on("submit", (e) => { e.preventDefault(); sendMessage(); }); // message input on keyup [Enter to send, Enter+Shift for new line] $("#message-form .m-send").on("keyup", (e) => { // if enter key pressed. if (e.which == 13 || e.keyCode == 13) { // if shift + enter key pressed, do nothing (new line). // if only enter key pressed, send message. if (!e.shiftKey) { triggered = isTyping(false); sendMessage(); } } }); // On [upload attachment] input change, show a preview of the image/file. $("body").on("change", ".upload-attachment", (e) => { let file = e.target.files[0]; if (!attachmentValidate(file)) return false; let reader = new FileReader(); let sendCard = $(".messenger-sendCard"); reader.readAsDataURL(file); reader.addEventListener("loadstart", (e) => { $("#message-form").before(loadingSVG()); }); reader.addEventListener("load", (e) => { $(".messenger-sendCard").find(".loadingSVG").remove(); if (!file.type.match("image.*")) { // if the file not image sendCard.find(".attachment-preview").remove(); // older one sendCard.prepend(attachmentTemplate("file", file.name)); } else { // if the file is an image sendCard.find(".attachment-preview").remove(); // older one sendCard.prepend( attachmentTemplate("image", file.name, e.target.result) ); } }); }); function attachmentValidate(file) { const fileElement = $(".upload-attachment"); const { name: fileName, size: fileSize } = file; const fileExtension = fileName.split(".").pop(); if ( !chatify.allAllowedExtensions.includes( fileExtension.toString().toLowerCase() ) ) { alert("file type not allowed"); fileElement.val(""); return false; } // Validate file size. if (fileSize > chatify.maxUploadSize) { alert("File is too large!"); return false; } return true; } // Attachment preview cancel button. $("body").on("click", ".attachment-preview .cancel", () => { cancelAttachment(); }); // typing indicator on [input] keyDown $("#message-form .m-send").on("keydown", () => { if (typingNow < 1) { isTyping(true); typingNow = 1; } clearTimeout(typingTimeout); typingTimeout = setTimeout(function () { isTyping(false); typingNow = 0; }, 1000); }); // Image modal $("body").on("click", ".chat-image", function () { let src = $(this).css("background-image").split(/"/)[1]; $("#imageModalBox").show(); $("#imageModalBoxSrc").attr("src", src); }); $(".imageModal-close").on("click", function () { $("#imageModalBox").hide(); }); // Search input on focus $(".messenger-search").on("focus", function () { $(".messenger-tab").hide(); $('.messenger-tab[data-view="search"]').show(); }); $(".messenger-search").on("blur", function () { setTimeout(function () { $(".messenger-tab").hide(); $('.messenger-tab[data-view="users"]').show(); }, 200); }); // Search action on keyup const debouncedSearch = debounce(function () { const value = $(".messenger-search").val(); messengerSearch(value); }, 500); $(".messenger-search").on("keyup", function (e) { const value = $(this).val(); if ($.trim(value).length > 0) { $(".messenger-search").trigger("focus"); debouncedSearch(); } else { $(".messenger-tab").hide(); $('.messenger-listView-tabs a[data-view="users"]').trigger("click"); } }); // Delete Conversation button $(".messenger-infoView-btns .delete-conversation").on("click", function () { app_modal({ name: "delete", }); }); // Delete Message Button $("body").on("click", ".message-card .actions .delete-btn", function () { app_modal({ name: "delete", data: $(this).data("id"), }); }); // Delete modal [on delete button click] $(".app-modal[data-name=delete]") .find(".app-modal-footer .delete") .on("click", function () { const id = $("body") .find(".app-modal[data-name=delete]") .find(".app-modal-card") .attr("data-modal"); if (id == 0) { deleteConversation(getMessengerId()); } else { deleteMessage(id); } app_modal({ show: false, name: "delete", }); }); // delete modal [cancel button] $(".app-modal[data-name=delete]") .find(".app-modal-footer .cancel") .on("click", function () { app_modal({ show: false, name: "delete", }); }); // Settings button action to show settings modal $("body").on("click", ".settings-btn", function (e) { e.preventDefault(); app_modal({ show: true, name: "settings", }); }); // on submit settings' form $("#update-settings").on("submit", (e) => { e.preventDefault(); updateSettings(); }); // Settings modal [cancel button] $(".app-modal[data-name=settings]") .find(".app-modal-footer .cancel") .on("click", function () { app_modal({ show: false, name: "settings", }); cancelUpdatingAvatar(); }); // upload avatar on change $("body").on("change", ".upload-avatar", (e) => { // store the original avatar if (defaultAvatarInSettings == null) { defaultAvatarInSettings = $(".upload-avatar-preview").css( "background-image" ); } let file = e.target.files[0]; if (!attachmentValidate(file)) return false; let reader = new FileReader(); reader.readAsDataURL(file); reader.addEventListener("loadstart", (e) => { $(".upload-avatar-preview").append( loadingSVG("42px", "upload-avatar-loading") ); }); reader.addEventListener("load", (e) => { $(".upload-avatar-preview").find(".loadingSVG").remove(); if (!file.type.match("image.*")) { // if the file is not an image console.error("File you selected is not an image!"); } else { // if the file is an image $(".upload-avatar-preview").css( "background-image", 'url("' + e.target.result + '")' ); } }); }); // change messenger color button $("body").on("click", ".update-messengerColor .color-btn", function () { messengerColor = $(this).attr("data-color"); $(".update-messengerColor .color-btn").removeClass("m-color-active"); $(this).addClass("m-color-active"); }); // Switch to Dark/Light mode $("body").on("click", ".dark-mode-switch", function () { if ($(this).attr("data-mode") == "0") { $(this).attr("data-mode", "1"); $(this).removeClass("far"); $(this).addClass("fas"); dark_mode = "dark"; } else { $(this).attr("data-mode", "0"); $(this).removeClass("fas"); $(this).addClass("far"); dark_mode = "light"; } }); //Messages pagination actionOnScroll( ".m-body.messages-container", function () { fetchMessages(getMessengerId()); }, true ); //Contacts pagination actionOnScroll(".messenger-tab.users-tab", function () { getContacts(); }); //Search pagination actionOnScroll(".messenger-tab.search-tab", function () { messengerSearch($(".messenger-search").val()); }); }); /** *------------------------------------------------------------- * Observer on DOM changes *------------------------------------------------------------- */ let previousMessengerId = getMessengerId(); const observer = new MutationObserver(function (mutations) { if (getMessengerId() !== previousMessengerId) { previousMessengerId = getMessengerId(); initClientChannel(); } }); const config = { subtree: true, childList: true }; // start listening to changes observer.observe(document, config); // stop listening to changes // observer.disconnect(); /** *------------------------------------------------------------- * Resize messaging area when resize the viewport. * on mobile devices when the keyboard is shown, the viewport * height is changed, so we need to resize the messaging area * to fit the new height. *------------------------------------------------------------- */ var resizeTimeout; window.visualViewport.addEventListener("resize", (e) => { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(function () { const h = e.target.height; if (h) { $(".messenger-messagingView").css({ height: h + "px" }); } }, 100); }); /** *------------------------------------------------------------- * Emoji Picker *------------------------------------------------------------- */ const emojiButton = document.querySelector(".emoji-button"); const emojiPicker = new EmojiButton({ theme: messengerTheme, autoHide: false, position: "top-start", }); emojiButton.addEventListener("click", (e) => { e.preventDefault(); emojiPicker.togglePicker(emojiButton); }); emojiPicker.on("emoji", (emoji) => { const el = messageInput[0]; const startPos = el.selectionStart; const endPos = el.selectionEnd; const value = messageInput.val(); const newValue = value.substring(0, startPos) + emoji + value.substring(endPos, value.length); messageInput.val(newValue); el.selectionStart = el.selectionEnd = startPos + emoji.length; el.focus(); }); /** *------------------------------------------------------------- * Notification sounds *------------------------------------------------------------- */ function playNotificationSound(soundName, condition = false) { if ((document.hidden || condition) && chatify.sounds.enabled) { const sound = new Audio( `/${chatify.sounds.public_path}/${chatify.sounds[soundName]}` ); sound.play(); } } /** *------------------------------------------------------------- * Update and format dates to time ago. *------------------------------------------------------------- */ function updateElementsDateToTimeAgo() { $(".message-time").each(function () { const time = $(this).attr("data-time"); $(this).find(".time").text(dateStringToTimeAgo(time)); }); $(".contact-item-time").each(function () { const time = $(this).attr("data-time"); $(this).text(dateStringToTimeAgo(time)); }); } setInterval(() => { updateElementsDateToTimeAgo(); }, 60000);
Simpan