2021-01-31 22:45:45 +01:00
|
|
|
import BasicWidget from "./basic_widget.js";
|
|
|
|
import server from "../services/server.js";
|
|
|
|
import linkService from "../services/link.js";
|
2021-04-16 23:01:56 +02:00
|
|
|
import froca from "../services/froca.js";
|
2021-01-31 22:45:45 +01:00
|
|
|
import utils from "../services/utils.js";
|
2022-12-01 13:07:23 +01:00
|
|
|
import appContext from "../components/app_context.js";
|
2022-12-01 00:17:15 +01:00
|
|
|
import shortcutService from "../services/shortcuts.js";
|
2024-09-13 22:08:52 +03:00
|
|
|
import { t } from "../services/i18n.js";
|
2021-01-31 22:45:45 +01:00
|
|
|
|
|
|
|
const TPL = `
|
2021-05-17 21:46:18 +02:00
|
|
|
<div class="quick-search input-group input-group-sm">
|
2021-01-31 22:45:45 +01:00
|
|
|
<style>
|
2021-02-01 20:55:35 +01:00
|
|
|
.quick-search {
|
2021-06-13 22:55:31 +02:00
|
|
|
padding: 10px 10px 10px 0px;
|
|
|
|
height: 50px;
|
2021-05-22 22:55:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.quick-search button, .quick-search input {
|
|
|
|
border: 0;
|
|
|
|
font-size: 100% !important;
|
2021-02-01 20:55:35 +01:00
|
|
|
}
|
|
|
|
|
2021-01-31 22:45:45 +01:00
|
|
|
.quick-search .dropdown-menu {
|
|
|
|
max-height: 600px;
|
|
|
|
max-width: 400px;
|
|
|
|
overflow-y: auto;
|
|
|
|
overflow-x: hidden;
|
|
|
|
text-overflow: ellipsis;
|
2021-02-01 23:51:04 +01:00
|
|
|
box-shadow: -30px 50px 93px -50px black;
|
2021-01-31 22:45:45 +01:00
|
|
|
}
|
|
|
|
</style>
|
|
|
|
|
2021-05-22 22:55:24 +02:00
|
|
|
<div class="input-group-prepend">
|
2024-09-03 17:08:07 +02:00
|
|
|
<button class="btn btn-outline-secondary search-button" type="button" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
2021-01-31 22:45:45 +01:00
|
|
|
<span class="bx bx-search"></span>
|
|
|
|
</button>
|
2021-07-02 23:22:10 +02:00
|
|
|
<div class="dropdown-menu dropdown-menu-left"></div>
|
2021-01-31 22:45:45 +01:00
|
|
|
</div>
|
2024-09-13 22:08:52 +03:00
|
|
|
<input type="text" class="form-control form-control-sm search-string" placeholder="${t("quick-search.placeholder")}">
|
2021-01-31 22:45:45 +01:00
|
|
|
</div>`;
|
|
|
|
|
2021-02-01 23:51:04 +01:00
|
|
|
const MAX_DISPLAYED_NOTES = 15;
|
2021-01-31 22:45:45 +01:00
|
|
|
|
|
|
|
export default class QuickSearchWidget extends BasicWidget {
|
|
|
|
doRender() {
|
|
|
|
this.$widget = $(TPL);
|
2024-09-03 17:08:07 +02:00
|
|
|
this.dropdown = bootstrap.Dropdown.getOrCreateInstance(this.$widget.find("[data-bs-toggle='dropdown']"));
|
2021-01-31 22:45:45 +01:00
|
|
|
|
|
|
|
this.$searchString = this.$widget.find('.search-string');
|
|
|
|
this.$dropdownMenu = this.$widget.find('.dropdown-menu');
|
|
|
|
|
2021-07-02 23:22:10 +02:00
|
|
|
this.$widget.find('.input-group-prepend').on('shown.bs.dropdown', () => this.search());
|
2021-01-31 22:45:45 +01:00
|
|
|
|
2024-09-03 17:08:07 +02:00
|
|
|
if (utils.isMobile()) {
|
|
|
|
this.$searchString.keydown(e => {
|
|
|
|
if (e.which === 13) {
|
2021-11-21 03:55:52 +08:00
|
|
|
if (this.$dropdownMenu.is(":visible")) {
|
|
|
|
this.search(); // just update already visible dropdown
|
|
|
|
} else {
|
2024-09-03 17:08:07 +02:00
|
|
|
this.dropdown.show();
|
2021-11-21 03:55:52 +08:00
|
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-12-01 00:17:15 +01:00
|
|
|
shortcutService.bindElShortcut(this.$searchString, 'return', () => {
|
2021-02-26 23:20:49 +01:00
|
|
|
if (this.$dropdownMenu.is(":visible")) {
|
|
|
|
this.search(); // just update already visible dropdown
|
|
|
|
} else {
|
2024-09-03 17:08:07 +02:00
|
|
|
this.dropdown.show();
|
2021-02-26 23:20:49 +01:00
|
|
|
}
|
2021-01-31 22:45:45 +01:00
|
|
|
|
|
|
|
this.$searchString.focus();
|
|
|
|
});
|
|
|
|
|
2022-12-01 00:17:15 +01:00
|
|
|
shortcutService.bindElShortcut(this.$searchString, 'down', () => {
|
2021-02-01 23:51:04 +01:00
|
|
|
this.$dropdownMenu.find('.dropdown-item:first').focus();
|
|
|
|
});
|
|
|
|
|
2022-12-01 00:17:15 +01:00
|
|
|
shortcutService.bindElShortcut(this.$searchString, 'esc', () => {
|
2024-09-03 17:08:07 +02:00
|
|
|
this.dropdown.hide();
|
2021-02-05 23:19:43 +01:00
|
|
|
});
|
|
|
|
|
2021-01-31 22:45:45 +01:00
|
|
|
return this.$widget;
|
|
|
|
}
|
|
|
|
|
|
|
|
async search() {
|
2021-02-01 23:51:04 +01:00
|
|
|
const searchString = this.$searchString.val().trim();
|
|
|
|
|
|
|
|
if (!searchString) {
|
2024-09-03 17:08:07 +02:00
|
|
|
this.dropdown.hide();
|
2021-02-01 23:51:04 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-31 22:45:45 +01:00
|
|
|
this.$dropdownMenu.empty();
|
2024-09-13 22:08:52 +03:00
|
|
|
this.$dropdownMenu.append(`<span class="dropdown-item disabled"><span class="bx bx-loader bx-spin"></span>${t("quick-search.searching")}</span>`);
|
2021-01-31 22:45:45 +01:00
|
|
|
|
2024-09-03 17:08:07 +02:00
|
|
|
const { searchResultNoteIds, error } = await server.get(`quick-search/${encodeURIComponent(searchString)}`);
|
2021-01-31 22:45:45 +01:00
|
|
|
|
2022-12-17 11:58:30 +01:00
|
|
|
if (error) {
|
2024-09-03 17:08:07 +02:00
|
|
|
let tooltip = new bootstrap.Tooltip(this.$searchString, {
|
2022-12-17 11:58:30 +01:00
|
|
|
trigger: 'manual',
|
2022-12-21 15:19:05 +01:00
|
|
|
title: `Search error: ${error}`,
|
2022-12-17 11:58:30 +01:00
|
|
|
placement: 'right'
|
|
|
|
});
|
|
|
|
|
2024-09-03 17:08:07 +02:00
|
|
|
tooltip.show();
|
2022-12-17 11:58:30 +01:00
|
|
|
|
2024-09-03 17:08:07 +02:00
|
|
|
setTimeout(() => tooltip.dispose(), 4000);
|
2022-12-17 11:58:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const displayedNoteIds = searchResultNoteIds.slice(0, Math.min(MAX_DISPLAYED_NOTES, searchResultNoteIds.length));
|
2021-01-31 22:45:45 +01:00
|
|
|
|
|
|
|
this.$dropdownMenu.empty();
|
|
|
|
|
|
|
|
if (displayedNoteIds.length === 0) {
|
2024-09-13 22:08:52 +03:00
|
|
|
this.$dropdownMenu.append(`<span class="dropdown-item disabled">${t("quick-search.no-results")}</span>`);
|
2021-01-31 22:45:45 +01:00
|
|
|
}
|
|
|
|
|
2021-04-16 22:57:37 +02:00
|
|
|
for (const note of await froca.getNotes(displayedNoteIds)) {
|
2024-09-03 17:08:07 +02:00
|
|
|
const $link = await linkService.createLink(note.noteId, { showNotePath: true });
|
2021-01-31 22:45:45 +01:00
|
|
|
$link.addClass('dropdown-item');
|
2021-02-01 23:51:04 +01:00
|
|
|
$link.attr("tabIndex", "0");
|
2021-02-24 22:19:09 +01:00
|
|
|
$link.on('click', e => {
|
2024-09-03 17:08:07 +02:00
|
|
|
this.dropdown.hide();
|
2021-02-24 22:19:09 +01:00
|
|
|
|
|
|
|
if (!e.target || e.target.nodeName !== 'A') {
|
2023-01-15 21:04:17 +01:00
|
|
|
// click on the link is handled by link handling, but we want the whole item clickable
|
2021-05-22 12:35:41 +02:00
|
|
|
appContext.tabManager.getActiveContext().setNote(note.noteId);
|
2021-02-24 22:19:09 +01:00
|
|
|
}
|
|
|
|
});
|
2022-12-01 00:17:15 +01:00
|
|
|
shortcutService.bindElShortcut($link, 'return', () => {
|
2024-09-03 17:08:07 +02:00
|
|
|
this.dropdown.hide();
|
2021-02-24 22:19:09 +01:00
|
|
|
|
2021-05-22 12:35:41 +02:00
|
|
|
appContext.tabManager.getActiveContext().setNote(note.noteId);
|
2021-02-01 23:51:04 +01:00
|
|
|
});
|
2021-01-31 22:45:45 +01:00
|
|
|
|
|
|
|
this.$dropdownMenu.append($link);
|
|
|
|
}
|
|
|
|
|
2022-12-17 11:58:30 +01:00
|
|
|
if (searchResultNoteIds.length > MAX_DISPLAYED_NOTES) {
|
2024-09-13 22:08:52 +03:00
|
|
|
const numRemainingResults = (searchResultNoteIds.length - MAX_DISPLAYED_NOTES);
|
|
|
|
this.$dropdownMenu.append(`<span class="dropdown-item disabled">${t("quick-search.more-results", { number: numRemainingResults })}</span>`);
|
2021-01-31 22:45:45 +01:00
|
|
|
}
|
|
|
|
|
2021-02-01 23:51:04 +01:00
|
|
|
const $showInFullButton = $('<a class="dropdown-item" tabindex="0">')
|
2024-09-13 22:08:52 +03:00
|
|
|
.append($(`<button class="btn btn-sm">${t("quick-search.show-in-full-search")}</button>`));
|
2021-02-01 23:51:04 +01:00
|
|
|
|
|
|
|
this.$dropdownMenu.append($showInFullButton);
|
|
|
|
|
2021-02-16 21:19:07 +01:00
|
|
|
$showInFullButton.on('click', () => this.showInFullSearch());
|
2021-02-01 23:51:04 +01:00
|
|
|
|
2022-12-01 00:17:15 +01:00
|
|
|
shortcutService.bindElShortcut($showInFullButton, 'return', () => this.showInFullSearch());
|
2021-02-01 23:51:04 +01:00
|
|
|
|
2022-12-01 00:17:15 +01:00
|
|
|
shortcutService.bindElShortcut(this.$dropdownMenu.find('.dropdown-item:first'), 'up', () => this.$searchString.focus());
|
2021-02-01 23:51:04 +01:00
|
|
|
|
2024-09-03 17:08:07 +02:00
|
|
|
this.dropdown.update();
|
2021-01-31 22:45:45 +01:00
|
|
|
}
|
2021-02-01 23:51:04 +01:00
|
|
|
|
2021-02-16 21:19:07 +01:00
|
|
|
async showInFullSearch() {
|
2024-09-03 17:08:07 +02:00
|
|
|
this.dropdown.hide();
|
2021-12-06 20:43:50 +01:00
|
|
|
|
2022-01-10 20:44:59 +01:00
|
|
|
await appContext.triggerCommand('searchNotes', {
|
|
|
|
searchString: this.$searchString.val()
|
|
|
|
});
|
2021-02-16 21:19:07 +01:00
|
|
|
}
|
|
|
|
|
2021-02-01 23:51:04 +01:00
|
|
|
quickSearchEvent() {
|
|
|
|
this.$searchString.focus();
|
|
|
|
}
|
2021-01-31 22:45:45 +01:00
|
|
|
}
|