aboutsummaryrefslogtreecommitdiffstats
path: root/view/js/main.js
diff options
context:
space:
mode:
Diffstat (limited to 'view/js/main.js')
-rw-r--r--view/js/main.js356
1 files changed, 312 insertions, 44 deletions
diff --git a/view/js/main.js b/view/js/main.js
index 7043c8577..8e369f62a 100644
--- a/view/js/main.js
+++ b/view/js/main.js
@@ -28,6 +28,8 @@ var expanded_items = [];
var updateTimeout = [];
const singlethread_modules = ['display', 'hq'];
const redirect_modules = ['display', 'notify'];
+let b64mids = [];
+
var page_cache = {};
@@ -87,6 +89,124 @@ $(document).ready(function() {
}
});
+ document.addEventListener('click', function(event) {
+ const targetElement = event.target.closest('.wall-item-reaction');
+ if (!targetElement) return;
+
+ const userClick = event.isTrusted;
+ const id = targetElement.dataset.itemId;
+ const mid = targetElement.dataset.itemMid;
+ const parent = targetElement.dataset.itemParent;
+ const uuid = targetElement.dataset.itemUuid;
+ const verb = targetElement.dataset.itemVerb;
+
+ if (targetElement.classList.contains('wall-item-comment')) {
+ const threadWrapper = document.getElementById(`thread-wrapper-${id}`);
+ const subWrapper = document.getElementById(`wall-item-sub-thread-wrapper-${id}`);
+ const parentSubWrapper = document.querySelectorAll(`#wall-item-sub-thread-wrapper-${parent} .wall-item-sub-thread-wrapper`);
+ const parentSubWrapperIndented = document.querySelector(`#wall-item-sub-thread-wrapper-${parent} .wall-item-sub-thread-wrapper.item-indent`);
+
+ subWrapper.style.setProperty('--hz-item-indent', stringToHslColor(uuid));
+ threadWrapper.style.setProperty('--hz-item-highlight', stringToHslColor(uuid));
+
+ document.querySelectorAll('.thread-wrapper.item-highlight').forEach(el => {
+ el.classList.remove('item-highlight');
+ });
+
+ if (!parentSubWrapperIndented && userClick) {
+ threadWrapper.classList.add('item-highlight');
+ }
+ else {
+ subWrapper.classList.add('item-indent');
+ }
+
+ if (userClick && targetElement.classList.contains('expanded')) {
+ document.querySelectorAll('.thread-wrapper.item-highlight').forEach(el => {
+ el.classList.remove('item-highlight');
+ });
+
+ parentSubWrapper.forEach(el => {
+ if (el.children.length > 0) {
+ el.classList.add('item-indent');
+ }
+ });
+
+ targetElement.classList.add('disabled');
+ return;
+ }
+
+ targetElement.classList.add('expanded');
+
+ if (!userClick) {
+ targetElement.classList.add('disabled');
+ }
+ }
+
+ request(id, mid, verb, parent, uuid, userClick);
+ });
+
+ document.addEventListener('click', function(event) {
+ const targetElement = event.target.closest('.dropdown-item-expand');
+ if (!targetElement) return;
+
+ // Disable the button we just clicked
+ targetElement.classList.add('disabled');
+ event.preventDefault();
+
+ document.querySelectorAll('.thread-wrapper.item-highlight').forEach(el => {
+ el.classList.remove('item-highlight');
+ });
+
+ const id = targetElement.dataset.itemId;
+ const uuid = targetElement.dataset.itemUuid;
+ const subWrapper = document.getElementById(`wall-item-sub-thread-wrapper-${id}`);
+
+ const loading = document.getElementById('like-rotator-' + id);
+
+ const wrapper = document.getElementById('thread-wrapper-' + id);
+ const parent = wrapper.closest('.generic-content-wrapper');
+
+ parent.querySelectorAll('.wall-item-sub-thread-wrapper.item-indent').forEach(el => {
+ el.classList.remove('item-indent');
+ });
+
+ parent.querySelectorAll('.thread-wrapper.wall-item-expanded').forEach(el => {
+ el.classList.remove('wall-item-expanded');
+ });
+
+ parent.classList.add('wall-item-backdrop');
+ wrapper.classList.add('wall-item-expanded', 'shadow');
+
+ if (!wrapper.classList.contains('toplevel_item')) {
+ document.documentElement.style.setProperty('--hz-item-highlight', stringToHslColor(uuid));
+ }
+
+ autoExpand(id);
+
+ // Close and reset if dbl clicked
+ wrapper.addEventListener('dblclick', function(event) {
+
+ parent.classList.remove('wall-item-backdrop');
+ wrapper.classList.remove('wall-item-expanded', 'shadow');
+
+ wrapper.querySelectorAll('.dropdown-item-expand').forEach(el => {
+ el.classList.remove('disabled');
+ });
+
+ wrapper.querySelectorAll('.wall-item-comment').forEach(el => {
+ el.classList.remove('disabled', 'expanded');
+ });
+
+ subWrapper.querySelectorAll('.wall-item-comment').forEach(el => {
+ el.classList.remove('disabled', 'expanded');
+ });
+
+ subWrapper.innerHTML = '';
+ subWrapper.classList.remove('item-indent');
+ })
+
+ });
+
// @hilmar |->
if ( typeof(window.tao) == 'undefined' ) {
window.tao = {};
@@ -756,7 +876,7 @@ function updateConvItems(mode, data) {
if (data_json.includes(bParam_mid) && elem.parentNode.classList.contains('wall-item-sub-thread-wrapper')) {
if (!elem.parentNode.parentNode.classList.contains('toplevel_item')) {
elem.parentNode.parentNode.classList.add('item-highlight');
- document.documentElement.style.setProperty('--hz-item-highlight', stringToHlsColor(JSON.parse(elem.parentNode.parentNode.dataset.b64mids)[0]));
+ document.documentElement.style.setProperty('--hz-item-highlight', stringToHslColor(JSON.parse(elem.parentNode.parentNode.dataset.b64mids)[0]));
}
}
@@ -1292,27 +1412,64 @@ function justifyPhotosAjax(id) {
$('#' + id).justifiedGallery('norewind').on('jg.complete', function(e){ justifiedGalleryActive = false; });
}
-function request(id, mid, verb, parent, uuid) {
+function request(id, mid, verb, parent, uuid, userClick) {
- const loading = document.getElementById('like-rotator-' + id);
- loading.style.display = 'block';
+ if (verb === 'load') {
+ const dots = document.getElementById('load-more-dots-' + parent);
+ dots.classList.add('jumping-dots');
- if (verb === 'comment') {
+ const parent_sub = document.getElementById('wall-item-sub-thread-wrapper-' + parent);
+ const offset = parent_sub.children.length;
- if (singlethread_modules.indexOf(module) !== -1) {
- let stateObj = { b64mid: uuid };
- history.pushState(stateObj, '', module + '/' + uuid);
- }
+ fetch('/request?offset=' + offset + '&verb=' + verb + '&mid=' + mid + '&parent=' + parent + '&module=' + module)
+ .then(response => response.json())
+ .then(obj => {
+ let parser = new DOMParser();
+ let doc = parser.parseFromString(obj.html, 'text/html');
+ let b64mids = [];
- document.querySelectorAll('.thread-wrapper.item-highlight').forEach(el => {
- el.classList.remove('item-highlight');
- el.style.boxShadow = '';
+ doc.querySelectorAll('.thread-wrapper').forEach(function (e) {
+ let data = JSON.parse(e.dataset.b64mids);
+ b64mids.push(...data);
+ });
+
+ imagesLoaded(doc.querySelectorAll('.wall-item-body img'), function () {
+ injectWithAnimation('wall-item-sub-thread-wrapper-' + parent, doc);
+ dots.classList.remove('jumping-dots');
+
+ const loadmore_progress = document.getElementById('load-more-progress-' + parent);
+ loadmore_progress.style.width = Math.round(100 * parent_sub.children.length / loadmore_progress.dataset.commentsTotal) + '%';
+
+ if (Number(parent_sub.children.length) === Number(loadmore_progress.dataset.commentsTotal)) {
+ const loadmore = document.getElementById('load-more-' + parent);
+ loadmore.remove();
+ }
+
+ updateRelativeTime('.autotime');
+ collapseHeight();
+
+ document.dispatchEvent(new CustomEvent('hz:sse_setNotificationsStatus', { detail: b64mids }));
+ document.dispatchEvent(new Event('hz:sse_bs_counts'));
+ });
+
+ })
+ .catch(error => {
+ console.error('Error fetching data:', error);
});
- const wrapper = document.getElementById('thread-wrapper-' + id);
- if (!wrapper.classList.contains('toplevel_item')) {
- wrapper.classList.add('item-highlight');
- document.documentElement.style.setProperty('--hz-item-highlight', stringToHlsColor(uuid));
+ return;
+ }
+
+ const loading = document.getElementById('like-rotator-' + id);
+
+ if (userClick) {
+ loading.style.display = 'block';
+ }
+
+ if (verb === 'comment') {
+ if (userClick && singlethread_modules.indexOf(module) !== -1) {
+ let stateObj = { b64mid: uuid };
+ history.pushState(stateObj, '', module + '/' + uuid);
}
fetch('/request?verb=' + verb + '&mid=' + mid + '&parent=' + parent + '&module=' + module)
@@ -1320,7 +1477,6 @@ function request(id, mid, verb, parent, uuid) {
.then(obj => {
let parser = new DOMParser();
let doc = parser.parseFromString(obj.html, 'text/html');
- let b64mids = [];
doc.querySelectorAll('.thread-wrapper').forEach(function (e) {
let data = JSON.parse(e.dataset.b64mids);
@@ -1328,13 +1484,15 @@ function request(id, mid, verb, parent, uuid) {
});
imagesLoaded(doc.querySelectorAll('.wall-item-body img'), function () {
- injectWithAnimation('wall-item-sub-thread-wrapper-' + id, obj.html);
+ injectWithAnimation('wall-item-sub-thread-wrapper-' + id, doc, true);
updateRelativeTime('.autotime');
- loading.style.display = 'none';
collapseHeight();
- document.dispatchEvent(new CustomEvent('hz:sse_setNotificationsStatus', { detail: b64mids }));
- document.dispatchEvent(new Event('hz:sse_bs_counts'));
+ if (userClick) {
+ loading.style.display = 'none';
+ document.dispatchEvent(new CustomEvent('hz:sse_setNotificationsStatus', { detail: b64mids }));
+ document.dispatchEvent(new Event('hz:sse_bs_counts'));
+ }
});
})
@@ -1377,32 +1535,142 @@ function request(id, mid, verb, parent, uuid) {
}
-function injectWithAnimation(container, html) {
- const target = document.getElementById(container);
- target.innerHTML = html;
+function injectWithAnimation(containerId, parsedDoc, overwrite = false) {
+ const container = document.getElementById(containerId);
+ if (!container) return;
+ if (overwrite) container.innerHTML = '';
- target.animate([
- { opacity: 0, transform: 'translateY(-20px)' },
- { opacity: 1, transform: 'translateY(0)' }
- ], {
- duration: 300,
- easing: 'ease-out'
- });
+ const newElements = Array.from(parsedDoc.body.children);
- // For children animation
- Array.from(target.children).forEach((el, i) => {
- el.animate([
- { opacity: 0, transform: 'scale(.7)' },
- { opacity: 1, transform: 'scale(1)' }
- ], {
- duration: 300,
- delay: i * 50,
- fill: 'both',
- easing: 'ease-out'
- });
- });
+ for (let i = newElements.length - 1; i >= 0; i--) {
+ const el = newElements[i].cloneNode(true);
+ el.classList.add('item-fade-in');
+ container.insertBefore(el, container.firstChild);
+
+ // Remove classes after transition ends
+ const onTransitionEnd = (event) => {
+ el.classList.remove('item-fade-in', 'show');
+ el.removeEventListener('transitionend', onTransitionEnd);
+ };
+ el.addEventListener('transitionend', onTransitionEnd);
+
+ setTimeout(() => {
+ el.classList.add('show');
+ }, (newElements.length - 1 - i) * 30);
+ }
}
+const autoExpand = (function () {
+ const clickedElements = new Set(); // Stores clicked button references
+
+ // We wait 10 seconds for images. Set the timeout here slightly higher.
+ function waitForElement(selector, timeout = 11000) {
+ return new Promise((resolve, reject) => {
+ // Check if the element already exists
+ const element = document.querySelector(selector);
+
+ if (element) {
+ resolve(element);
+ return;
+ }
+
+ // Set up a timeout to reject the promise if the element doesn't appear in time
+ const timer = setTimeout(() => {
+ observer.disconnect();
+ reject(new Error(`Element "${selector}" not found within ${timeout}ms`));
+ }, timeout);
+
+ // Create a MutationObserver to watch for DOM changes
+ const observer = new MutationObserver(() => {
+ const el = document.querySelector(selector);
+ if (el) {
+ clearTimeout(timer);
+ observer.disconnect();
+ resolve(el);
+ }
+ });
+
+ // Start observing the document for changes
+ observer.observe(document.documentElement, {
+ childList: true,
+ subtree: true
+ });
+ });
+ }
+
+ async function autoExpand(id) {
+ const loading = document.getElementById('like-rotator-' + id);
+ const maxIterations = 3;
+ clickedElements.clear();
+
+ try {
+ // Step 1: Ensure initial button is clicked
+ const initBtnSelector = '#wall-item-comment-' + id;
+ const initBtn = await waitForElement(initBtnSelector);
+
+ if (!clickedElements.has(initBtn)) {
+ initBtn.click();
+ clickedElements.add(initBtn);
+ }
+
+ // Step 2: Loop until no new buttons are found
+ let newButtonsFound;
+
+ const commentSelector = `#wall-item-sub-thread-wrapper-${id} .thread-wrapper`;
+ const commentBtnSelector = `#wall-item-sub-thread-wrapper-${id} .wall-item-comment`;
+ const subsSelector = `#wall-item-sub-thread-wrapper-${id}, #wall-item-sub-thread-wrapper-${id} .wall-item-sub-thread-wrapper`;
+
+ let iteration = 1;
+
+ do {
+ newButtonsFound = false;
+
+ // Wait for any comment to appear
+ await waitForElement(commentSelector);
+
+ document.querySelectorAll(subsSelector).forEach(el => {
+ if (el.children.length > 0) {
+ el.classList.add('item-indent');
+ }
+ });
+
+ const expandButtons = document.querySelectorAll(commentBtnSelector);
+
+ for (const btn of expandButtons) {
+ if (!clickedElements.has(btn)) {
+ btn.click();
+ clickedElements.add(btn);
+ newButtonsFound = true;
+ // Optional: await waitForElement(...) to wait for new content
+ }
+ }
+
+ // Wait between iterations to allow UI to update
+ if (newButtonsFound) {
+ await new Promise(res => setTimeout(res, 700));
+ }
+
+ iteration++;
+
+ } while (newButtonsFound && iteration < maxIterations);
+
+ console.log('All replies loaded!');
+
+ loading.style.display = 'none';
+
+ document.dispatchEvent(new CustomEvent('hz:sse_setNotificationsStatus', { detail: b64mids }));
+ document.dispatchEvent(new Event('hz:sse_bs_counts'));
+
+ } catch (error) {
+ loading.style.display = 'none';
+ console.error("autoExpand failed:", error.message);
+ }
+ }
+
+ return autoExpand;
+})();
+
+
function stringToHexColor(str) {
let hash = 0;
for (let i = 0; i < str.length; i++) {
@@ -1416,7 +1684,7 @@ function stringToHexColor(str) {
return color;
}
-function stringToHlsColor(str) {
+function stringToHslColor(str) {
let stringUniqueHash = [...str].reduce((acc, char) => {
return char.charCodeAt(0) + ((acc << 5) - acc);
}, 0);