mirror of
https://github.com/kiwix/libkiwix.git
synced 2025-09-07 22:27:00 -04:00
Add ability to filter by tags in kiwix serve
This change introduces filtering by tags. To filter, the user can click on the tag name and it will filter it. A label is added (clickable) to show the tag filter, it can be clicked to remove the filter
This commit is contained in:
parent
93f2686a94
commit
43ab6dfb6a
File diff suppressed because one or more lines are too long
@ -77,6 +77,13 @@
|
|||||||
return queryNode != null ? queryNode.innerHTML : "";
|
return queryNode != null ? queryNode.innerHTML : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function generateTagLink(tagValue) {
|
||||||
|
tagValue = tagValue.toLowerCase();
|
||||||
|
const humanFriendlyTagValue = humanFriendlyTitle(tagValue);
|
||||||
|
const tagMessage = `Filter by tag "${humanFriendlyTagValue}"`;
|
||||||
|
return `<span class='tag__link' aria-label='${tagMessage}' title='${tagMessage}' data-tag=${tagValue}>${humanFriendlyTagValue}</span>`
|
||||||
|
}
|
||||||
|
|
||||||
function generateBookHtml(book, sort = false) {
|
function generateBookHtml(book, sort = false) {
|
||||||
const link = book.querySelector('link[type="text/html"]').getAttribute('href');
|
const link = book.querySelector('link[type="text/html"]').getAttribute('href');
|
||||||
let iconUrl;
|
let iconUrl;
|
||||||
@ -91,9 +98,9 @@
|
|||||||
const langCode = getInnerHtml(book, 'language');
|
const langCode = getInnerHtml(book, 'language');
|
||||||
const language = languages[langCode];
|
const language = languages[langCode];
|
||||||
const tags = getInnerHtml(book, 'tags');
|
const tags = getInnerHtml(book, 'tags');
|
||||||
let tagHtml = tags.split(';').filter(tag => {return !(tag.split(':')[0].startsWith('_'))})
|
const tagList = tags.split(';').filter(tag => {return !(tag.startsWith('_'))});
|
||||||
.map((tag) => {return tag.charAt(0).toUpperCase() + tag.slice(1)})
|
const tagFilterLinks = tagList.map((tagValue) => generateTagLink(tagValue));
|
||||||
.join(' | ').replace(/_/g, ' ');
|
const tagHtml = tagFilterLinks.join(' | ');
|
||||||
let downloadLink;
|
let downloadLink;
|
||||||
let zimSize = 0;
|
let zimSize = 0;
|
||||||
try {
|
try {
|
||||||
@ -113,17 +120,21 @@
|
|||||||
}
|
}
|
||||||
const faviconAttr = iconUrl != undefined ? `style="background-image: url('${iconUrl}')"` : '';
|
const faviconAttr = iconUrl != undefined ? `style="background-image: url('${iconUrl}')"` : '';
|
||||||
const languageAttr = langCode != '' ? `title="${language}" aria-label="${language}"` : 'style="background-color: transparent"';
|
const languageAttr = langCode != '' ? `title="${language}" aria-label="${language}"` : 'style="background-color: transparent"';
|
||||||
divTag.innerHTML = `<a class="book__link" href="${link}" data-hover="Preview">
|
divTag.innerHTML = `
|
||||||
<div class="book__wrapper">
|
<div class="book__wrapper">
|
||||||
|
<a class="book__link" href="${link}" data-hover="Preview">
|
||||||
|
<div class="book__link__wrapper">
|
||||||
<div class="book__icon" ${faviconAttr}></div>
|
<div class="book__icon" ${faviconAttr}></div>
|
||||||
<div class="book__header">
|
<div class="book__header">
|
||||||
<div id="book__title">${title}</div>
|
<div id="book__title">${title}</div>
|
||||||
${downloadLink ? `<div class="book__download"><span data-link="${downloadLink}">Download ${humanFriendlyZimSize ? ` - ${humanFriendlyZimSize}</span></div>`: ''}` : ''}
|
${downloadLink ? `<div class="book__download"><span data-link="${downloadLink}">Download ${humanFriendlyZimSize ? ` - ${humanFriendlyZimSize}</span></div>`: ''}` : ''}
|
||||||
</div>
|
</div>
|
||||||
<div class="book__description" title="${description}">${description}</div>
|
<div class="book__description" title="${description}">${description}</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
<div class="book__languageTag" ${languageAttr}>${getLanguageCodeToDisplay(langCode)}</div>
|
<div class="book__languageTag" ${languageAttr}>${getLanguageCodeToDisplay(langCode)}</div>
|
||||||
<div class="book__tags"><div class="book__tags--wrapper">${tagHtml}</div></div>
|
<div class="book__tags"><div class="book__tags--wrapper">${tagHtml}</div></div>
|
||||||
</div></div></a>`;
|
</div></div>`;
|
||||||
return divTag;
|
return divTag;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,6 +344,7 @@
|
|||||||
insertModal(downloadButton);
|
insertModal(downloadButton);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
refreshTagLinks();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function resetAndFilter(filterType = '', filterValue = '') {
|
async function resetAndFilter(filterType = '', filterValue = '') {
|
||||||
@ -376,10 +388,45 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addTagElement(tagValue, resetFilter) {
|
||||||
|
const tagElement = document.getElementsByClassName('tagFilterLabel')[0];
|
||||||
|
tagElement.style.display = 'inline-block';
|
||||||
|
const humanFriendlyTagValue = humanFriendlyTitle(tagValue);
|
||||||
|
tagElement.innerHTML = `${humanFriendlyTagValue}`;
|
||||||
|
const tagMessage = `Stop filtering by tag "${humanFriendlyTagValue}"`;
|
||||||
|
tagElement.setAttribute('aria-label', tagMessage);
|
||||||
|
tagElement.setAttribute('title', tagMessage);
|
||||||
|
if (resetFilter)
|
||||||
|
resetAndFilter('tag', tagValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
function refreshTagLinks() {
|
||||||
|
const tagLinks = document.getElementsByClassName('tag__link');
|
||||||
|
[...tagLinks].forEach(elem => {
|
||||||
|
if (!elem.getAttribute('click-listener')) {
|
||||||
|
elem.addEventListener('click', () => addTagElement(elem.dataset.tag, true));
|
||||||
|
elem.setAttribute('click-listener', 'true');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeTagElement(resetFilter) {
|
||||||
|
const tagElement = document.getElementsByClassName('tagFilterLabel')[0];
|
||||||
|
tagElement.style.display = 'none';
|
||||||
|
if (resetFilter)
|
||||||
|
resetAndFilter('tag', '');
|
||||||
|
}
|
||||||
|
|
||||||
function updateVisibleParams() {
|
function updateVisibleParams() {
|
||||||
document.querySelectorAll('.filter').forEach(filter => {filter.value = params.get(filter.name) || ''});
|
document.querySelectorAll('.filter').forEach(filter => {filter.value = params.get(filter.name) || ''});
|
||||||
updateFilterColors();
|
updateFilterColors();
|
||||||
|
const tagKey = params.get('tag');
|
||||||
|
if (tagKey !== null && tagKey.trim() !== '') {
|
||||||
|
addTagElement(tagKey, false);
|
||||||
|
} else {
|
||||||
|
removeTagElement(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('resize', (event) => {
|
window.addEventListener('resize', (event) => {
|
||||||
@ -417,6 +464,8 @@
|
|||||||
document.querySelectorAll('.filter').forEach(filter => {
|
document.querySelectorAll('.filter').forEach(filter => {
|
||||||
filter.addEventListener('change', () => {resetAndFilter(filter.name, filter.value)});
|
filter.addEventListener('change', () => {resetAndFilter(filter.name, filter.value)});
|
||||||
});
|
});
|
||||||
|
const tagElement = document.getElementsByClassName('tagFilterLabel')[0];
|
||||||
|
tagElement.addEventListener('click', () => removeTagElement(true));
|
||||||
if (filters) {
|
if (filters) {
|
||||||
const currentLink = window.location.search;
|
const currentLink = window.location.search;
|
||||||
const newLink = `?${params.toString()}`;
|
const newLink = `?${params.toString()}`;
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<form id='kiwixSearchForm' class='kiwixNav__SearchForm'>
|
<form id='kiwixSearchForm' class='kiwixNav__SearchForm'>
|
||||||
<input type="text" name="q" placeholder="Search" id="searchFilter" class='kiwixSearch filter'>
|
<input type="text" name="q" placeholder="Search" id="searchFilter" class='kiwixSearch filter'>
|
||||||
|
<span class="kiwixButton tagFilterLabel"></span>
|
||||||
<input type="submit" class="kiwixButton kiwixButtonHover" value="Search"/>
|
<input type="submit" class="kiwixButton kiwixButtonHover" value="Search"/>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -179,12 +179,12 @@ R"EXPECTEDRESULT( src="/ROOT/skin/jquery-ui/external/jquery/jquery.js?cache
|
|||||||
src="/ROOT/skin/jquery-ui/jquery-ui.min.js?cacheid=d927c2ff"
|
src="/ROOT/skin/jquery-ui/jquery-ui.min.js?cacheid=d927c2ff"
|
||||||
href="/ROOT/skin/jquery-ui/jquery-ui.min.css?cacheid=e1de77b3"
|
href="/ROOT/skin/jquery-ui/jquery-ui.min.css?cacheid=e1de77b3"
|
||||||
href="/ROOT/skin/jquery-ui/jquery-ui.theme.min.css?cacheid=2a5841f9"
|
href="/ROOT/skin/jquery-ui/jquery-ui.theme.min.css?cacheid=2a5841f9"
|
||||||
href="/ROOT/skin/index.css?cacheid=1aca980a"
|
href="/ROOT/skin/index.css?cacheid=a1acc52f"
|
||||||
src: url("/ROOT/skin/fonts/Poppins.ttf?cacheid=af705837") format("truetype");
|
src: url("/ROOT/skin/fonts/Poppins.ttf?cacheid=af705837") format("truetype");
|
||||||
src: url("/ROOT/skin/fonts/Roboto.ttf?cacheid=84d10248") format("truetype");
|
src: url("/ROOT/skin/fonts/Roboto.ttf?cacheid=84d10248") format("truetype");
|
||||||
<script src="/ROOT/skin/isotope.pkgd.min.js?cacheid=2e48d392" defer></script>
|
<script src="/ROOT/skin/isotope.pkgd.min.js?cacheid=2e48d392" defer></script>
|
||||||
<script src="/ROOT/skin/iso6391To3.js?cacheid=ecde2bb3"></script>
|
<script src="/ROOT/skin/iso6391To3.js?cacheid=ecde2bb3"></script>
|
||||||
<script type="text/javascript" src="/ROOT/skin/index.js?cacheid=5f0f7683" defer></script>
|
<script type="text/javascript" src="/ROOT/skin/index.js?cacheid=e99ed2dd" defer></script>
|
||||||
)EXPECTEDRESULT"
|
)EXPECTEDRESULT"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user