Skip to content

Instantly share code, notes, and snippets.

@zopyx
Created January 24, 2024 08:40
Show Gist options
  • Save zopyx/9897d692571caccba60e49480fc36461 to your computer and use it in GitHub Desktop.
Save zopyx/9897d692571caccba60e49480fc36461 to your computer and use it in GitHub Desktop.
/* global instantsearch */
/* global vars first */
var remote_url = CONTEXT_URL + "/@@typesense-search-settings";
var ts_settings = null;
/* Show initially all hits with all form control (true)
* or show only empty search field by default (false).
*/
var SHOW_ALL_HITS_INITIALLY = true;
const TRANSLATIONS = {
"10-per-page": {
de: "10 je Seite",
en: "10 per page",
},
"20-per-page": {
de: "20 je Seite",
en: "20 per page",
},
"50-per-page": {
de: "50 je Seite",
en: "50 per page",
},
"100-per-page": {
de: "100 je Seite",
en: "100 per page",
},
"250-per-page": {
de: "250 je Seite",
en: "250 per page",
},
"placeholder-search-by-topic": {
de: "Suche nach Themengebiet",
en: "Search by topic",
},
"placeholder-search-by": {
de: "Suchbegriff(e) eingeben...",
en: "Search by",
},
hits: {
de: "Treffer",
en: "hits",
},
hit: {
de: "Treffer",
en: "hit",
},
"no-hits": {
de: "Keine Treffer",
en: "No hits",
},
"one-hit": {
de: "ein Treffer",
en: "one hit",
},
"show-more": {
de: "Alle Themengebiete",
en: "Show more",
},
"chapter-wise": {
de: "kapitelweise",
en: "chapter-wise",
},
"reset-filters": {
de: "Alle Filter zurücksetzen",
en: "Reset all filters",
},
"no-filters-set": {
de: "Keine Filter gesetzt",
en: "No filters set",
},
chapter: {
de: "Kapitel",
en: "Chapter",
},
"document-locked": {
de: "Zugriff nur für angemeldete Mitglieder unserer medizinischen Fachgesellschaften",
en: "Access only for logged-in members of our medical societies",
},
area: {
de: "Bereich",
en: "Section",
},
language: {
de: "Sprache",
en: "Language",
},
"filtered-by": {
de: "Gefiltert nach",
en: "Filtered by",
},
ayapedia: {
de: "AYApedia",
en: "AYApediaby",
},
"onkopedia-p": {
de: "Onkopedia Pflege",
},
onkopedia: {
de: "Onkopedia",
en: "Onkopedia",
},
"drug-assessment": {
de: "Arzneimittel",
},
"knowledge-database": {
de: "Wissensdatenbank",
},
"reset-search": {
de: "Eingabe löschen",
en: "Clear input",
},
de: {
de: "Deutsch",
en: "German",
},
en: {
de: "Englisch",
en: "English",
},
"area-label": {
de: "Bereich",
en: "Area",
},
"no-topics": {
de: "Keine passenden Themengebiete",
en: "No matching topics",
},
date: {
de: "Stand",
en: "Date",
},
};
/* translate */
function tr(msg_id) {
var arr = TRANSLATIONS[msg_id];
if (arr == undefined) {
console.log("Unknown msg_id " + msg_id);
return msg_id;
}
translation = TRANSLATIONS[msg_id][LANGUAGE];
if (translation == undefined) {
console.log("Unknown msg_id " + msg_id + "/" + LANGUAGE);
return msg_id;
}
return translation;
}
DOCUMENT_TYPE_ORDERING = [
"Leitlinie",
"Guideline",
"Algorithmus",
"Algorithm",
"Studienergebnisse",
"Protokolle",
"Wechselwirkungen und Nebenwirkungen",
"Frühe Nutzenbewertung",
"Fact Sheet",
"Zulassungen",
"AYApedia",
"Ayapedia",
"Datei/PDF",
"File/PDF",
"Dokument",
"Document",
"Nachricht",
"Anderer Inhalt",
];
AREA_ORDERING = [
"Onkopedia",
"Arzneimittel",
"Ayapedia",
"Pflege",
"Wissensdatenbank",
"Allgemein",
];
instantsearch.widgets.configure({
facetFilters: ['document_type:guideline']
});
function sort_document_type(d1, d2) {
var idx1 = DOCUMENT_TYPE_ORDERING.indexOf(d1.name);
var idx2 = DOCUMENT_TYPE_ORDERING.indexOf(d2.name);
return idx1 === idx2 ? 0 : (idx1> idx2? 1 : -1);
}
function sort_topic(t1, t2) {
return t1.name.localeCompare(t2.name, "de");
}
function sort_area(d1, d2) {
var idx1 = AREA_ORDERING.indexOf(d1.name);
var idx2 = AREA_ORDERING.indexOf(d2.name);
return idx1 === idx2 ? 0 : (idx1> idx2? 1 : -1);
}
/* Retrieve search settings through JSON */
function getSearchSettings() {
return $.getJSON({
type: "GET",
url: remote_url,
async: false,
}).responseText;
}
/* get settings form backend */
ts_settings = JSON.parse(getSearchSettings());
var is_anonymous = ts_settings.is_anonymous;
let area = ts_settings["area"];
let language = ts_settings["language"];
/* Query parameters from URL */
const urlSearchParams = new URLSearchParams(window.location.search);
const params = Object.fromEntries(urlSearchParams.entries());
// global language for UI
let LANGUAGE = language;
const typesenseInstantsearchAdapter = new TypesenseInstantSearchAdapter({
server: {
apiKey: ts_settings["api_key"],
nodes: ts_settings["nodes"],
},
// The following parameters are directly passed to Typesense's search API
// endpoint. So you can pass any parameters supported by the search
// endpoint below. queryBy is required. filterBy is managed and
// overridden by InstantSearch.js. To set it, you want to use one of the
// filter widgets like refinementList or use the `configure` widget.
additionalSearchParameters: {
query_by: ts_settings["query_by"],
query_by_weights: ts_settings["query_by_weights"],
sort_by: "sort_key:desc,_text_match:desc,date_sort_key:desc",
enable_highlight_v1: false,
highlight_full_fields: "none",
// exclude_fields: "text",
use_cache: true,
cache_ttl: 120,
},
transformRequest: (request) => {
return request;
},
});
const searchClient = typesenseInstantsearchAdapter.searchClient;
const search = instantsearch({
searchClient,
indexName: ts_settings["collection"],
searchFunction(helper) {
if (helper.state.query.length == 0) {
$("#search-control").hide();
$("#hits").hide();
$(".search-panel__filters").hide();
} else {
$("#search-control").show();
$("#hits").show();
$(".search-panel__filters").show();
}
helper.search();
},
});
function renderHit(hit, highlight) {
var hl_result = hit._highlightResult;
var title = hl_result.title.value;
var subtitle = hit.subtitle;
var topic = "";
if (hit.topic_de.length > 0) topic += hit.topic_de;
if (hit.specification_de && hit.specification_de.length >= 0)
topic += " → " + hit.specification_de;
if (hit.specification2_de && hit.specification2_de.length >= 0)
topic += " → " + hit.specification2_de;
/* Hide Plone content having "no-topic" as topic set */
if (topic == "no-topic") topic = "";
var figure_title = "";
if (hit.document_type == "algorithm")
figure_title = `<div class="hit-figure-title">${hit.figure_title}</div>`;
var svg_markup = "";
if (hit.svg_url) {
svg_markup = `<figure class="hit-figure"><object data="${hit.svg_url}" class="hit-svg" type="image/svg+xml"></object></figure>`;
}
if (
hit.document_fragment == "yes" &&
!["File", "News Item", "Document"].includes(hit.document_type)
) {
chapter_str = tr("chapter");
subtitle = `<div class="subtitle"> ➡ ${chapter_str} ${hit.section_number} ${hit._highlightResult.section_title.value}</div>`;
}
/*
text = `<div class="text-highlights">${hit._highlightResult.text.value}</div>`;
*/
text2 = "";
if (hit._snippetResult.text.matchedWords.length > 0) {
text2 = `<div class="text-snippets">${hit._snippetResult.text.value}</div>`;
}
anchor = "";
if (hit.anchor.length > 0) anchor = `#${hit.anchor}`;
locked = "";
locked_text = "";
if (is_anonymous && hit.public == false) {
locked = `<span class="hit-locked">🔒</span>`;
document_locked = tr("document-locked");
locked_text = `<div class="locked-text">${document_locked}</div>`;
}
date_str = "";
if (hit.date_str.indexOf("/") != -1) {
date_str = `(${tr("date")} ${hit.date_str})`;
}
hit_document_type =
LANGUAGE == "de" ? hit.document_type_de : hit.document_type_en;
hit_area = LANGUAGE == "de" ? hit.area_de : hit.area_en;
var area_label = tr("area-label");
return `
<div class="hit">
<div class="hit-title">${locked} <a target="_blank" class="hit-link" href="${hit.url}${anchor}">${title} ${date_str}</a></div>
<div class="hit-subtitle"> ${subtitle} </div>
<div class="hit-topic">${topic}</div>
${figure_title}
${svg_markup}
${locked_text}
${text2}
<div class="hit-meta">
<span class="hit-portal_type">${hit_document_type}</span> |
<span class="hit-area">${area_label}: ${hit_area}</span> |
<span class="hit-date">${hit.date_str}</span> |
<span class="hit-date">${hit.language} </span>
<span class="hit-date" hidden>Public=${hit.public} | </span>
<span class="hit-date" hidden>SortKey=${hit.sort_key}</span>
| Score: ${hit.text_match_info.score}
| Fragment: ${hit.document_fragment}
</div>
</div>`;
}
function renderStats(stats) {
var num_hits = stats.nbHits.toLocaleString("de-DE");
// if (stats.hasNoResults) return tr("no-hits");
if (stats.hasOneResults) return tr("one-hit");
if (stats.hasManyResults) {
var str_hits = tr("hits");
return `${num_hits} ${str_hits}`;
}
}
function transform_topic_items(items) {
// Filter out items where the label is 'no-topic'
return items.filter((item) => item.label !== "no-topic");
}
search.addWidgets([
instantsearch.widgets.searchBox({
container: "#searchbox",
showSubmit: false,
showReset: true,
placeholder: tr("placeholder-search-by"),
autofocus: false,
searchAsYouType: true,
showLoadingIndicator: true,
cssClasses: {
input: "form-control form-control-sm border border-light text-dark",
loadingIcon: "stroke-primary",
},
templates: {
reset: tr("reset-search"),
},
}),
instantsearch.widgets.configure({
hitsPerPage: 20,
}),
instantsearch.widgets.hits({
container: "#hits",
templates: {
item: renderHit,
empty: tr("no-hits"),
},
}),
instantsearch.widgets.currentRefinements({
container: "#current-refinements",
excludedAttributes: ["document_fragment", "query", "area", "language"],
}),
instantsearch.widgets.clearRefinements({
container: "#clear-refinements",
excludedAttributes: ["query", "area", "language"],
templates: {
resetLabel(hasRefinements) {
if (hasRefinements.hasRefinements) return tr("reset-filters");
else return tr("no-filters-set");
},
},
}),
instantsearch.widgets.pagination({
container: "#pagination",
root: "nav",
cssClasses: {
root: "navigation",
list: "pagination ",
item: "page-item ",
link: "text-decoration-none",
disabledItem: "text-muted",
selectedItem: "fw-bold text-primary",
},
}),
instantsearch.widgets.refinementList({
container: "#document-type",
attribute: `document_type_${LANGUAGE.toLowerCase()}`,
sortBy: sort_document_type,
limit: 20,
}),
instantsearch.widgets.toggleRefinement({
container: "#document-fragment",
attribute: "document_fragment",
on: "yes",
off: "no",
templates: {
labelText(count) {
return tr("chapter-wise");
},
},
}),
instantsearch.widgets.refinementList({
container: "#topic",
attribute: `topic_${LANGUAGE.toLowerCase()}`,
searchable: true,
limit: 10,
showMore: true,
showMoreLimit: 150,
sortBy: sort_topic,
searchablePlaceholder: tr("placeholder-search-by-topic"),
transformItems: transform_topic_items,
templates: {
searchableNoResults(data) {
return tr("no-topics");
},
showMoreText(data) {
return tr("show-more");
},
noRefinementRoot() {
return "xxx";
},
noResults() {
return "xxx";
},
},
}),
instantsearch.widgets.stats({
container: "#stats",
templates: {
text: renderStats,
},
cssClasses: {
text: "small",
},
}),
instantsearch.widgets.hitsPerPage({
container: "#hits-per-page",
items: [
{
label: tr("10-per-page"),
value: 10,
},
{
label: tr("20-per-page"),
value: 20,
default: true,
},
{
label: tr("50-per-page"),
value: 50,
},
{
label: tr("100-per-page"),
value: 100,
},
{
label: tr("250-per-page"),
value: 250,
},
],
cssClasses: {
select: "custom-select custom-select-sm",
},
}),
]);
/* If area is set, then use toggleRefinement instead of refinementList */
if (area.length == 0) {
search.addWidgets([
instantsearch.widgets.refinementList({
container: "#area",
attribute: `area_${LANGUAGE.toLowerCase()}`,
sortBy: sort_area,
}),
]);
} else {
$("#area").hide()
$("#area-label").hide()
search.addWidgets([
instantsearch.widgets.toggleRefinement({
container: "#area",
attribute: "area",
off: `area-${area}`,
on: `area-${area}`,
}),
]);
}
/* If language is set, then use toggleRefinement instead of refinementList */
if (language.length == 0) {
instantsearch.widgets.refinementList({
container: "#language",
attribute: "language",
sortBy: ["name:asc"],
})
} else {
$("#language").hide()
$("#language-label").hide()
search.addWidgets([
instantsearch.widgets.toggleRefinement({
container: "#language",
attribute: "language",
off: language,
on: language,
}),
]);
}
/* Hide refinements for knowledge database */
if (area == "knowledge-database") {
$("#document-fragment").hide()
$("#document-fragment-label").hide()
$("#topic").hide()
$("#topic-label").hide()
}
search.start();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment