diff --git a/index.html b/index.html
index 2e67d5a..23eae3c 100644
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@
- Hello World
+ Spam Noticer
diff --git a/script.js b/script.js
index 927be6f..497bae5 100644
--- a/script.js
+++ b/script.js
@@ -108,7 +108,7 @@ function resolvePath(routes, path, query_params) {
function resolve(path_data, route_part) {
console.log('calling content');
- console.log(path_data, route_part);
+ console.log(path_data, route_part, query_params);
route_part.content(path_data, query_params);
}
@@ -140,6 +140,165 @@ var ROUTES = RoutePart(
, handlePageRoot
);
+/**
+ * Pagination
+ */
+
+function createPagination(start_page_num, url, name, page_size, renderContent) {
+ const numDisplayedPages = 5; // Specify the number of numbered links to display
+
+ // Helper function to update the URL with the new page number
+ function updatePageNumberInURL(pageNum) {
+ let params;
+
+ if (window.location.search == "") {
+ params = {}
+ } else {
+ console.log("calling parseQueryParams. window.location.search:", window.location.search);
+ params = parseQueryParams(window.location.search.substring(1));
+ }
+
+ console.log("updatePageNumberInURL", params);
+ params[name.replaceAll(' ', '_')] = pageNum;
+ changeUrl("/", params, true);
+ }
+
+ function createPaginationControls(page_num, dataset_size) {
+ const container = div();
+ container.classList.add('pagination');
+
+ // Calculate the total number of pages
+ const total_pages = Math.ceil(dataset_size / page_size);
+ console.log('page_num:', page_num, 'page_size:', page_size, 'dataset_size:', dataset_size, 'total_pages:', total_pages);
+
+ function createNumberedLink(pageNum) {
+ const link = document.createElement('a');
+
+ link.addEventListener('click', function(e) {
+ //loadNthPage(url, pageNum - 1, page_size)
+ e.preventDefault();
+ updatePageNumberInURL(pageNum - 1);
+ });
+
+ link.appendChild(text(pageNum));
+
+ if (pageNum - 1 === page_num) {
+ link.classList.add('active'); // Apply CSS class for active page
+ } else {
+ link.setAttribute('href', '#');
+ }
+
+ return link;
+ }
+
+ // Add Previous link if applicable
+ if (page_num > 0) {
+ const prev_link = document.createElement('a');
+ prev_link.setAttribute('href', '#');
+
+ prev_link.addEventListener('click', function(e) {
+ e.preventDefault();
+ //loadNthPage(url, page_num - 1, page_size)
+ updatePageNumberInURL(page_num - 1);
+ });
+
+ prev_link.appendChild(text('Previous'));
+ container.appendChild(prev_link);
+ }
+
+ // Add numbered links
+ const firstDisplayedPage = Math.max(1, page_num - Math.floor(numDisplayedPages / 2));
+ const lastDisplayedPage = Math.min(total_pages, firstDisplayedPage + numDisplayedPages - 1);
+
+ if (firstDisplayedPage > 1) {
+ container.appendChild(createNumberedLink(1));
+
+ if (firstDisplayedPage > 2) {
+ container.appendChild(text('...'));
+ }
+ }
+
+ for (let i = firstDisplayedPage; i <= lastDisplayedPage; i++) {
+ container.appendChild(createNumberedLink(i));
+ }
+
+ if (lastDisplayedPage < total_pages) {
+ if (lastDisplayedPage < total_pages - 1) {
+ container.appendChild(text('...'));
+ }
+
+ container.appendChild(createNumberedLink(total_pages));
+ }
+
+ // Add Next link if applicable
+ if (page_num < total_pages - 1) {
+ const next_link = document.createElement('a');
+ next_link.setAttribute('href', '#');
+
+ next_link.addEventListener('click', function(e) {
+ //loadNthPage(url, page_num + 1, page_size)
+ e.preventDefault();
+ updatePageNumberInURL(page_num + 1);
+ });
+
+ next_link.appendChild(text('Next'));
+ container.appendChild(next_link);
+ }
+
+ return container;
+ }
+
+ function loadNthPage(url, page_num) {
+ // Calculate the range of results based on the current page
+ const start = page_num * page_size;
+ const end = start + page_size - 1;
+
+ var headers = {
+ 'Authorization': 'Bearer ' + GlobalVars.settings.jwt,
+ //'Prefer': 'count=estimated',
+ 'Prefer': 'count=exact',
+ 'Range-Unit': 'items',
+ 'Range': `${start}-${end}`
+ };
+
+ pageInfoText.innerText = `Loading page ${page_num} of ${name}`;
+ cancelGlobalEvts();
+
+ if (page_num > 0) {
+ }
+
+ return get(url, cancel, headers)
+ .then(function(response) {
+ // Retrieve the range and total number of results from the HTTP headers
+ const rangeHeader = response.getResponseHeader('Content-Range');
+ const [start, end, total_results] = parseRangeHeader(rangeHeader);
+ const json = JSON.parse(response.responseText);
+ const controlsA = createPaginationControls(page_num, total_results);
+ const controlsB = createPaginationControls(page_num, total_results);
+ renderContent(json, controlsA, controlsB);
+ pageInfoText.innerText = `${name} ${page_num + 1}/${Math.ceil(total_results / page_size)}`;
+ })
+ .catch(caught.bind(this, `Failed to load ${url} page ${page_num}. Reason:`));
+ }
+
+ loadNthPage(url, start_page_num);
+}
+
+// Helper function to parse the Content-Range header
+function parseRangeHeader(rangeHeader) {
+ const match = rangeHeader.match(/(\d+)-(\d+)\/(\d+)/);
+
+ if (match) {
+ const start = parseInt(match[1]);
+ const end = parseInt(match[2]);
+ const totalResults = parseInt(match[3]);
+ return [start, end, totalResults];
+ }
+
+ return [0, 0, 0]; // Default values if the header is not available or not in the expected format
+}
+
+
/**
* Functions
*/
@@ -156,7 +315,7 @@ function resolveResponse(resolve, reject) {
}
} else {
if (e.target.status >= 200 && e.target.status < 300) {
- return resolve(e.target.responseText);
+ return resolve(e.target);
} else {
reject(new Error('API responded with ' + e.target.status));
}
@@ -361,10 +520,6 @@ function keepElements(elem_selectors) {
}
}
-function loadJwt() {
- cancelGlobalEvts();
-}
-
function caught(m, e) {
console.error(m);
console.error(e);
@@ -402,7 +557,8 @@ function mkSpamImgElement(img_description) {
function renderNav() {
var nav = document.createElement('nav');
var a_elem = _mkelem('a', text('All Known Spam Posts'));
- a_elem.addEventListener('click', function() {
+ a_elem.addEventListener('click', function(e) {
+ e.preventDefault();
changeUrl('/', null, true);
});
a_elem.setAttribute('href', '#');
@@ -476,7 +632,6 @@ function renderAttachmentReason(attachment, known_spam_post_attachments) {
'match': `${Math.round(distance * 100 * 10) / 10}%`
};
-
container.appendChild(renderThings(things));
return container;
}
@@ -556,34 +711,36 @@ function renderOverviewPost(post) {
return postContainer;
}
-function loadKnownSpamPosts() {
- pageInfoText.innerText = 'Loading all known spam posts...';
- cancelGlobalEvts();
+function loadKnownSpamPosts(params) {
+ if (params == null) {
+ params = {};
+ }
+ const pageName = "known spam posts";
var url = GlobalVars.settings.postgrest_url + '/known_spam_post?select=*,known_spam_post_attachment(*,phash::text)'
- var headers = {
- 'Authorization': 'Bearer ' + GlobalVars.settings.jwt
- };
- get(url, cancel, headers)
- .then(function(response) {
- var json = JSON.parse(response);
- console.log("results for", url, response);
- pageInfoText.innerText = 'Have these known spam posts:';
- var mainElem = document.querySelector('main');
- mainElem.innerHTML = '';
+ const pageNum = Number(params[pageName.replaceAll(' ', '_')] || 0);
- json.forEach(function (post) {
- var postElem = renderOverviewPost(post);
+ function renderContent(json, controlsA, controlsB) {
+ pageInfoText.innerText = 'Have these known spam posts:';
+ var mainElem = document.querySelector('main');
+ mainElem.innerHTML = '';
+ mainElem.appendChild(controlsA);
- postElem.addEventListener('click', function() {
- changeUrl('/spam_post/' + post.text_post_id, null, true);
- });
+ json.forEach(function (post) {
+ var postElem = renderOverviewPost(post);
- mainElem.appendChild(postElem);
+ postElem.addEventListener('click', function() {
+ changeUrl('/spam_post/' + post.text_post_id, null, true);
});
- })
- .catch(caught.bind(this, "Failed to load known spam posts. Reason:"));
+
+ mainElem.appendChild(postElem);
+ });
+
+ mainElem.appendChild(controlsB);
+ }
+
+ createPagination(pageNum, url, pageName, 25, renderContent);
}
function changeUrl(path, search_query, push_state) {
@@ -602,7 +759,7 @@ function changeUrl(path, search_query, push_state) {
function handlePageRoot(_, query_params) {
console.log("handlePageRoot", JSON.stringify(query_params));
- return loadKnownSpamPosts();
+ return loadKnownSpamPosts(query_params);
}
function showSpamPost(path_data, _) {
@@ -638,7 +795,7 @@ function showSpamPost(path_data, _) {
get(url, cancel, headers)
.then(function(response) {
- var json = JSON.parse(response);
+ var json = JSON.parse(response.responseText);
console.log(json);
pageInfoText.innerText = 'Known Spam Post';
@@ -657,7 +814,7 @@ function showSpamPost(path_data, _) {
get(url, cancel, headers)
.then(function(response) {
- var json = JSON.parse(response);
+ var json = JSON.parse(response.responseText);
console.log("known spam attachments:", json);
knownSpamAttachmentsSectionElem
.appendChild(renderKnownSpamAttachments(json));
@@ -706,8 +863,10 @@ function gatherElements() {
}
function parseQueryParams(querystring) {
+ console.log('parseQueryParams', querystring, querystring.split('&'));
return querystring.split('&')
.map(function(part) {
+ console.log(part);
return part.split('=').map(decodeURIComponent);
})
.reduce(function(acc, pair) { return { [pair[0]]: pair[1] } }, {});
@@ -739,7 +898,7 @@ function getSettings() {
pageInfoText.innerText = 'Loading settings';
return get('/static/settings.json', cancel)
.then(function(response) {
- var result = JSON.parse(response);
+ var result = JSON.parse(response.responseText);
console.log("settings response:", result);
GlobalVars.settings = result;
pageInfoText.innerText = 'Have settings.';
diff --git a/style.css b/style.css
index 1b09b4b..71efca5 100644
--- a/style.css
+++ b/style.css
@@ -28,3 +28,12 @@ header {
.attachment {
display: flow-root;
}
+
+.pagination a {
+ margin: 1em;
+ font-size: 2em;
+}
+
+main nav {
+ margin: 1em;
+}