philomena/assets/js/search.ts

86 lines
2.7 KiB
TypeScript
Raw Permalink Normal View History

2024-11-10 04:54:09 +01:00
import { assertNotNull, assertNotUndefined } from './utils/assert';
import { $, $$, showEl, hideEl } from './utils/dom';
import { delegate, leftClick } from './utils/events';
import { addTag } from './tagsinput';
function focusAndSelectLast(field: HTMLInputElement, characterCount: number) {
field.focus();
field.selectionStart = field.value.length - characterCount;
field.selectionEnd = field.value.length;
}
function prependToLast(field: HTMLInputElement, value: string) {
// Find the last comma in the input and advance past it
const separatorIndex = field.value.lastIndexOf(',');
const advanceBy = field.value[separatorIndex + 1] === ' ' ? 2 : 1;
// Insert the value string at the new location
field.value = [
field.value.slice(0, separatorIndex + advanceBy),
value,
field.value.slice(separatorIndex + advanceBy),
].join('');
}
function getAssociatedData(target: HTMLElement) {
const form = assertNotNull(target.closest('form'));
const input = assertNotNull($<HTMLInputElement>('.js-search-field', form));
const helpBoxes = $$<HTMLDivElement>('[data-search-help]', form);
return { input, helpBoxes };
}
function showHelp(helpBoxes: HTMLDivElement[], typeName: string, subject: string) {
for (const helpBox of helpBoxes) {
// Get the subject name span
const subjectName = assertNotNull($<HTMLElement>('.js-search-help-subject', helpBox));
// Take the appropriate action for this help box
if (helpBox.dataset.searchHelp === typeName) {
subjectName.textContent = subject;
showEl(helpBox);
} else {
hideEl(helpBox);
}
}
}
function onSearchAdd(_event: Event, target: HTMLAnchorElement) {
// Load form
const { input, helpBoxes } = getAssociatedData(target);
// Get data for this link
const addValue = assertNotUndefined(target.dataset.searchAdd);
const showHelpValue = assertNotUndefined(target.dataset.searchShowHelp);
const selectLastValue = target.dataset.searchSelectLast;
// Add the tag
addTag(input, addValue);
// Show associated help, if available
showHelp(helpBoxes, showHelpValue, assertNotNull(target.textContent));
// Select last characters, if requested
if (selectLastValue) {
focusAndSelectLast(input, Number(selectLastValue));
}
}
function onSearchPrepend(_event: Event, target: HTMLAnchorElement) {
// Load form
const { input } = getAssociatedData(target);
// Get data for this link
const prependValue = assertNotUndefined(target.dataset.searchPrepend);
// Prepend
prependToLast(input, prependValue);
}
export function setupSearch() {
delegate(document, 'click', {
'form.js-search-form a[data-search-add][data-search-show-help]': leftClick(onSearchAdd),
'form.js-search-form a[data-search-prepend]': leftClick(onSearchPrepend),
});
}