Notes/src/public/app/widgets/quick_search.js

142 lines
5.0 KiB
JavaScript
Raw Normal View History

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-02-01 23:51:04 +01:00
import dateNotesService from "../services/date_notes.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";
2021-02-01 23:51:04 +01:00
import appContext from "../services/app_context.js";
2021-01-31 22:45:45 +01:00
const TPL = `
<div class="quick-search input-group input-group-sm" style="width: 250px;">
<style>
.quick-search {
2021-02-07 20:55:49 +01:00
margin-left: 5px;
margin-right: 5px;
}
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>
<input type="text" class="form-control form-control-sm search-string" placeholder="Quick search">
<div class="input-group-append">
<button class="btn btn-outline-secondary search-button" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span class="bx bx-search"></span>
</button>
2021-02-01 23:51:04 +01:00
<div class="dropdown-menu dropdown-menu-right"></div>
2021-01-31 22:45:45 +01:00
</div>
</div>
</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);
this.overflowing();
this.$searchString = this.$widget.find('.search-string');
this.$dropdownMenu = this.$widget.find('.dropdown-menu');
this.$dropdownToggle = this.$widget.find('.search-button');
2021-02-01 23:51:04 +01:00
this.$dropdownToggle.dropdown();
2021-01-31 22:45:45 +01:00
2021-02-01 23:51:04 +01:00
this.$widget.find('.input-group-append').on('shown.bs.dropdown', () => this.search());
2021-01-31 22:45:45 +01:00
utils.bindElShortcut(this.$searchString, 'return', () => {
if (this.$dropdownMenu.is(":visible")) {
this.search(); // just update already visible dropdown
} else {
this.$dropdownToggle.dropdown('show');
}
2021-01-31 22:45:45 +01:00
this.$searchString.focus();
});
2021-02-01 23:51:04 +01:00
utils.bindElShortcut(this.$searchString, 'down', () => {
this.$dropdownMenu.find('.dropdown-item:first').focus();
});
2021-02-05 23:19:43 +01:00
utils.bindElShortcut(this.$searchString, 'esc', () => {
this.$dropdownToggle.dropdown('hide');
});
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) {
this.$dropdownToggle.dropdown("hide");
return;
}
2021-01-31 22:45:45 +01:00
this.$dropdownMenu.empty();
this.$dropdownMenu.append('<span class="dropdown-item disabled"><span class="bx bx-loader bx-spin"></span> Searching ...</span>');
2021-02-01 23:51:04 +01:00
const resultNoteIds = await server.get('quick-search/' + encodeURIComponent(searchString));
2021-01-31 22:45:45 +01:00
const displayedNoteIds = resultNoteIds.slice(0, Math.min(MAX_DISPLAYED_NOTES, resultNoteIds.length));
this.$dropdownMenu.empty();
if (displayedNoteIds.length === 0) {
this.$dropdownMenu.append('<span class="dropdown-item disabled">No results found</span>');
}
2021-04-16 22:57:37 +02:00
for (const note of await froca.getNotes(displayedNoteIds)) {
2021-01-31 22:45:45 +01:00
const $link = await linkService.createNoteLink(note.noteId, {showNotePath: true});
$link.addClass('dropdown-item');
2021-02-01 23:51:04 +01:00
$link.attr("tabIndex", "0");
$link.on('click', e => {
this.$dropdownToggle.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.getActiveTabContext().setNote(note.noteId);
}
});
2021-02-01 23:51:04 +01:00
utils.bindElShortcut($link, 'return', () => {
this.$dropdownToggle.dropdown("hide");
appContext.tabManager.getActiveTabContext().setNote(note.noteId);
2021-02-01 23:51:04 +01:00
});
2021-01-31 22:45:45 +01:00
this.$dropdownMenu.append($link);
}
if (resultNoteIds.length > MAX_DISPLAYED_NOTES) {
this.$dropdownMenu.append(`<span class="dropdown-item disabled">... and ${resultNoteIds.length - MAX_DISPLAYED_NOTES} more results.</span>`);
}
2021-02-01 23:51:04 +01:00
const $showInFullButton = $('<a class="dropdown-item" tabindex="0">')
.append($('<button class="btn btn-sm">Show in full search</button>'));
this.$dropdownMenu.append($showInFullButton);
$showInFullButton.on('click', () => this.showInFullSearch());
2021-02-01 23:51:04 +01:00
utils.bindElShortcut($showInFullButton, 'return', () => this.showInFullSearch());
2021-02-01 23:51:04 +01:00
utils.bindElShortcut(this.$dropdownMenu.find('.dropdown-item:first'), 'up', () => this.$searchString.focus());
2021-01-31 22:45:45 +01:00
this.$dropdownToggle.dropdown('update');
}
2021-02-01 23:51:04 +01:00
async showInFullSearch() {
const searchNote = await dateNotesService.createSearchNote({searchString: this.$searchString.val()});
await appContext.tabManager.getActiveTabContext().setNote(searchNote.noteId);
}
2021-02-01 23:51:04 +01:00
quickSearchEvent() {
this.$searchString.focus();
}
2021-01-31 22:45:45 +01:00
}