diff --git a/static/skin/i18n/en.json b/static/skin/i18n/en.json index 9345a1cb5..7add683cc 100644 --- a/static/skin/i18n/en.json +++ b/static/skin/i18n/en.json @@ -51,8 +51,8 @@ , "torrent-download-link-text": "BitTorrent" , "torrent-download-alt-text": "Download via BitTorrent" , "library-opds-feed-all-entries": "Library OPDS Feed - All entries" - , "filter-by-tag": "Filter by tag \"{{TAG}}\"" - , "stop-filtering-by-tag": "Stop filtering by tag \"{{TAG}}\"" + , "filter-by-tag": "Filter by tag \"{{{TAG}}}\"" + , "stop-filtering-by-tag": "Stop filtering by tag \"{{{TAG}}}\"" , "library-opds-feed-parameterised": "Library OPDS Feed - entries matching {{#LANG}}\nLanguage: {{LANG}} {{/LANG}}{{#CATEGORY}}\nCategory: {{CATEGORY}} {{/CATEGORY}}{{#TAG}}\nTag: {{TAG}} {{/TAG}}{{#Q}}\nQuery: {{Q}} {{/Q}}" , "welcome-to-kiwix-server": "Welcome to Kiwix Server" , "download-links-heading": "Download links for {{BOOK_TITLE}}" diff --git a/static/skin/index.js b/static/skin/index.js index 13359cbcf..873b187f0 100644 --- a/static/skin/index.js +++ b/static/skin/index.js @@ -105,6 +105,14 @@ return ''; } + // Borrowed from https://stackoverflow.com/a/1912522 + function htmlDecode(input){ + var e = document.createElement('textarea'); + e.innerHTML = input; + // handle case of empty input + return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue; + } + function htmlEncode(str) { return str.replace(/[\u00A0-\u9999<>\&]/gim, (i) => `&#${i.charCodeAt(0)};`); } @@ -121,9 +129,14 @@ function generateTagLink(tagValue) { tagValue = tagValue.toLowerCase(); - const htmlEncodedTagValue = htmlEncode(tagValue); const tagMessage = $t("filter-by-tag", {TAG: tagValue}); - return `${htmlEncodedTagValue}` + const spanElement = document.createElement("span"); + spanElement.className = 'tag__link'; + spanElement.setAttribute('aria-label', tagMessage); + spanElement.setAttribute('title', tagMessage); + spanElement.setAttribute('data-tag', tagValue); + spanElement.innerHTML = htmlEncode(tagValue); + return spanElement.outerHTML; } function generateBookHtml(book, sort = false) { @@ -144,7 +157,7 @@ const mulLangList = langCodesList.filter(x => languages.hasOwnProperty(x)).map(x => languages[x]); language = mulLangList.join(', '); } - const tags = getInnerHtml(book, 'tags'); + const tags = htmlDecode(getInnerHtml(book, 'tags')); const tagList = tags.split(';').filter(tag => {return !(tag.startsWith('_'))}); const tagFilterLinks = tagList.map((tagValue) => generateTagLink(tagValue)); const tagHtml = tagFilterLinks.join(' | '); @@ -492,7 +505,7 @@ function addTagElement(tagValue, resetFilter) { const tagElement = document.getElementsByClassName('tagFilterLabel')[0]; tagElement.style.display = 'inline-block'; - tagElement.innerHTML = `${tagValue}`; + tagElement.innerHTML = htmlEncode(tagValue); const tagMessage = $t("stop-filtering-by-tag", {TAG: tagValue}); tagElement.setAttribute('aria-label', tagMessage); tagElement.setAttribute('title', tagMessage);