import BasicWidget from "./basic_widget.js";
import server from "../services/server.js";
import linkService from "../services/link.js";
import froca from "../services/froca.js";
import utils from "../services/utils.js";
import appContext from "../components/app_context.js";
import shortcutService from "../services/shortcuts.js";
import { t } from "../services/i18n.js";
import { Dropdown, Tooltip } from "bootstrap";
const TPL = `
`;
const MAX_DISPLAYED_NOTES = 15;
export default class QuickSearchWidget extends BasicWidget {
doRender() {
this.$widget = $(TPL);
this.dropdown = Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']"));
this.$searchString = this.$widget.find(".search-string");
this.$dropdownMenu = this.$widget.find(".dropdown-menu");
this.$widget.find(".input-group-prepend").on("shown.bs.dropdown", () => this.search());
if (utils.isMobile()) {
this.$searchString.keydown((e) => {
if (e.which === 13) {
if (this.$dropdownMenu.is(":visible")) {
this.search(); // just update already visible dropdown
} else {
this.dropdown.show();
}
e.preventDefault();
e.stopPropagation();
}
});
}
shortcutService.bindElShortcut(this.$searchString, "return", () => {
if (this.$dropdownMenu.is(":visible")) {
this.search(); // just update already visible dropdown
} else {
this.dropdown.show();
}
this.$searchString.focus();
});
shortcutService.bindElShortcut(this.$searchString, "down", () => {
this.$dropdownMenu.find(".dropdown-item:not(.disabled):first").focus();
});
shortcutService.bindElShortcut(this.$searchString, "esc", () => {
this.dropdown.hide();
});
return this.$widget;
}
async search() {
const searchString = this.$searchString.val().trim();
if (!searchString) {
this.dropdown.hide();
return;
}
this.$dropdownMenu.empty();
this.$dropdownMenu.append(`${t("quick-search.searching")}`);
const { searchResultNoteIds, error } = await server.get(`quick-search/${encodeURIComponent(searchString)}`);
if (error) {
let tooltip = new Tooltip(this.$searchString, {
trigger: "manual",
title: `Search error: ${error}`,
placement: "right"
});
tooltip.show();
setTimeout(() => tooltip.dispose(), 4000);
}
const displayedNoteIds = searchResultNoteIds.slice(0, Math.min(MAX_DISPLAYED_NOTES, searchResultNoteIds.length));
this.$dropdownMenu.empty();
if (displayedNoteIds.length === 0) {
this.$dropdownMenu.append(`${t("quick-search.no-results")}`);
}
for (const note of await froca.getNotes(displayedNoteIds)) {
const $link = await linkService.createLink(note.noteId, { showNotePath: true, showNoteIcon: true });
$link.addClass("dropdown-item");
$link.attr("tabIndex", "0");
$link.on("click", (e) => {
this.dropdown.hide();
if (!e.target || e.target.nodeName !== "A") {
// click on the link is handled by link handling, but we want the whole item clickable
appContext.tabManager.getActiveContext().setNote(note.noteId);
}
});
shortcutService.bindElShortcut($link, "return", () => {
this.dropdown.hide();
appContext.tabManager.getActiveContext().setNote(note.noteId);
});
this.$dropdownMenu.append($link);
}
if (searchResultNoteIds.length > MAX_DISPLAYED_NOTES) {
const numRemainingResults = searchResultNoteIds.length - MAX_DISPLAYED_NOTES;
this.$dropdownMenu.append(`${t("quick-search.more-results", { number: numRemainingResults })}`);
}
const $showInFullButton = $('').text(t("quick-search.show-in-full-search"));
this.$dropdownMenu.append($(``));
this.$dropdownMenu.append($showInFullButton);
$showInFullButton.on("click", () => this.showInFullSearch());
shortcutService.bindElShortcut($showInFullButton, "return", () => this.showInFullSearch());
shortcutService.bindElShortcut(this.$dropdownMenu.find(".dropdown-item:first"), "up", () => this.$searchString.focus());
this.dropdown.update();
}
async showInFullSearch() {
this.dropdown.hide();
await appContext.triggerCommand("searchNotes", {
searchString: this.$searchString.val()
});
}
quickSearchEvent() {
this.$searchString.focus();
}
}