mirror of
https://github.com/philomena-dev/philomena.git
synced 2025-02-13 09:24:22 +01:00
Merge pull request #410 from koloml/autocomplete-on-textareas
Support for textareas, added autocomplete to Complex Spoiler/Hide filter fields
This commit is contained in:
commit
ee9c6b8bd6
2 changed files with 29 additions and 10 deletions
|
@ -9,7 +9,9 @@ import { TermContext } from './query/lex';
|
||||||
import { $$ } from './utils/dom';
|
import { $$ } from './utils/dom';
|
||||||
import { fetchLocalAutocomplete, fetchSuggestions, SuggestionsPopup, TermSuggestion } from './utils/suggestions';
|
import { fetchLocalAutocomplete, fetchSuggestions, SuggestionsPopup, TermSuggestion } from './utils/suggestions';
|
||||||
|
|
||||||
let inputField: HTMLInputElement | null = null,
|
type InputFieldElement = HTMLInputElement | HTMLTextAreaElement;
|
||||||
|
|
||||||
|
let inputField: InputFieldElement | null = null,
|
||||||
originalTerm: string | undefined,
|
originalTerm: string | undefined,
|
||||||
originalQuery: string | undefined,
|
originalQuery: string | undefined,
|
||||||
selectedTerm: TermContext | null = null;
|
selectedTerm: TermContext | null = null;
|
||||||
|
@ -105,19 +107,36 @@ function keydownHandler(event: KeyboardEvent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function findSelectedTerm(targetInput: HTMLInputElement, searchQuery: string): TermContext | null {
|
function findSelectedTerm(targetInput: InputFieldElement, searchQuery: string): TermContext | null {
|
||||||
if (targetInput.selectionStart === null || targetInput.selectionEnd === null) return null;
|
if (targetInput.selectionStart === null || targetInput.selectionEnd === null) return null;
|
||||||
|
|
||||||
const selectionIndex = Math.min(targetInput.selectionStart, targetInput.selectionEnd);
|
const selectionIndex = Math.min(targetInput.selectionStart, targetInput.selectionEnd);
|
||||||
const terms = getTermContexts(searchQuery);
|
|
||||||
|
|
||||||
return terms.find(([range]) => range[0] < selectionIndex && range[1] >= selectionIndex) ?? null;
|
// Multi-line textarea elements should treat each line as the different search queries. Here we're looking for the
|
||||||
|
// actively edited line and use it instead of the whole value.
|
||||||
|
const activeLineStart = searchQuery.slice(0, selectionIndex).lastIndexOf('\n') + 1;
|
||||||
|
const lengthAfterSelectionIndex = Math.max(searchQuery.slice(selectionIndex).indexOf('\n'), 0);
|
||||||
|
const targetQuery = searchQuery.slice(activeLineStart, selectionIndex + lengthAfterSelectionIndex);
|
||||||
|
|
||||||
|
const terms = getTermContexts(targetQuery);
|
||||||
|
const searchIndex = selectionIndex - activeLineStart;
|
||||||
|
const term = terms.find(([range]) => range[0] < searchIndex && range[1] >= searchIndex) ?? null;
|
||||||
|
|
||||||
|
// Converting line-specific indexes back to absolute ones.
|
||||||
|
if (term) {
|
||||||
|
const [range] = term;
|
||||||
|
|
||||||
|
range[0] += activeLineStart;
|
||||||
|
range[1] += activeLineStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
return term;
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleSearchAutocomplete() {
|
function toggleSearchAutocomplete() {
|
||||||
const enable = store.get('enable_search_ac');
|
const enable = store.get('enable_search_ac');
|
||||||
|
|
||||||
for (const searchField of $$<HTMLInputElement>('input[data-ac-mode=search]')) {
|
for (const searchField of $$<InputFieldElement>(':is(input, textarea)[data-ac-mode=search]')) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
searchField.autocomplete = 'off';
|
searchField.autocomplete = 'off';
|
||||||
} else {
|
} else {
|
||||||
|
@ -144,13 +163,13 @@ function listenAutocomplete() {
|
||||||
loadAutocompleteFromEvent(event);
|
loadAutocompleteFromEvent(event);
|
||||||
window.clearTimeout(serverSideSuggestionsTimeout);
|
window.clearTimeout(serverSideSuggestionsTimeout);
|
||||||
|
|
||||||
if (!(event.target instanceof HTMLInputElement)) return;
|
if (!(event.target instanceof HTMLInputElement) && !(event.target instanceof HTMLTextAreaElement)) return;
|
||||||
|
|
||||||
const targetedInput = event.target;
|
const targetedInput = event.target;
|
||||||
|
|
||||||
if (!targetedInput.dataset.ac) return;
|
if (!targetedInput.dataset.ac) return;
|
||||||
|
|
||||||
targetedInput.addEventListener('keydown', keydownHandler);
|
targetedInput.addEventListener('keydown', keydownHandler as EventListener);
|
||||||
|
|
||||||
if (localAc !== null) {
|
if (localAc !== null) {
|
||||||
inputField = targetedInput;
|
inputField = targetedInput;
|
||||||
|
@ -212,7 +231,7 @@ function listenAutocomplete() {
|
||||||
});
|
});
|
||||||
|
|
||||||
function loadAutocompleteFromEvent(event: Event) {
|
function loadAutocompleteFromEvent(event: Event) {
|
||||||
if (!(event.target instanceof HTMLInputElement)) return;
|
if (!(event.target instanceof HTMLInputElement) && !(event.target instanceof HTMLTextAreaElement)) return;
|
||||||
|
|
||||||
if (!isLocalLoading && event.target.dataset.ac) {
|
if (!isLocalLoading && event.target.dataset.ac) {
|
||||||
isLocalLoading = true;
|
isLocalLoading = true;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
.field
|
.field
|
||||||
= label f, :spoilered_complex_str, "Complex Spoiler Filter"
|
= label f, :spoilered_complex_str, "Complex Spoiler Filter"
|
||||||
br
|
br
|
||||||
= textarea f, :spoilered_complex_str, class: "input input--wide", autocapitalize: "none"
|
= textarea f, :spoilered_complex_str, class: "input input--wide", autocapitalize: "none", data: [ac: "true", ac_min_length: 3, ac_mode: "search"]
|
||||||
br
|
br
|
||||||
= error_tag f, :spoilered_complex_str
|
= error_tag f, :spoilered_complex_str
|
||||||
.fieldlabel
|
.fieldlabel
|
||||||
|
@ -51,7 +51,7 @@
|
||||||
.field
|
.field
|
||||||
= label f, :hidden_complex_str, "Complex Hide Filter"
|
= label f, :hidden_complex_str, "Complex Hide Filter"
|
||||||
br
|
br
|
||||||
= textarea f, :hidden_complex_str, class: "input input--wide", autocapitalize: "none"
|
= textarea f, :hidden_complex_str, class: "input input--wide", autocapitalize: "none", data: [ac: "true", ac_min_length: 3, ac_mode: "search"]
|
||||||
br
|
br
|
||||||
= error_tag f, :hidden_complex_str
|
= error_tag f, :hidden_complex_str
|
||||||
.fieldlabel
|
.fieldlabel
|
||||||
|
|
Loading…
Reference in a new issue