forked from Icycoide/searxng
[mod] infinite_scroll as preference
* oscar theme: code from searx/plugins/infinite_scroll.py * simple theme: new implementation Co-authored-by: Markus Heiser <markus.heiser@darmarIT.de>
This commit is contained in:
parent
36aee70c24
commit
56e34947a6
23 changed files with 314 additions and 121 deletions
|
@ -59,43 +59,45 @@ window.searxng = (function (w, d) {
|
|||
}
|
||||
};
|
||||
|
||||
searxng.http = function (method, url) {
|
||||
var req = new XMLHttpRequest(),
|
||||
resolve = function () {},
|
||||
reject = function () {},
|
||||
promise = {
|
||||
then: function (callback) { resolve = callback; return promise; },
|
||||
catch: function (callback) { reject = callback; return promise; }
|
||||
};
|
||||
searxng.http = function (method, url, data = null) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
try {
|
||||
var req = new XMLHttpRequest();
|
||||
req.open(method, url, true);
|
||||
req.timeout = 20000;
|
||||
|
||||
try {
|
||||
req.open(method, url, true);
|
||||
// On load
|
||||
req.onload = function () {
|
||||
if (req.status == 200) {
|
||||
resolve(req.response, req.responseType);
|
||||
} else {
|
||||
reject(Error(req.statusText));
|
||||
}
|
||||
};
|
||||
|
||||
// On load
|
||||
req.onload = function () {
|
||||
if (req.status == 200) {
|
||||
resolve(req.response, req.responseType);
|
||||
} else {
|
||||
reject(Error(req.statusText));
|
||||
// Handle network errors
|
||||
req.onerror = function () {
|
||||
reject(Error("Network Error"));
|
||||
};
|
||||
|
||||
req.onabort = function () {
|
||||
reject(Error("Transaction is aborted"));
|
||||
};
|
||||
|
||||
req.ontimeout = function () {
|
||||
reject(Error("Timeout"));
|
||||
}
|
||||
};
|
||||
|
||||
// Handle network errors
|
||||
req.onerror = function () {
|
||||
reject(Error("Network Error"));
|
||||
};
|
||||
|
||||
req.onabort = function () {
|
||||
reject(Error("Transaction is aborted"));
|
||||
};
|
||||
|
||||
// Make the request
|
||||
req.send();
|
||||
} catch (ex) {
|
||||
reject(ex);
|
||||
}
|
||||
|
||||
return promise;
|
||||
// Make the request
|
||||
if (data) {
|
||||
req.send(data)
|
||||
} else {
|
||||
req.send();
|
||||
}
|
||||
} catch (ex) {
|
||||
reject(ex);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
searxng.loadStyle = function (src) {
|
||||
|
@ -148,5 +150,16 @@ window.searxng = (function (w, d) {
|
|||
this.parentNode.classList.add('invisible');
|
||||
});
|
||||
|
||||
function getEndpoint () {
|
||||
for (var className of d.getElementsByTagName('body')[0].classList.values()) {
|
||||
if (className.endsWith('_endpoint')) {
|
||||
return className.split('_')[0];
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
searxng.endpoint = getEndpoint();
|
||||
|
||||
return searxng;
|
||||
})(window, document);
|
||||
|
|
88
searx/static/themes/simple/src/js/main/infinite_scroll.js
Normal file
88
searx/static/themes/simple/src/js/main/infinite_scroll.js
Normal file
|
@ -0,0 +1,88 @@
|
|||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
/* global searxng */
|
||||
|
||||
searxng.ready(function () {
|
||||
'use strict';
|
||||
|
||||
searxng.infinite_scroll_supported = (
|
||||
'IntersectionObserver' in window &&
|
||||
'IntersectionObserverEntry' in window &&
|
||||
'intersectionRatio' in window.IntersectionObserverEntry.prototype);
|
||||
|
||||
if (searxng.endpoint !== 'results') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!searxng.infinite_scroll_supported) {
|
||||
console.log('IntersectionObserver not supported');
|
||||
return;
|
||||
}
|
||||
|
||||
let d = document;
|
||||
var onlyImages = d.getElementById('results').classList.contains('only_template_images');
|
||||
|
||||
function newLoadSpinner () {
|
||||
var loader = d.createElement('div');
|
||||
loader.classList.add('loader');
|
||||
return loader;
|
||||
}
|
||||
|
||||
function replaceChildrenWith (element, children) {
|
||||
element.textContent = '';
|
||||
children.forEach(child => element.appendChild(child));
|
||||
}
|
||||
|
||||
function loadNextPage (callback) {
|
||||
var form = d.querySelector('#pagination form.next_page');
|
||||
if (!form) {
|
||||
return
|
||||
}
|
||||
replaceChildrenWith(d.querySelector('#pagination'), [ newLoadSpinner() ]);
|
||||
var formData = new FormData(form);
|
||||
searxng.http('POST', d.querySelector('#search').getAttribute('action'), formData).then(
|
||||
function (response) {
|
||||
var nextPageDoc = new DOMParser().parseFromString(response, 'text/html');
|
||||
var articleList = nextPageDoc.querySelectorAll('#urls article');
|
||||
var paginationElement = nextPageDoc.querySelector('#pagination');
|
||||
d.querySelector('#pagination').remove();
|
||||
if (articleList.length > 0 && !onlyImages) {
|
||||
// do not add <hr> element when there are only images
|
||||
d.querySelector('#urls').appendChild(d.createElement('hr'));
|
||||
}
|
||||
articleList.forEach(articleElement => {
|
||||
d.querySelector('#urls').appendChild(articleElement);
|
||||
});
|
||||
if (paginationElement) {
|
||||
d.querySelector('#results').appendChild(paginationElement);
|
||||
callback();
|
||||
}
|
||||
}
|
||||
).catch(
|
||||
function (err) {
|
||||
console.log(err);
|
||||
var e = d.createElement('div');
|
||||
e.textContent = searxng.translations.error_loading_next_page;
|
||||
e.classList.add('dialog-error');
|
||||
e.setAttribute('role', 'alert');
|
||||
replaceChildrenWith(d.querySelector('#pagination'), [ e ]);
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
if (searxng.infinite_scroll && searxng.infinite_scroll_supported) {
|
||||
const intersectionObserveOptions = {
|
||||
rootMargin: "20rem",
|
||||
};
|
||||
const observedSelector = 'article.result:last-child';
|
||||
const observer = new IntersectionObserver(entries => {
|
||||
const paginationEntry = entries[0];
|
||||
if (paginationEntry.isIntersecting) {
|
||||
observer.unobserve(paginationEntry.target);
|
||||
loadNextPage(() => observer.observe(d.querySelector(observedSelector), intersectionObserveOptions));
|
||||
}
|
||||
});
|
||||
observer.observe(d.querySelector(observedSelector), intersectionObserveOptions);
|
||||
}
|
||||
|
||||
});
|
|
@ -2,6 +2,10 @@
|
|||
(function (w, d, searxng) {
|
||||
'use strict';
|
||||
|
||||
if (searxng.endpoint !== 'preferences') {
|
||||
return;
|
||||
}
|
||||
|
||||
searxng.ready(function () {
|
||||
let engine_descriptions = null;
|
||||
function load_engine_descriptions () {
|
||||
|
@ -19,10 +23,8 @@
|
|||
}
|
||||
}
|
||||
|
||||
if (d.querySelector('body[class="preferences_endpoint"]')) {
|
||||
for (const el of d.querySelectorAll('[data-engine-name]')) {
|
||||
searxng.on(el, 'mouseenter', load_engine_descriptions);
|
||||
}
|
||||
for (const el of d.querySelectorAll('[data-engine-name]')) {
|
||||
searxng.on(el, 'mouseenter', load_engine_descriptions);
|
||||
}
|
||||
});
|
||||
})(window, document, window.searxng);
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
(function (w, d, searxng) {
|
||||
'use strict';
|
||||
|
||||
if (searxng.endpoint !== 'results') {
|
||||
return;
|
||||
}
|
||||
|
||||
searxng.ready(function () {
|
||||
searxng.image_thumbnail_layout = new searxng.ImageLayout('#urls', '#urls .result-images', 'img.image_thumbnail', 14, 6, 200);
|
||||
searxng.image_thumbnail_layout.watch();
|
||||
|
|
|
@ -771,15 +771,19 @@ article[data-vim-selected].category-social {
|
|||
margin: 1rem @results-tablet-offset 0 @results-tablet-offset;
|
||||
display: grid;
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: min-content min-content 1fr min-content min-content;
|
||||
grid-template-rows: min-content min-content min-content 1fr min-content;
|
||||
gap: 0;
|
||||
grid-template-areas:
|
||||
"corrections"
|
||||
"urls"
|
||||
"answers"
|
||||
"sidebar"
|
||||
"urls"
|
||||
"pagination";
|
||||
|
||||
#sidebar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#urls {
|
||||
width: inherit;
|
||||
margin: 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue