diff options
author | Mario <mario@mariovavti.com> | 2024-12-19 18:49:07 +0000 |
---|---|---|
committer | Mario <mario@mariovavti.com> | 2024-12-19 18:49:07 +0000 |
commit | a2dde34b1be35282618035652f919c39199beea1 (patch) | |
tree | 128d7fb247fc463cc5dc403da8ecc1928c138c29 /view/tpl | |
parent | fb5824417e12710572b8786f1db2e75457819447 (diff) | |
download | volse-hubzilla-a2dde34b1be35282618035652f919c39199beea1.tar.gz volse-hubzilla-a2dde34b1be35282618035652f919c39199beea1.tar.bz2 volse-hubzilla-a2dde34b1be35282618035652f919c39199beea1.zip |
refactor notifications widget and updateConvItems() to not require jquery
Diffstat (limited to 'view/tpl')
-rw-r--r-- | view/tpl/notifications_widget.tpl | 758 |
1 files changed, 462 insertions, 296 deletions
diff --git a/view/tpl/notifications_widget.tpl b/view/tpl/notifications_widget.tpl index c1d7edd66..1ad054d37 100644 --- a/view/tpl/notifications_widget.tpl +++ b/view/tpl/notifications_widget.tpl @@ -8,42 +8,52 @@ var sse_sys_only = {{$sys_only}}; $(document).ready(function() { - let notifications_parent; - if ($('#notifications_wrapper').length) { - notifications_parent = $('#notifications_wrapper')[0].parentElement.id; - } - - $('.notifications-btn').click(function() { - $('#notifications_wrapper').removeClass('d-none'); - - if($('#notifications_wrapper').hasClass('fs')) { - $('#notifications_wrapper').prependTo('#' + notifications_parent); - $('#notifications_wrapper').addClass('d-none'); + let notificationsWrapper = document.getElementById('notifications_wrapper'); + let notificationsParent = notificationsWrapper.parentElement.id; + let notificationsBtn = document.querySelector('.notifications-btn'); + + // Event listener for notifications button + if (notificationsBtn) { + notificationsBtn.addEventListener('click', function() { + // Remove the 'd-none' class to show the notifications wrapper + notificationsWrapper.classList.remove('d-none'); + + // Check if the notifications wrapper has the 'fs' class + if (notificationsWrapper.classList.contains('fs')) { + // Prepend the notifications wrapper back to its original parent and hide it + document.getElementById(notificationsParent).appendChild(notificationsWrapper); + notificationsWrapper.classList.add('d-none'); + } else { + // Otherwise, prepend the notifications wrapper to 'main' + document.querySelector('main').prepend(notificationsWrapper); + } - } - else { - $('#notifications_wrapper').prependTo('main'); - } + // Toggle the 'fs' class + notificationsWrapper.classList.toggle('fs'); + }); + } - $('#notifications_wrapper').toggleClass('fs'); - if($('#navbar-collapse-2').hasClass('show')){ - $('#navbar-collapse-2').removeClass('show'); - } - }); + // Event listener for clicking a notification + document.addEventListener('click', function(event) { + if (event.target.closest('a') && event.target.closest('a').classList.contains('notification')) { + console.log(1) + if (notificationsWrapper.classList.contains('fs')) { + // Move notifications wrapper back to its original parent and hide it + notificationsWrapper.classList.remove('fs'); + notificationsWrapper.classList.add('d-none'); + document.getElementById(notificationsParent).appendChild(notificationsWrapper); - $(document).on('click', '.notification', function() { - if($('#notifications_wrapper').hasClass('fs')) { - $('#notifications_wrapper').prependTo('#' + notifications_parent).removeClass('fs').addClass('d-none'); + } } }); if(sse_enabled) { if(typeof(window.SharedWorker) === 'undefined') { // notifications with multiple tabs open will not work very well in this scenario - var evtSource = new EventSource('/sse'); + let evtSource = new EventSource('/sse'); evtSource.addEventListener('notifications', function(e) { - var obj = JSON.parse(e.data); + let obj = JSON.parse(e.data); sse_handleNotifications(obj, false, false); }, false); @@ -56,7 +66,7 @@ } else { - var myWorker = new SharedWorker('/view/js/sse_worker.js', localUser); + let myWorker = new SharedWorker('/view/js/sse_worker.js', localUser); myWorker.port.onmessage = function(e) { obj = e.data; @@ -72,8 +82,9 @@ } } else { - if (!document.hidden) + if (!document.hidden) { sse_fallback_interval = setInterval(sse_fallback, updateInterval); + } document.addEventListener('visibilitychange', function() { if (document.hidden) { @@ -88,234 +99,338 @@ }, false); } - $('.notification-link').on('click', { replace: true, followup: false }, sse_bs_notifications); - - $('.notification-filter').on('keypress', function(e) { - if(e.which == 13) { // enter - this.blur(); - sse_offset = 0; - $("#nav-" + sse_type + "-menu").html(''); - $("#nav-" + sse_type + "-loading").show(); - - var cn_val = $('#cn-' + sse_type + '-input').length ? $('#cn-' + sse_type + '-input').val().toString().toLowerCase() : ''; - - $.get('/sse_bs/' + sse_type + '/' + sse_offset + '?nquery=' + encodeURIComponent(cn_val), function(obj) { - console.log('sse: bootstraping ' + sse_type); - console.log(obj); - - sse_bs_active = false; - sse_partial_result = true; - sse_offset = obj[sse_type].offset; - if(sse_offset < 0) - $("#nav-" + sse_type + "-loading").hide(); + document.querySelectorAll('.notification-link').forEach(function (element) { + element.addEventListener('click', function (element) { + sse_bs_notifications(element, true, false); + }); + }); - sse_handleNotifications(obj, true, false); + document.querySelectorAll('.notification-filter').forEach(function (element) { + element.addEventListener('keypress', function(e) { + if (e.which == 13) { // Enter key + this.blur(); + sse_offset = 0; - }); - } + // Clear the content of the menu + document.getElementById("nav-" + sse_type + "-menu").innerHTML = ''; + + // Show the loading element + document.getElementById("nav-" + sse_type + "-loading").style.display = 'block'; + + // Get the value from the input element + var cn_val = document.getElementById('cn-' + sse_type + '-input') ? document.getElementById('cn-' + sse_type + '-input').value.toString().toLowerCase() : ''; + + // Send a GET request using the Fetch API + fetch('/sse_bs/' + sse_type + '/' + sse_offset + '?nquery=' + encodeURIComponent(cn_val)) + .then(response => response.json()) + .then(obj => { + console.log('sse: bootstraping ' + sse_type); + console.log(obj); + + sse_bs_active = false; + sse_partial_result = true; + sse_offset = obj[sse_type].offset; + if (sse_offset < 0) { + document.getElementById("nav-" + sse_type + "-loading").style.display = 'none'; + } + + sse_handleNotifications(obj, true, false); + }) + .catch(error => { + console.error('Error fetching data:', error); + }); + } + }); }); - $('.notifications-textinput-clear').on('click', function(e) { - if(! sse_partial_result) - return; + document.querySelectorAll('.notifications-textinput-clear').forEach(function (element) { + element.addEventListener('click', function(e) { + if (!sse_partial_result) return; - $("#nav-" + sse_type + "-menu").html(''); - $("#nav-" + sse_type + "-loading").show(); - $.get('/sse_bs/' + sse_type, function(obj) { - console.log('sse: bootstraping ' + sse_type); - console.log(obj); + // Clear the content of the menu + document.getElementById("nav-" + sse_type + "-menu").innerHTML = ''; + + // Show the loading element + document.getElementById("nav-" + sse_type + "-loading").style.display = 'block'; - sse_bs_active = false; - sse_partial_result = false; - sse_offset = obj[sse_type].offset; - if(sse_offset < 0) - $("#nav-" + sse_type + "-loading").hide(); + // Send a GET request using the Fetch API + fetch('/sse_bs/' + sse_type) + .then(response => response.json()) + .then(obj => { + console.log('sse: bootstraping ' + sse_type); + console.log(obj); - sse_handleNotifications(obj, true, false); + sse_bs_active = false; + sse_partial_result = false; + sse_offset = obj[sse_type].offset; + if (sse_offset < 0) { + document.getElementById("nav-" + sse_type + "-loading").style.display = 'none'; + } + sse_handleNotifications(obj, true, false); + }) + .catch(error => { + console.error('Error fetching data:', error); + }); }); }); - $('.notification-content').on('scroll', function() { - if(this.scrollTop > this.scrollHeight - this.clientHeight - (this.scrollHeight/7)) { - sse_bs_notifications(sse_type, false, true); - } + document.querySelectorAll('.notification-content').forEach(function(element) { + element.addEventListener('scroll', function() { + if (this.scrollTop > this.scrollHeight - this.clientHeight - (this.scrollHeight / 7)) { + sse_bs_notifications(sse_type, false, true); + } + }); }); }); - $(document).on('hz:sse_setNotificationsStatus', function(e, data) { - sse_setNotificationsStatus(data); + document.addEventListener('hz:sse_setNotificationsStatus', function(e) { + sse_setNotificationsStatus(e.detail); }); - $(document).on('hz:sse_bs_init', function() { + document.addEventListener('hz:sse_bs_init', function() { sse_bs_init(); }); - $(document).on('hz:sse_bs_counts', function() { + document.addEventListener('hz:sse_bs_counts', function() { sse_bs_counts(); }); + {{foreach $notifications as $notification}} {{if $notification.filter}} - $(document).on('click', '#tt-{{$notification.type}}-only', function(e) { - if($(this).hasClass('active sticky-top')) { - $('#nav-{{$notification.type}}-menu .notification[data-thread_top=false]').removeClass('tt-filter-active'); - $(this).removeClass('active sticky-top'); - } - else { - $('#nav-{{$notification.type}}-menu .notification[data-thread_top=false]').addClass('tt-filter-active'); - $(this).addClass('active sticky-top'); - // load more notifications if visible notifications count is low - if(sse_type && sse_offset != -1 && $('#nav-' + sse_type + '-menu').children(':visible').length < 15) { - sse_bs_notifications(sse_type, false, true); + document.addEventListener('click', function(e) { + if (e.target.closest('div').matches('#tt-{{$notification.type}}-only')) { + let element = e.target.closest('div'); + let menu = document.querySelector('#nav-{{$notification.type}}-menu'); + let notifications = menu.querySelectorAll('.notification[data-thread_top="false"]'); + + // Function to check if an element is visible + function isVisible(el) { + return el.offsetWidth > 0 && el.offsetHeight > 0; } - } - }); + if (element.classList.contains('active') && element.classList.contains('sticky-top')) { + notifications.forEach(function(notification) { + notification.classList.remove('tt-filter-active'); + }); + element.classList.remove('active', 'sticky-top'); + } else { + notifications.forEach(function(notification) { + notification.classList.add('tt-filter-active'); + }); + element.classList.add('active', 'sticky-top'); - $(document).on('click', '#cn-{{$notification.type}}-input-clear', function(e) { - $('#cn-{{$notification.type}}-input').val(''); - $('#cn-{{$notification.type}}-only').removeClass('active sticky-top'); - $("#nav-{{$notification.type}}-menu .notification").removeClass('cn-filter-active'); - $('#cn-{{$notification.type}}-input-clear').addClass('d-none'); - }); + // Count the visible notifications + let visibleNotifications = Array.from(menu.querySelectorAll('.notification')).filter(isVisible).length; - $(document).on('input', '#cn-{{$notification.type}}-input', function(e) { - var val = $('#cn-{{$notification.type}}-input').val().toString().toLowerCase(); - if(val) { - val = val.indexOf('%') == 0 ? val.substring(1) : val; - $('#cn-{{$notification.type}}-only').addClass('active sticky-top'); - $('#cn-{{$notification.type}}-input-clear').removeClass('d-none'); + // Load more notifications if the visible count is low + if (sse_type && sse_offset !== -1 && visibleNotifications < 15) { + sse_bs_notifications(sse_type, false, true); + } + } } - else { - $('#cn-{{$notification.type}}-only').removeClass('active sticky-top'); - $('#cn-{{$notification.type}}-input-clear').addClass('d-none'); + + if (e.target.closest('div').matches('#cn-{{$notification.type}}-input-clear')) { + // Clear the input value + let input = document.querySelector('#cn-{{$notification.type}}-input'); + input.value = ''; + + // Remove the 'active' and 'sticky-top' classes from the clear button + let clearButton = e.target; + clearButton.classList.remove('active', 'sticky-top'); + + // Remove the 'cn-filter-active' class from all notifications + let notifications = document.querySelectorAll("#nav-{{$notification.type}}-menu .notification"); + notifications.forEach(function(notification) { + notification.classList.remove('cn-filter-active'); + }); + + // Add the 'd-none' class to hide the clear button + clearButton.classList.add('d-none'); } - $("#nav-{{$notification.type}}-menu .notification").each(function(i, el){ - var cn = $(el).data('contact_name').toString().toLowerCase(); - var ca = $(el).data('contact_addr').toString().toLowerCase(); + }); - if(cn.indexOf(val) === -1 && ca.indexOf(val) === -1) - $(this).addClass('cn-filter-active'); - else - $(this).removeClass('cn-filter-active'); - }); + document.addEventListener('input', function(e) { + // Check if the input element matches the selector + if (e.target.matches('#cn-{{$notification.type}}-input')) { + let input = e.target; + let val = input.value.toString().toLowerCase(); + + // Check if there is input value + if (val) { + // Remove '%' if it's at the beginning of the input value + val = val.indexOf('%') === 0 ? val.substring(1) : val; + + // Add 'active' and 'sticky-top' classes to the 'only' element + let onlyElement = document.getElementById('cn-{{$notification.type}}-only'); + onlyElement.classList.add('active', 'sticky-top'); + + // Remove 'd-none' class from the clear button + let clearButton = document.getElementById('cn-{{$notification.type}}-input-clear'); + clearButton.classList.remove('d-none'); + } else { + // Remove 'active' and 'sticky-top' classes from the 'only' element + let onlyElement = document.getElementById('cn-{{$notification.type}}-only'); + onlyElement.classList.remove('active', 'sticky-top'); + + // Add 'd-none' class to the clear button + let clearButton = document.getElementById('cn-{{$notification.type}}-input-clear'); + clearButton.classList.add('d-none'); + } + + // Loop through each notification and apply filter logic + let notifications = document.querySelectorAll("#nav-{{$notification.type}}-menu .notification"); + notifications.forEach(function(el) { + let cn = el.dataset.contact_name.toString().toLowerCase(); + let ca = el.dataset.contact_addr.toString().toLowerCase(); + + // Check if the contact name or address matches the input value + if (cn.indexOf(val) === -1 && ca.indexOf(val) === -1) { + el.classList.add('cn-filter-active'); + } else { + el.classList.remove('cn-filter-active'); + } + }); + } }); + {{/if}} {{/foreach}} function sse_bs_init() { - if(sessionStorage.getItem('notification_open') !== null || typeof sse_type !== 'undefined' ) { - if(typeof sse_type === 'undefined') + // Check if 'notification_open' exists in sessionStorage or if sse_type is defined + if (sessionStorage.getItem('notification_open') !== null || typeof sse_type !== 'undefined') { + if (typeof sse_type === 'undefined') { sse_type = sessionStorage.getItem('notification_open'); + } + + // Add the 'show' class to the appropriate element + let subNav = document.getElementById("nav-" + sse_type + "-sub"); + if (subNav) { + subNav.classList.add('show'); + } - $("#nav-" + sse_type + "-sub").addClass('show'); + // Call the sse_bs_notifications function sse_bs_notifications(sse_type, true, false); - } - else { + } else { + // Call the sse_bs_counts function if conditions are not met sse_bs_counts(); } } function sse_bs_counts() { - if(sse_bs_active || sse_sys_only) { + if (sse_bs_active || sse_sys_only) { return; } sse_bs_active = true; - $.ajax({ - type: 'post', - url: '/sse_bs', - data: { sse_rmids } - }).done( function(obj) { + // Use the fetch API to send the POST request with the data + fetch('/sse_bs', { + method: 'POST', + body: new URLSearchParams({sse_rmids: sse_rmids}) + }) + .then(response => response.json()) // Parse the JSON response + .then(obj => { console.log(obj); sse_bs_active = false; sse_rmids = []; sse_handleNotifications(obj, true, false); + }) + .catch(error => { + console.error('Error:', error); + sse_bs_active = false; }); } function sse_bs_notifications(e, replace, followup) { - - if(sse_bs_active || sse_sys_only) { + if (sse_bs_active || sse_sys_only) { return; } let manual = false; - if(typeof replace === 'undefined') + if (typeof replace === 'undefined') { replace = e.data.replace; + } - if(typeof followup === 'undefined') + if (typeof followup === 'undefined') { followup = e.data.followup; + } - if(typeof e === 'string') { + if (typeof e === 'string') { sse_type = e; - } - else { + } else { manual = true; sse_offset = 0; sse_type = e.target.dataset.sse_type; } - if(typeof sse_type === 'undefined') + if (typeof sse_type === 'undefined') { return; + } - if(followup || !manual || !$('#notification-link-' + sse_type).hasClass('collapsed')) { + if (followup || !manual || !document.getElementById('notification-link-' + sse_type).classList.contains('collapsed')) { - if(sse_offset >= 0) { - $("#nav-" + sse_type + "-loading").show(); + if (sse_offset >= 0) { + document.getElementById("nav-" + sse_type + "-loading").style.display = 'block'; } sessionStorage.setItem('notification_open', sse_type); - if(sse_offset !== -1 || replace) { - var cn_val = (($('#cn-' + sse_type + '-input').length && sse_partial_result) ? $('#cn-' + sse_type + '-input').val().toString().toLowerCase() : ''); + if (sse_offset !== -1 || replace) { + let cn_val = (document.getElementById('cn-' + sse_type + '-input') && sse_partial_result) + ? document.getElementById('cn-' + sse_type + '-input').value.toString().toLowerCase() + : ''; - $("#nav-" + sse_type + "-loading").show(); + document.getElementById("nav-" + sse_type + "-loading").style.display = 'block'; sse_bs_active = true; - $.ajax({ - type: 'post', - url: '/sse_bs/' + sse_type + '/' + sse_offset, - nquery: encodeURIComponent(cn_val), - data: { sse_rmids } - }).done(function(obj) { + // Send POST request using fetch API + fetch('/sse_bs/' + sse_type + '/' + sse_offset, { + method: 'POST', + body: new URLSearchParams({ + sse_rmids: sse_rmids, + nquery: encodeURIComponent(cn_val) + }) + }) + .then(response => response.json()) // Parse the JSON response + .then(obj => { console.log('sse: bootstraping ' + sse_type); console.log(obj); sse_bs_active = false; sse_rmids = []; - $("#nav-" + sse_type + "-loading").hide(); + document.getElementById("nav-" + sse_type + "-loading").style.display = 'none'; sse_offset = obj[sse_type].offset; sse_handleNotifications(obj, replace, followup); + }) + .catch(error => { + console.error('Error:', error); + sse_bs_active = false; }); + } else { + document.getElementById("nav-" + sse_type + "-loading").style.display = 'none'; } - else { - $("#nav-" + sse_type + "-loading").hide(); - } - } - else { + } else { sessionStorage.removeItem('notification_open'); } } function sse_handleNotifications(obj, replace, followup) { - - // notice and info - - if(obj.notice) { - $(obj.notice.notifications).each(function() { - toast(this, 'danger'); + // Notice and info notifications + if (obj.notice) { + obj.notice.notifications.forEach(notification => { + toast(notification, 'danger'); }); } - if(obj.info) { - $(obj.info.notifications).each(function(){ - toast(this, 'info'); + if (obj.info) { + obj.info.notifications.forEach(notification => { + toast(notification, 'info'); }); } @@ -325,218 +440,269 @@ let primary_notifications = ['dm', 'home', 'intros', 'register', 'notify', 'files']; let secondary_notifications = ['network', 'forums', 'all_events', 'pubs']; - let all_notifications = primary_notifications.concat(secondary_notifications); + let all_notifications = [...primary_notifications, ...secondary_notifications]; - all_notifications.forEach(function(type, index) { - if(typeof obj[type] === typeof undefined) - return true; + all_notifications.forEach(type => { + if (typeof obj[type] === 'undefined') { + return; + } - var count = Number(obj[type].count); + let count = Number(obj[type].count); - if(obj[type].count) { - $('.' + type + '-button').fadeIn(); - if(replace || followup) { - $('.' + type + '-update').html(count >= 100 ? '99+' : count); - } - else { - count = count + Number($('.' + type + '-update').html().replace(/\++$/, '')); - $('.' + type + '-update').html(count >= 100 ? '99+' : count); + // Show notifications and update count + let updateElement = document.querySelector('.' + type + '-update'); + let buttonElement = document.querySelector('.' + type + '-button'); + let subElement = document.getElementById('nav-' + type + '-sub'); + + if (count) { + if (buttonElement) buttonElement.style.display = 'block'; // Fade-in effect replaced by display block + if (replace || followup) { + updateElement.textContent = count >= 100 ? '99+' : count; + } else { + count = count + Number(updateElement.textContent.replace(/\++$/, '')); + updateElement.textContent = count >= 100 ? '99+' : count; } - } - else { - $('.' + type + '-update').html('0'); - $('#nav-' + type + '-sub').removeClass('show'); - $('.' + type + '-button').fadeOut(function() { + } else { + updateElement.textContent = '0'; + if (subElement) subElement.classList.remove('show'); + if (buttonElement) { + buttonElement.style.display = 'none'; // Fade-out effect replaced by display none sse_setNotificationsStatus(); - }); + } } - if(obj[type].notifications.length) + + if (obj[type].notifications.length) { sse_handleNotificationsItems(type, obj[type].notifications, replace, followup); + } }); sse_setNotificationsStatus(); - // load more notifications if visible notifications count becomes low - if(sse_type && sse_offset != -1 && $('#nav-' + sse_type + '-menu').children(':not(.tt-filter-active)').length < 15) { - sse_bs_notifications(sse_type, false, true); + // Load more notifications if visible notifications count becomes low + if (sse_type && sse_offset !== -1) { + let menu = document.getElementById('nav-' + sse_type + '-menu'); + if (menu && menu.children.length < 15) { + sse_bs_notifications(sse_type, false, true); + } } - - } - function sse_handleNotificationsItems(notifyType, data, replace, followup) { - - let notifications_tpl = ((notifyType == 'forums') ? decodeURIComponent($("#nav-notifications-forums-template[rel=template]").html().replace('data-src', 'src')) : decodeURIComponent($("#nav-notifications-template[rel=template]").html().replace('data-src', 'src'))); - let notify_menu = $("#nav-" + notifyType + "-menu"); - let notify_loading = $("#nav-" + notifyType + "-loading"); - let notify_count = $("." + notifyType + "-update"); - if(replace && !followup) { - notify_menu.html(''); - notify_loading.hide(); - } + function sse_handleNotificationsItems(notifyType, data, replace, followup) { - $(data).each(function() { + // Get the template, adjust based on the notification type + let notifications_tpl = (notifyType === 'forums') + ? decodeURIComponent(document.querySelector("#nav-notifications-forums-template[rel=template]").innerHTML.replace('data-src', 'src')) + : decodeURIComponent(document.querySelector("#nav-notifications-template[rel=template]").innerHTML.replace('data-src', 'src')); - // do not add a notification if it is already present + let notify_menu = document.getElementById("nav-" + notifyType + "-menu"); + let notify_loading = document.getElementById("nav-" + notifyType + "-loading"); + let notify_count = document.getElementsByClassName(notifyType + "-update"); - // TODO: this is questionable because at least in 'notify' notification type an item can have more than one notifications - // e.g. one for the mention and one for the item itself. - //if($('#nav-' + notifyType + '-menu .notification[data-b64mid=\'' + this.b64mid + '\']').length) - // return true; + if (replace && !followup) { + notify_menu.innerHTML = ''; // Clear menu + notify_loading.style.display = 'none'; // Hide loading + } - if(!replace && !followup && (this.thread_top && notifyType === 'network')) { - $(document).trigger('hz:handleNetworkNotificationsItems', this); + data.forEach(notification => { + // Special handling for network notifications + if (!replace && !followup && notification.thread_top && notifyType === 'network') { + document.dispatchEvent(new CustomEvent('hz:handleNetworkNotificationsItems', { detail: notification })); } - let html = notifications_tpl.format(this.notify_link,this.photo,this.name,this.addr,this.message,this.when,this.hclass,this.b64mid,this.notify_id,this.thread_top,this.unseen,this.private_forum, encodeURIComponent(this.mids), this.body); - notify_menu.append(html); + // Prepare HTML using the template + let html = notifications_tpl.format( + notification.notify_link, + notification.photo, + notification.name, + notification.addr, + notification.message, + notification.when, + notification.hclass, + notification.b64mid, + notification.notify_id, + notification.thread_top, + notification.unseen, + notification.private_forum, + encodeURIComponent(notification.mids), + notification.body + ); + + // Append the new notification HTML to the menu + notify_menu.insertAdjacentHTML('beforeend', html); }); - if(!replace && !followup) { - $("#nav-" + notifyType + "-menu .notification").sort(function(a,b) { - a = new Date(a.dataset.when); - b = new Date(b.dataset.when); - return a > b ? -1 : a < b ? 1 : 0; - }).appendTo('#nav-' + notifyType + '-menu'); + // Sort notifications by date + if (!replace && !followup) { + let notifications = Array.from(notify_menu.getElementsByClassName('notification')); + notifications.sort((a, b) => { + let dateA = new Date(a.dataset.when); + let dateB = new Date(b.dataset.when); + return dateA > dateB ? -1 : dateA < dateB ? 1 : 0; + }); + notifications.forEach(notification => notify_menu.appendChild(notification)); } - if($('#tt-' + notifyType + '-only').hasClass('active')) - $('#nav-' + notifyType + '-menu [data-thread_top=false]').addClass('tt-filter-active'); - - if($('#cn-' + notifyType + '-input').length) { - let filter = $('#cn-' + notifyType + '-input').val().toString().toLowerCase(); - if(filter) { - filter = filter.indexOf('%') == 0 ? filter.substring(1) : filter; - - $('#nav-' + notifyType + '-menu .notification').each(function(i, el) { - let cn = $(el).data('contact_name').toString().toLowerCase(); - let ca = $(el).data('contact_addr').toString().toLowerCase(); - if(cn.indexOf(filter) === -1 && ca.indexOf(filter) === -1) - $(el).addClass('cn-filter-active'); - else - $(el).removeClass('cn-filter-active'); + // Filter thread_top notifications if the filter is active + if (document.getElementById('tt-' + notifyType + '-only').classList.contains('active')) { + let notifications = notify_menu.querySelectorAll('[data-thread_top="false"]'); + notifications.forEach(notification => notification.classList.add('tt-filter-active')); + } + + // Filter notifications based on the input field + let filterInput = document.getElementById('cn-' + notifyType + '-input'); + if (filterInput) { + let filter = filterInput.value.toString().toLowerCase(); + if (filter) { + if (filter.indexOf('%') === 0) filter = filter.substring(1); // Remove the percent if it exists + let notifications = notify_menu.querySelectorAll('.notification'); + notifications.forEach(notification => { + let cn = notification.dataset.contactName.toString().toLowerCase(); + let ca = notification.dataset.contactAddr.toString().toLowerCase(); + if (cn.indexOf(filter) === -1 && ca.indexOf(filter) === -1) { + notification.classList.add('cn-filter-active'); + } else { + notification.classList.remove('cn-filter-active'); + } }); } } + // Update relative time for notifications updateRelativeTime('.autotime-narrow'); } + function sse_updateNotifications(type, mid) { - /* - if(type === 'pubs') + // Skip processing if the type is 'notify' and the conditions don't match + if (type === 'notify' && (mid !== bParam_mid || sse_type !== 'notify')) { return true; - */ - if(type === 'notify' && (mid !== bParam_mid || sse_type !== 'notify')) - return true; - /* - var count = Number($('.' + type + '-update').html()); + } - count--; + // Find the notification element based on its 'data-b64mid' attribute + let notification = document.querySelector(`#nav-${type}-menu .notification[data-b64mid='${mid}']`); - if(count < 1) { - $('.' + type + '-update').html(count); - $('.' + type + '-button').fadeOut(function() { - sse_setNotificationsStatus(); + if (notification) { + // Fade out the notification by adjusting its opacity + notification.style.transition = 'opacity 0.5s'; + notification.style.opacity = 0; + + // After the transition ends, remove the notification element from the DOM + notification.addEventListener('transitionend', function () { + notification.remove(); }); } - else { - $('.' + type + '-update').html(count); - } - */ - - $('#nav-' + type + '-menu .notification[data-b64mid=\'' + mid + '\']').fadeOut(function() { - this.remove(); - }); - } + function sse_setNotificationsStatus(data) { - var primary_notifications = ['dm', 'home', 'intros', 'register', 'notify', 'files']; - var secondary_notifications = ['network', 'forums', 'all_events', 'pubs']; - var all_notifications = primary_notifications.concat(secondary_notifications); + let primary_notifications = ['dm', 'home', 'intros', 'register', 'notify', 'files']; + let secondary_notifications = ['network', 'forums', 'all_events', 'pubs']; + let all_notifications = primary_notifications.concat(secondary_notifications); - var primary_available = false; - var any_available = false; + let primary_available = false; + let any_available = false; - all_notifications.forEach(function(type, index) { - if($('.' + type + '-button').css('display') == 'block') { + // Loop through all notifications and check their visibility + all_notifications.forEach(function (type) { + let button = document.querySelector(`.${type}-button`); + if (button && getComputedStyle(button).display === 'block') { any_available = true; - if(primary_notifications.indexOf(type) > -1) + if (primary_notifications.indexOf(type) > -1) { primary_available = true; + } } }); - if(primary_available) { - $('.notifications-btn-icon').removeClass('bi-exclamation-circle'); - $('.notifications-btn-icon').addClass('bi-exclamation-triangle'); - } - else { - $('.notifications-btn-icon').removeClass('bi-exclamation-triangle'); - $('.notifications-btn-icon').addClass('bi-exclamation-circle'); + // Update notification button icon based on the primary notification availability + let notificationIcon = document.querySelector('.notifications-btn-icon'); + if (primary_available) { + notificationIcon.classList.remove('bi-exclamation-circle'); + notificationIcon.classList.add('bi-exclamation-triangle'); + } else { + notificationIcon.classList.remove('bi-exclamation-triangle'); + notificationIcon.classList.add('bi-exclamation-circle'); } - if(any_available) { - $('.notifications-btn').css('opacity', 1); - $('#no_notifications').hide(); - $('#notifications').show(); - } - else { - $('.notifications-btn').css('opacity', 0.5); - $('#navbar-collapse-1').removeClass('show'); - $('#no_notifications').show(); - $('#notifications').hide(); + // Update visibility of notification button and sections + let notificationsBtn = document.querySelector('.notifications-btn'); + let noNotifications = document.querySelector('#no_notifications'); + let notifications = document.querySelector('#notifications'); + let navbarCollapse = document.querySelector('#navbar-collapse-1'); + + if (any_available) { + notificationsBtn.style.opacity = 1; + noNotifications.style.display = 'none'; + notifications.style.display = 'block'; + } else { + notificationsBtn.style.opacity = 0.5; + if (navbarCollapse) navbarCollapse.classList.remove('show'); + noNotifications.style.display = 'block'; + notifications.style.display = 'none'; } - if (typeof data !== typeof undefined) { - data.forEach(function(nmid, index) { - + // Handle specific notifications if 'data' is provided + if (typeof data !== 'undefined') { + data.forEach(function (nmid) { sse_rmids.push(nmid); - if($('.notification[data-b64mid=\'' + nmid + '\']').length) { - $('.notification[data-b64mid=\'' + nmid + '\']').each(function() { - var n = this.parentElement.id.split('-'); - return sse_updateNotifications(n[1], nmid); - }); + // Handle regular notifications + let notification = document.querySelector(`.notification[data-b64mid='${nmid}']`); + if (notification) { + let parentId = notification.parentElement.id.split('-')[1]; + sse_updateNotifications(parentId, nmid); } - // special handling for forum notifications - $('.notification-forum').filter(function() { - var fmids = decodeURIComponent($(this).data('b64mids')); - var n = this.parentElement.id.split('-'); - if(fmids.indexOf(nmid) > -1) { - var fcount = Number($('.' + n[1] + '-update').html()); + // Special handling for forum notifications + let forumNotifications = document.querySelectorAll('.notification-forum'); + forumNotifications.forEach(function (forumNotification) { + let fmids = decodeURIComponent(forumNotification.dataset.b64mids); + let parentId = forumNotification.parentElement.id.split('-')[1]; + + if (fmids.indexOf(nmid) > -1) { + let updateElem = document.querySelector(`.${parentId}-update`); + let fcount = Number(updateElem.innerText); fcount--; - $('.' + n[1] + '-update').html(fcount); - if(fcount < 1) { - $('.' + n[1] + '-button').fadeOut(); - $('#nav-' + n[1] + '-sub').removeClass('show'); + updateElem.innerText = fcount; + + if (fcount < 1) { + let button = document.querySelector(`.${parentId}-button`); + button.style.display = 'none'; + let subMenu = document.querySelector(`#nav-${parentId}-sub`); + if (subMenu) subMenu.classList.remove('show'); } - var count = Number($(this).find('.bg-secondary').html()); + + let countElem = forumNotification.querySelector('.bg-secondary'); + let count = Number(countElem.innerText); count--; - $(this).find('.bg-secondary').html(count); - if(count < 1) - $(this).remove(); + countElem.innerText = count; + + if (count < 1) { + forumNotification.remove(); + } } }); }); } - } function sse_fallback() { - $.get('/sse', function(obj) { - if(! obj) - return; + fetch('/sse') + .then(response => response.json()) + .then(obj => { + if (!obj) return; - console.log('sse fallback'); - console.log(obj); + console.log('sse fallback'); + console.log(obj); - sse_handleNotifications(obj, false, false); - }); + sse_handleNotifications(obj, false, false); + }) + .catch(error => { + console.error('Error fetching SSE data:', error); + }); } + </script> {{if !$sys_only}} |