replaced topbar with custom topbar

This commit is contained in:
Manan Jethwani 2021-05-11 20:25:05 +05:30
parent 619dbf4e85
commit 9d5abd7e35
6 changed files with 118 additions and 75 deletions

View File

@ -325,7 +325,7 @@ InternalServer::get_matching_if_none_match_etag(const RequestContext& r) const
std::unique_ptr<Response> InternalServer::build_homepage(const RequestContext& request)
{
return ContentResponse::build(*this, RESOURCE::templates::index_html, homepage_data(), "text/html; charset=utf-8");
return ContentResponse::build(*this, RESOURCE::templates::index_html, homepage_data(), "text/html; charset=utf-8", true);
}
std::unique_ptr<Response> InternalServer::handle_meta(const RequestContext& request)

View File

@ -107,7 +107,7 @@ class InternalServer {
std::string m_server_id;
friend std::unique_ptr<Response> Response::build(const InternalServer& server);
friend std::unique_ptr<ContentResponse> ContentResponse::build(const InternalServer& server, const std::string& content, const std::string& mimetype);
friend std::unique_ptr<ContentResponse> ContentResponse::build(const InternalServer& server, const std::string& content, const std::string& mimetype, bool isHomePage);
friend std::unique_ptr<Response> ItemResponse::build(const InternalServer& server, const RequestContext& request, const zim::Item& item);
friend std::unique_ptr<Response> Response::build_500(const InternalServer& server, const std::string& msg);

View File

@ -349,21 +349,21 @@ ContentResponse::ContentResponse(const std::string& root, bool verbose, bool wit
add_header(MHD_HTTP_HEADER_CONTENT_TYPE, m_mimeType);
}
std::unique_ptr<ContentResponse> ContentResponse::build(const InternalServer& server, const std::string& content, const std::string& mimetype)
std::unique_ptr<ContentResponse> ContentResponse::build(const InternalServer& server, const std::string& content, const std::string& mimetype, bool isHomePage)
{
return std::unique_ptr<ContentResponse>(new ContentResponse(
server.m_root,
server.m_verbose.load(),
server.m_withTaskbar,
server.m_withTaskbar && !isHomePage,
server.m_withLibraryButton,
server.m_blockExternalLinks,
content,
mimetype));
}
std::unique_ptr<ContentResponse> ContentResponse::build(const InternalServer& server, const std::string& template_str, kainjow::mustache::data data, const std::string& mimetype) {
std::unique_ptr<ContentResponse> ContentResponse::build(const InternalServer& server, const std::string& template_str, kainjow::mustache::data data, const std::string& mimetype, bool isHomePage) {
auto content = render_template(template_str, data);
return ContentResponse::build(server, content, mimetype);
return ContentResponse::build(server, content, mimetype, isHomePage);
}
ItemResponse::ItemResponse(bool verbose, const zim::Item& item, const std::string& mimetype, const ByteRange& byterange) :

View File

@ -79,8 +79,8 @@ class Response {
class ContentResponse : public Response {
public:
ContentResponse(const std::string& root, bool verbose, bool withTaskbar, bool withLibraryButton, bool blockExternalLinks, const std::string& content, const std::string& mimetype);
static std::unique_ptr<ContentResponse> build(const InternalServer& server, const std::string& content, const std::string& mimetype);
static std::unique_ptr<ContentResponse> build(const InternalServer& server, const std::string& template_str, kainjow::mustache::data data, const std::string& mimetype);
static std::unique_ptr<ContentResponse> build(const InternalServer& server, const std::string& content, const std::string& mimetype, bool isHomePage = false);
static std::unique_ptr<ContentResponse> build(const InternalServer& server, const std::string& template_str, kainjow::mustache::data data, const std::string& mimetype, bool isHomePage = false);
void set_taskbar(const std::string& bookName, const std::string& bookTitle);

View File

@ -1,13 +1,24 @@
const root = $( `link[type='root']` ).attr("href");
let viewPortHeight = window.innerHeight;
let count = Math.floor(viewPortHeight/100 + 1) * 3;
let isFetching = false;
let isEnd = false;
let prevStart = 0;
const params = new URLSearchParams(window.location.search);
const basicConfig = {
'start': 0,
'count': Math.floor(viewPortHeight/100 + 1) * 3
};
async function loadAndDisplay(query, append = false) {
function queryUrlBuilder() {
let url = `${root}/catalog/search?`
Object.keys(basicConfig).forEach((key, idx) => {
url += `${key}=${basicConfig[key]}${idx !== Object.keys(basicConfig).length - 1 ? '&' : ''}`;
});
return url + (params.toString() ? `&${params.toString()}` : '');
}
async function loadAndDisplayBooks(append = false) {
isFetching = true;
await fetch(`${root}/catalog/search${query}`)
await fetch(queryUrlBuilder())
.then(async (resp) => {
const data = new window.DOMParser().parseFromString(await resp.text(), 'application/xml');
const books = data.querySelectorAll("entry");
@ -31,6 +42,29 @@ async function loadAndDisplay(query, append = false) {
});
}
async function loadAndDisplayOptions(nodeQuery, query) {
// currently taking an array in place of query, will replace it with query while fetching data from backend later on.
query.forEach((option) => {
let value = Object.keys(option)[0];
let label = option[value];
document.querySelector(nodeQuery).innerHTML += `<option value='${value}'>${label}</option>`;
})
}
async function filterBooks(filterType, filterValue) {
isEnd = false;
isFetching = false;
basicConfig['start'] = 0;
const params = new URLSearchParams(window.location.search);
if (!filterValue) {
params.delete(filterType);
} else {
params.set(filterType, filterValue);
}
window.location.search = params.toString();
loadAndDisplayBooks();
}
function getInnerHtml(node, query) {
return node.querySelector(query).innerHTML;
}
@ -38,21 +72,24 @@ function getInnerHtml(node, query) {
window.addEventListener('resize', async () => {
if (isFetching || isEnd) return;
viewPortHeight = window.innerHeight;
count = Math.floor(viewPortHeight/100 + 1) * 3;
start = prevStart + count;
loadAndDisplay(`?start=${start}&count=${count}`, true);
prevStart = start;
})
basicConfig['count'] = Math.floor(viewPortHeight/100 + 1) * 3;
basicConfig['start'] = basicConfig['start'] + basicConfig['count'];
loadAndDisplayBooks(true);
});
window.addEventListener('scroll', async () => {
if (isFetching || isEnd) return;
if (viewPortHeight + window.scrollY >= document.body.offsetHeight) {
start = prevStart + count;
loadAndDisplay(`?start=${start}&count=${count}`, true);
prevStart = start;
basicConfig['start'] = basicConfig['start'] + basicConfig['count'];
loadAndDisplayBooks(true);
}
});
window.onload = async (event) => {
loadAndDisplay(`?start=0&count=${count}`);
loadAndDisplayBooks();
loadAndDisplayOptions('#languageFilter', [{'eng': 'English'}, {'fra': 'french'}, {'ara': 'arab'}, {'hin': 'Hindi'}]);
loadAndDisplayOptions('#categoryFilter', [{'stack_exchange': 'stack exchange'}, {'wikipedia': 'wikipedia'}, {'phet': 'phet'}, {'youtube': 'youtube'}]);
for (const key of params.keys()) {
document.getElementsByName(key)[0].value = params.get(key);
}
}

View File

@ -1,57 +1,63 @@
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width">
<title>Welcome to Kiwix Server</title>
<script type="text/javascript" src="{{root}}/skin/jquery-ui/external/jquery/jquery.js"></script>
<script type="text/javascript" src="{{root}}/skin/jquery-ui/jquery-ui.min.js"></script>
<link type="text/css" href="{{root}}/skin/jquery-ui/jquery-ui.min.css" rel="Stylesheet" />
<link type="text/css" href="{{root}}/skin/jquery-ui/jquery-ui.theme.min.css" rel="Stylesheet" />
<style>
body {
background:
radial-gradient(#EEEEEE 15%, transparent 16%) 0 0,
radial-gradient(#EEEEEE 15%, transparent 16%) 8px 8px,
radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 0 1px,
radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 8px 9px;
background-color:#E8E8E8;
background-size:16px 16px;
margin-left: auto;
margin-right: auto;
max-width: 1100px;
}
.book__list { text-align: center; }
.book {
display: inline-block; vertical-align: bottom; margin: 8px; padding: 12px 15px; width: 300px;
border: 1px solid #ccc; border-radius: 8px;
text-align: left; color: #000; font-family: sans-serif; font-size: 13px;
background-color:#F1F1F1;
box-shadow: 2px 2px 5px 0px #ccc;
}
.book:hover { background-color: #F9F9F9; box-shadow: none;}
.book__background { background-repeat: no-repeat; background-size: 48px 48px; background-position: top right; }
.book__title {
padding: 0 55px 0 0;overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
font-size: 18px; color: #0645ad; line-height: 1em;
}
.book__description {
padding: 5px 55px 5px 0px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
font-size: 15px; line-height: 1em;
}
.book__info { color: #777; font-weight: bold; font-size: 13px; line-height: 1em; }
</style>
<script type="text/javascript" src="{{root}}/skin/index.js" defer></script>
</head>
<body class="kiwix">
<div class="kiwix">
<div class='book__list'></div>
</div>
<div id="kiwixfooter">
Powered by <a href="https://kiwix.org">Kiwix</a>
</div>
</body>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width">
<title>Welcome to Kiwix Server</title>
<script type="text/javascript" src="{{root}}/skin/jquery-ui/external/jquery/jquery.js"></script>
<script type="text/javascript" src="{{root}}/skin/jquery-ui/jquery-ui.min.js"></script>
<link type="text/css" href="{{root}}/skin/jquery-ui/jquery-ui.min.css" rel="Stylesheet" />
<link type="text/css" href="{{root}}/skin/jquery-ui/jquery-ui.theme.min.css" rel="Stylesheet" />
<style>
body {
background:
radial-gradient(#EEEEEE 15%, transparent 16%) 0 0,
radial-gradient(#EEEEEE 15%, transparent 16%) 8px 8px,
radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 0 1px,
radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 8px 9px;
background-color:#E8E8E8;
background-size:16px 16px;
margin-left: auto;
margin-right: auto;
max-width: 1100px;
}
.book__list { text-align: center; }
.book {
display: inline-block; vertical-align: bottom; margin: 8px; padding: 12px 15px; width: 300px;
border: 1px solid #ccc; border-radius: 8px;
text-align: left; color: #000; font-family: sans-serif; font-size: 13px;
background-color:#F1F1F1;
box-shadow: 2px 2px 5px 0px #ccc;
}
.book:hover { background-color: #F9F9F9; box-shadow: none;}
.book__background { background-repeat: no-repeat; background-size: 48px 48px; background-position: top right; }
.book__title {
padding: 0 55px 0 0;overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
font-size: 18px; color: #0645ad; line-height: 1em;
}
.book__description {
padding: 5px 55px 5px 0px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
font-size: 15px; line-height: 1em;
}
.book__info { color: #777; font-weight: bold; font-size: 13px; line-height: 1em; }
</style>
<script type="text/javascript" src="{{root}}/skin/index.js" defer></script>
</head>
<body class="kiwix">
<div class='kiwixHomeNavbar'>
<select name="lang" id="languageFilter" onchange="filterBooks('lang', this.value)">
<option value="" disabled selected>Languages</option>
</select>
<select name="category" id="categoryFilter" onchange="filterBooks('category', this.value)">
<option value="" disabled selected>Categories</option>
</select>
<input type="text" name="q" id="searchFilter" onchange="filterBooks('q', this.value)">
</div>
<div class="kiwix">
<div class='book__list'></div>
</div>
<div id="kiwixfooter">
Powered by <a href="https://kiwix.org">Kiwix</a>
</div>
</body>
</html>