refactor: internationalise pagination and clean up related code

This commit is contained in:
frosty 2026-04-01 05:49:18 +03:00
parent c6bdeecb2a
commit 614bd26cb3
7 changed files with 191 additions and 158 deletions

View file

@ -15,6 +15,30 @@ static char *build_images_request_cache_key(const char *query, int page,
return cache_compute_key(query, page, scope_key);
}
static char *build_images_href(const char *query, int page) {
const char *safe_query = query ? query : "";
size_t needed = strlen("/images?q=") + strlen(safe_query) + 1;
if (page > 1)
needed += strlen("&p=") + 16;
char *href = (char *)malloc(needed);
if (!href)
return NULL;
snprintf(href, needed, "/images?q=%s", safe_query);
if (page > 1) {
char page_buf[16];
snprintf(page_buf, sizeof(page_buf), "%d", page);
strcat(href, "&p=");
strcat(href, page_buf);
}
return href;
}
static char *images_href_builder(int page, void *data) {
return build_images_href((const char *)data, page);
}
int images_handler(UrlParams *params) {
extern Config global_config;
TemplateContext ctx = new_context();
@ -33,14 +57,6 @@ int images_handler(UrlParams *params) {
}
}
char page_str[16], prev_str[16], next_str[16], two_prev_str[16],
two_next_str[16];
snprintf(page_str, sizeof(page_str), "%d", page);
snprintf(prev_str, sizeof(prev_str), "%d", page > 1 ? page - 1 : 0);
snprintf(next_str, sizeof(next_str), "%d", page + 1);
snprintf(two_prev_str, sizeof(two_prev_str), "%d", page > 2 ? page - 2 : 0);
snprintf(two_next_str, sizeof(two_next_str), "%d", page + 2);
context_set(&ctx, "query", raw_query);
char *theme = get_theme("");
@ -55,11 +71,15 @@ int images_handler(UrlParams *params) {
const char *error_images_msg = beaker_get_locale_value(locale, "error_images");
if (!error_images_msg) error_images_msg = "Error fetching images";
context_set(&ctx, "page", page_str);
context_set(&ctx, "prev_page", prev_str);
context_set(&ctx, "next_page", next_str);
context_set(&ctx, "two_prev_page", two_prev_str);
context_set(&ctx, "two_next_page", two_next_str);
char ***pager_matrix = NULL;
int *pager_inner_counts = NULL;
int pager_count = build_pagination(page, locale, images_href_builder,
(void *)raw_query, &pager_matrix,
&pager_inner_counts);
if (pager_count > 0) {
context_set_array_of_arrays(&ctx, "pagination_links", pager_matrix,
pager_count, pager_inner_counts);
}
char *display_query = url_decode_query(raw_query);
context_set(&ctx, "query", display_query);
@ -170,6 +190,16 @@ int images_handler(UrlParams *params) {
free(image_matrix);
free(inner_counts);
if (pager_count > 0) {
for (int i = 0; i < pager_count; i++) {
for (int j = 0; j < LINK_FIELD_COUNT; j++)
free(pager_matrix[i][j]);
free(pager_matrix[i]);
}
free(pager_matrix);
free(pager_inner_counts);
}
free_image_results(results, result_count);
free(request_cache_key);
free(display_query);

View file

@ -32,8 +32,6 @@ typedef struct {
enum {
RESULT_FIELD_COUNT = 6,
LINK_FIELD_COUNT = 3,
PAGER_WINDOW_SIZE = 5,
};
static InfoBox fetch_wiki_wrapper(char *query) {
@ -189,66 +187,6 @@ static int add_infobox_to_collection(InfoBox *infobox, char ****collection,
return current_count + 1;
}
static int add_link_to_collection(const char *href, const char *label,
const char *class_name, char ****collection,
int **inner_counts, int current_count) {
char ***old_collection = *collection;
int *old_inner_counts = *inner_counts;
char ***new_collection =
(char ***)malloc(sizeof(char **) * (current_count + 1));
int *new_inner_counts =
(int *)malloc(sizeof(int) * (current_count + 1));
if (!new_collection || !new_inner_counts) {
free(new_collection);
free(new_inner_counts);
return current_count;
}
if (*collection && current_count > 0) {
memcpy(new_collection, *collection, sizeof(char **) * current_count);
}
if (*inner_counts && current_count > 0) {
memcpy(new_inner_counts, *inner_counts, sizeof(int) * current_count);
}
*collection = new_collection;
*inner_counts = new_inner_counts;
(*collection)[current_count] =
(char **)malloc(sizeof(char *) * LINK_FIELD_COUNT);
if (!(*collection)[current_count]) {
*collection = old_collection;
*inner_counts = old_inner_counts;
free(new_collection);
free(new_inner_counts);
return current_count;
}
(*collection)[current_count][0] = strdup(href ? href : "");
(*collection)[current_count][1] = strdup(label ? label : "");
(*collection)[current_count][2] = strdup(class_name ? class_name : "");
if (!(*collection)[current_count][0] || !(*collection)[current_count][1] ||
!(*collection)[current_count][2]) {
free((*collection)[current_count][0]);
free((*collection)[current_count][1]);
free((*collection)[current_count][2]);
free((*collection)[current_count]);
*collection = old_collection;
*inner_counts = old_inner_counts;
free(new_collection);
free(new_inner_counts);
return current_count;
}
(*inner_counts)[current_count] = LINK_FIELD_COUNT;
free(old_collection);
free(old_inner_counts);
return current_count + 1;
}
static int add_warning_to_collection(const char *engine_name,
const char *warning_message,
char ****collection, int **inner_counts,
@ -385,6 +323,16 @@ static char *build_search_href(const char *query, const char *engine_id,
return href;
}
typedef struct {
const char *query;
const char *engine_id;
} SearchHrefData;
static char *search_href_builder(int page, void *data) {
SearchHrefData *d = (SearchHrefData *)data;
return build_search_href(d->query, d->engine_id, page);
}
static char *build_search_request_cache_key(const char *query,
const char *engine_id, int page,
const char *client_key) {
@ -436,6 +384,16 @@ int results_handler(UrlParams *params) {
snprintf(page_str, sizeof(page_str), "%d", page);
context_set(&ctx, "page", page_str);
char prev_str[16], next_str[16], two_prev_str[16], two_next_str[16];
snprintf(prev_str, sizeof(prev_str), "%d", page > 1 ? page - 1 : 0);
snprintf(next_str, sizeof(next_str), "%d", page + 1);
snprintf(two_prev_str, sizeof(two_prev_str), "%d", page > 2 ? page - 2 : 0);
snprintf(two_next_str, sizeof(two_next_str), "%d", page + 2);
context_set(&ctx, "prev_page", prev_str);
context_set(&ctx, "next_page", next_str);
context_set(&ctx, "two_prev_page", two_prev_str);
context_set(&ctx, "two_next_page", two_next_str);
if (!raw_query || strlen(raw_query) == 0) {
send_redirect("/");
free_context(&ctx);
@ -810,43 +768,10 @@ int results_handler(UrlParams *params) {
char ***pager_matrix = NULL;
int *pager_inner_counts = NULL;
int pager_count = 0;
int pager_start = page <= 3 ? 1 : page - 2;
int pager_end = pager_start + PAGER_WINDOW_SIZE - 1;
if (page > 3) {
char *first_href = build_search_href(raw_query, selected_engine_id, 1);
pager_count = add_link_to_collection(first_href, "First", "pagination-btn",
&pager_matrix, &pager_inner_counts,
pager_count);
free(first_href);
}
if (page > 1) {
char *prev_href =
build_search_href(raw_query, selected_engine_id, page - 1);
pager_count = add_link_to_collection(prev_href, "Prev", "pagination-btn",
&pager_matrix, &pager_inner_counts,
pager_count);
free(prev_href);
}
for (int i = pager_start; i <= pager_end; i++) {
char label[16];
snprintf(label, sizeof(label), "%d", i);
char *page_href = build_search_href(raw_query, selected_engine_id, i);
pager_count = add_link_to_collection(
page_href, label,
i == page ? "pagination-btn pagination-current" : "pagination-btn",
&pager_matrix, &pager_inner_counts, pager_count);
free(page_href);
}
char *next_href = build_search_href(raw_query, selected_engine_id, page + 1);
pager_count = add_link_to_collection(next_href, "Next", "pagination-btn",
&pager_matrix, &pager_inner_counts,
pager_count);
free(next_href);
SearchHrefData href_data = { .query = raw_query, .engine_id = selected_engine_id };
int pager_count = build_pagination(page, locale, search_href_builder,
&href_data, &pager_matrix,
&pager_inner_counts);
if (pager_count > 0) {
context_set_array_of_arrays(&ctx, "pagination_links", pager_matrix,

View file

@ -1,5 +1,6 @@
#include "Utility.h"
#include <beaker.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -32,3 +33,101 @@ char *get_locale(const char *default_locale) {
free(cookie);
return strdup(default_locale);
}
int add_link_to_collection(const char *href, const char *label,
const char *class_name, char ****collection,
int **inner_counts, int current_count) {
char ***old_collection = *collection;
int *old_inner_counts = *inner_counts;
char ***new_collection =
(char ***)malloc(sizeof(char **) * (current_count + 1));
int *new_inner_counts =
(int *)malloc(sizeof(int) * (current_count + 1));
if (!new_collection || !new_inner_counts) {
free(new_collection);
free(new_inner_counts);
return current_count;
}
if (*collection && current_count > 0) {
memcpy(new_collection, *collection, sizeof(char **) * current_count);
}
if (*inner_counts && current_count > 0) {
memcpy(new_inner_counts, *inner_counts, sizeof(int) * current_count);
}
*collection = new_collection;
*inner_counts = new_inner_counts;
(*collection)[current_count] =
(char **)malloc(sizeof(char *) * LINK_FIELD_COUNT);
if (!(*collection)[current_count]) {
*collection = old_collection;
*inner_counts = old_inner_counts;
free(new_collection);
free(new_inner_counts);
return current_count;
}
(*collection)[current_count][0] = strdup(href ? href : "");
(*collection)[current_count][1] = strdup(label ? label : "");
(*collection)[current_count][2] = strdup(class_name ? class_name : "");
if (!(*collection)[current_count][0] || !(*collection)[current_count][1] ||
!(*collection)[current_count][2]) {
free((*collection)[current_count][0]);
free((*collection)[current_count][1]);
free((*collection)[current_count][2]);
free((*collection)[current_count]);
*collection = old_collection;
*inner_counts = old_inner_counts;
free(new_collection);
free(new_inner_counts);
return current_count;
}
(*inner_counts)[current_count] = LINK_FIELD_COUNT;
free(old_collection);
free(old_inner_counts);
return current_count + 1;
}
int build_pagination(int page, const char *locale,
char *(*href_builder)(int page, void *data), void *data,
char ****out_matrix, int **out_inner_counts) {
enum { PAGER_WINDOW_SIZE = 5 };
*out_matrix = NULL;
*out_inner_counts = NULL;
int count = 0;
int pager_start = page <= 3 ? 1 : page - 2;
int pager_end = pager_start + PAGER_WINDOW_SIZE - 1;
if (page > 1) {
char *href = href_builder(page - 1, data);
count = add_link_to_collection(href, "<", "pagination-btn prev",
out_matrix, out_inner_counts, count);
free(href);
}
for (int i = pager_start; i <= pager_end; i++) {
char label[16];
snprintf(label, sizeof(label), "%d", i);
char *href = href_builder(i, data);
count = add_link_to_collection(
href, label,
i == page ? "pagination-btn pagination-current" : "pagination-btn",
out_matrix, out_inner_counts, count);
free(href);
}
char *href = href_builder(page + 1, data);
count = add_link_to_collection(href, ">", "pagination-btn next",
out_matrix, out_inner_counts, count);
free(href);
return count;
}

View file

@ -3,8 +3,18 @@
#include <beaker.h>
#define LINK_FIELD_COUNT 3
int hex_to_int(char c);
char *get_theme(const char *default_theme);
char *get_locale(const char *default_locale);
int add_link_to_collection(const char *href, const char *label,
const char *class_name, char ****collection,
int **inner_counts, int current_count);
int build_pagination(int page, const char *locale,
char *(*href_builder)(int page, void *data), void *data,
char ****out_matrix, int **out_inner_counts);
#endif

View file

@ -927,3 +927,5 @@ header .logo-link:hover {
flex-direction: column;
}
}

View file

@ -65,48 +65,15 @@
</div>
{{endfor}}
</div>
{{if exists pagination_links}}
<nav class="pagination">
<a class="pagination-btn prev" href="/images?q={{query}}&p={{prev_page}}">
&larr;
</a>
{{if two_prev_page != 0}}
<a class="pagination-btn prev" href="/images?q={{query}}&p={{two_prev_page}}">
{{two_prev_page}}
</a>
{{endif}}
{{if prev_page != 0}}
<a class="pagination-btn prev" href="/images?q={{query}}&p={{prev_page}}">
{{prev_page}}
</a>
{{endif}}
<a class="pagination-btn pagination-current" href="/images?q={{query}}&p={{page}}">
{{page}}
</a>
<a class="pagination-btn next" href="/images?q={{query}}&p={{next_page}}">
{{next_page}}
</a>
<a class="pagination-btn next" href="/images?q={{query}}&p={{two_next_page}}">
{{two_next_page}}
</a>
{{if prev_page == 0}}
<a class="pagination-btn prev" href="/images?q={{query}}&p=4">
4
</a>
{{endif}}
{{if two_prev_page == 0}}
<a class="pagination-btn prev" href="/images?q={{query}}&p=5">
5
</a>
{{endif}}
<a class="pagination-btn next" href="/images?q={{query}}&p={{next_page}}">
&rarr;
{{for link in pagination_links}}
<a class="{{link[2]}}" href="{{link[0]}}">
{{link[1]}}
</a>
{{endfor}}
</nav>
{{endif}}
</main>
</body>