diff options
-rw-r--r-- | boot.php | 2 | ||||
-rw-r--r-- | view/js/main.js | 91 | ||||
-rw-r--r-- | view/php/theme_init.php | 1 | ||||
-rw-r--r-- | view/tpl/notifications_widget.tpl | 193 |
4 files changed, 144 insertions, 143 deletions
@@ -66,7 +66,7 @@ require_once('include/security.php'); define('PLATFORM_NAME', 'hubzilla'); -define('STD_VERSION', '10.1.2'); +define('STD_VERSION', '10.1.3'); define('ZOT_REVISION', '6.0'); define('DB_UPDATE_VERSION', 1263); diff --git a/view/js/main.js b/view/js/main.js index 658dd8b6f..d95e9f659 100644 --- a/view/js/main.js +++ b/view/js/main.js @@ -767,19 +767,12 @@ function updateConvItems(mode, data) { mediaPlaying = event.type === 'playing'; } - if (!preloadImages) { - imagesLoaded(document.querySelectorAll('.wall-item-body, .wall-photo-item'), function () { - collapseHeight(); - if (bParam_mid && mode === 'replace') { - scrollToItem(); - } - }); - } else { + imagesLoaded(document.querySelectorAll('.wall-item-body img, .wall-photo-item img'), function () { collapseHeight(); if (bParam_mid && mode === 'replace') { scrollToItem(); } - } + }); // reset rotators and cursors we may have set before reaching this place let pageSpinner = document.getElementById("page-spinner"); @@ -799,16 +792,54 @@ function updateConvItems(mode, data) { // Helper function for images loaded function imagesLoaded(elements, callback) { let loaded = 0; - let count = elements.length; + let count = 0; + + // Helper function to extract img elements from an HTML string + function extractImagesFromHtml(htmlString) { + const tempDiv = document.createElement('div'); + tempDiv.innerHTML = htmlString; + return Array.from(tempDiv.getElementsByTagName('img')); + } + + // If the elements is an HTML string, convert it to img elements + if (typeof elements === 'string') { + elements = extractImagesFromHtml(elements); + } + + // If elements is not a valid array-like object, or is empty, exit early + if (!elements || elements.length === 0) { + callback(); // No images to load, immediately call the callback + return; + } - elements.forEach(element => { + // Filter out only img elements from the list + const images = Array.from(elements).filter(element => { + return element.tagName && element.tagName.toLowerCase() === 'img' && element.src; + }); + + // If no images are found, call the callback immediately + if (images.length === 0) { + callback(); + return; + } + + count = images.length; + + // Process each image element + images.forEach(element => { let img = new Image(); + + // Handle both loading and error events img.onload = img.onerror = function () { loaded++; + document.getElementById('image_counter').innerHTML = Math.round((loaded * 100) / count) + '%'; + if (loaded === count) { callback(); } }; + + // Set the source to the image's src attribute img.src = element.src; }); } @@ -1076,10 +1107,7 @@ function liveUpdate(notify_id) { if(update_mode === 'update' || preloadImages) { console.log('LOADING images...'); - $('.wall-item-body, .wall-photo-item',data).imagesLoaded() - .always( function( instance ) { - //console.log('all images loaded'); - + imagesLoaded(data, function () { var iready = new Date(); console.log('IMAGES ready in: ' + (iready - dready)/1000 + ' seconds.'); @@ -1088,23 +1116,7 @@ function liveUpdate(notify_id) { updateConvItems(update_mode,data); in_progress = false; - $('#image_counter').html(''); - - // remove modal backdrop in case the update was triggered from a modal - $('.modal-backdrop').remove(); - }) - .done( function( instance ) { - //console.log('all images successfully loaded'); - }) - .fail( function() { - //console.log('all images loaded, at least one is broken'); - }) - .progress( function( instance, image ) { - $('#image_counter').html(Math.floor((instance.progressedCount*100)/instance.images.length) + '%'); - //var result = image.isLoaded ? 'loaded' : 'broken'; - //console.log( 'image is ' + result + ' for ' + image.img.src ); }); - } else { page_load = false; @@ -1146,9 +1158,8 @@ function cache_next_page() { console.log('cached: ' + update_url); - $('.wall-item-body, .wall-photo-item', data).imagesLoaded() - .always( function( instance ) { - console.log('page_cache images loaded:'); + imagesLoaded(data, function () { + console.log('page_cache: images loaded'); page_cache.data = data; page_cache.page = bParam_page; @@ -1156,19 +1167,7 @@ function cache_next_page() { bParam_page--; page_load = false; - }) - .done( function( instance ) { - console.log('success'); - }) - .fail( function() { - console.log('at least one is broken'); - }) - .progress( function( instance, image ) { - //console.log(instance.progressedCount + '/' + instance.images.length); - //var result = image.isLoaded ? 'loaded' : 'broken'; - //console.log( 'image is ' + result + ' for ' + image.img.src ); }); - }); } diff --git a/view/php/theme_init.php b/view/php/theme_init.php index abe4851af..e6bd09224 100644 --- a/view/php/theme_init.php +++ b/view/php/theme_init.php @@ -34,7 +34,6 @@ head_add_js('/library/colorbox/jquery.colorbox-min.js'); head_add_js('/library/jquery.AreYouSure/jquery.are-you-sure.js'); head_add_js('/library/tableofcontents/jquery.toc.js'); head_add_js('/library/Sortable/Sortable.min.js'); -head_add_js('/vendor/desandro/imagesloaded/imagesloaded.pkgd.min.js'); /** * Those who require this feature will know what to do with it. diff --git a/view/tpl/notifications_widget.tpl b/view/tpl/notifications_widget.tpl index cdef36eb3..f42ff21dc 100644 --- a/view/tpl/notifications_widget.tpl +++ b/view/tpl/notifications_widget.tpl @@ -183,122 +183,125 @@ }); }); - }); - - document.addEventListener('hz:sse_setNotificationsStatus', function(e) { - sse_setNotificationsStatus(e.detail); - }); - - document.addEventListener('hz:sse_bs_init', function() { - sse_bs_init(); - }); - - document.addEventListener('hz:sse_bs_counts', function() { - sse_bs_counts(); - }); + {{foreach $notifications as $notification}} + {{if $notification.filter}} + document.querySelectorAll('#tt-{{$notification.type}}-only').forEach(function (element) { + element.addEventListener('click', function(e) { - {{foreach $notifications as $notification}} - {{if $notification.filter}} - 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"]'); + 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; - } + // 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'); + 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'); - // Count the visible notifications - let visibleNotifications = Array.from(menu.querySelectorAll('.notification')).filter(isVisible).length; + // Count the visible notifications + let visibleNotifications = Array.from(menu.querySelectorAll('.notification')).filter(isVisible).length; - // Load more notifications if the visible count is low - if (sse_type && sse_offset !== -1 && visibleNotifications < 15) { - sse_bs_notifications(sse_type, false, true); + // Load more notifications if the visible count is low + if (sse_type && sse_offset !== -1 && visibleNotifications < 15) { + sse_bs_notifications(sse_type, false, true); + } } - } - } - - 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'); - } - - }); - - 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'); + document.querySelectorAll('#cn-{{$notification.type}}-input-clear').forEach(function (element) { + element.addEventListener('click', function(e) { + let input = document.getElementById('cn-{{$notification.type}}-input'); + input.value = ''; - // 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 + // Remove 'active' and 'sticky-top' classes to 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 + // Add 'd-none' class from 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(); + // 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'); + }); + }); + }); + + document.querySelectorAll('#cn-{{$notification.type}}-input').forEach(function (element) { + element.addEventListener('input', function(e) { + 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; - // 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'); + // 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 { - el.classList.remove('cn-filter-active'); + // 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}} + + }); + + document.addEventListener('hz:sse_setNotificationsStatus', function(e) { + sse_setNotificationsStatus(e.detail); + }); + + document.addEventListener('hz:sse_bs_init', function() { + sse_bs_init(); + }); + + document.addEventListener('hz:sse_bs_counts', function() { + sse_bs_counts(); }); - {{/if}} - {{/foreach}} function sse_bs_init() { // Check if 'notification_open' exists in sessionStorage or if sse_type is defined @@ -557,8 +560,8 @@ 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(); + let cn = notification.dataset.contact_name.toString().toLowerCase(); + let ca = notification.dataset.contact_addr.toString().toLowerCase(); if (cn.indexOf(filter) === -1 && ca.indexOf(filter) === -1) { notification.classList.add('cn-filter-active'); } else { |