algolia v1 upgrade

This commit is contained in:
zadam 2021-12-14 22:44:54 +01:00
parent 657496ea37
commit baed93e749
14 changed files with 351 additions and 244 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

182
package-lock.json generated
View File

@ -616,9 +616,9 @@
}
},
"@types/eslint": {
"version": "8.2.0",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.0.tgz",
"integrity": "sha512-74hbvsnc+7TEDa1z5YLSe4/q8hGYB3USNvCuzHUJrjPV6hXaq8IXcngCrHkuvFt0+8rFz7xYXrHgNayIX0UZvQ==",
"version": "8.2.1",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.1.tgz",
"integrity": "sha512-UP9rzNn/XyGwb5RQ2fok+DzcIRIYwc16qTXse5+Smsy8MOIccCChT15KAwnsgQx4PzJkaMq4myFyZ4CL5TjhIQ==",
"dev": true,
"requires": {
"@types/estree": "*",
@ -1468,20 +1468,20 @@
"integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw=="
},
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
"version": "1.19.1",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz",
"integrity": "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA==",
"requires": {
"bytes": "3.1.0",
"bytes": "3.1.1",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.7.2",
"http-errors": "1.8.1",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
"qs": "6.9.6",
"raw-body": "2.4.2",
"type-is": "~1.6.18"
},
"dependencies": {
"debug": {
@ -1491,6 +1491,38 @@
"requires": {
"ms": "2.0.0"
}
},
"http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"qs": {
"version": "6.9.6",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz",
"integrity": "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ=="
},
"setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
}
}
},
@ -1831,9 +1863,9 @@
}
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz",
"integrity": "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg=="
},
"cacache": {
"version": "15.3.0",
@ -1920,9 +1952,9 @@
"dev": true
},
"caniuse-lite": {
"version": "1.0.30001283",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001283.tgz",
"integrity": "sha512-9RoKo841j1GQFSJz/nCXOj0sD7tHBtlowjYlrqIUS812x9/emfBLBt6IyMz1zIaYc/eRL8Cs6HPUVi2Hzq4sIg==",
"version": "1.0.30001286",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001286.tgz",
"integrity": "sha512-zaEMRH6xg8ESMi2eQ3R4eZ5qw/hJiVsO/HlLwniIwErij0JDr9P+8V4dtx1l+kLq6j3yy8l8W4fst1lBnat5wQ==",
"dev": true
},
"caseless": {
@ -3702,9 +3734,9 @@
}
},
"electron-to-chromium": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.8.tgz",
"integrity": "sha512-Cu5+dbg55+1E3ohlsa8HT0s4b8D0gBewXEGG8s5wBl8ynWv60VuvYW25GpsOeTVXpulhyU/U8JYZH+yxASSJBQ==",
"version": "1.4.16",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.16.tgz",
"integrity": "sha512-BQb7FgYwnu6haWLU63/CdVW+9xhmHls3RCQUFiV4lvw3wimEHTVcUk2hkuZo76QhR8nnDdfZE7evJIZqijwPdA==",
"dev": true
},
"electron-window-state": {
@ -3995,6 +4027,28 @@
"vary": "~1.1.2"
},
"dependencies": {
"body-parser": {
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
"integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
"requires": {
"bytes": "3.1.0",
"content-type": "~1.0.4",
"debug": "2.6.9",
"depd": "~1.1.2",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"on-finished": "~2.3.0",
"qs": "6.7.0",
"raw-body": "2.4.0",
"type-is": "~1.6.17"
}
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -4002,6 +4056,17 @@
"requires": {
"ms": "2.0.0"
}
},
"raw-body": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
}
}
},
@ -5100,9 +5165,9 @@
"dev": true
},
"jest-worker": {
"version": "27.4.2",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.2.tgz",
"integrity": "sha512-0QMy/zPovLfUPyHuOuuU4E+kGACXXE84nRnq6lBVI9GJg5DCBiA97SATi+ZP8CpiJwEQy1oCPjRBf8AnLjN+Ag==",
"version": "27.4.4",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.4.tgz",
"integrity": "sha512-jfwxYJvfua1b1XkyuyPh01ATmgg4e5fPM/muLmhy9Qc6dmiwacQB0MLHaU6IjEsv/+nAixHGxTn8WllA27Pn0w==",
"dev": true,
"requires": {
"@types/node": "*",
@ -5891,9 +5956,9 @@
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"multer": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.3.tgz",
"integrity": "sha512-np0YLKncuZoTzufbkM6wEKp68EhWJXcU6fq6QqrSwkckd2LlMgd1UqhUJLj6NS/5sZ8dE8LYDWslsltJznnXlg==",
"version": "1.4.4",
"resolved": "https://registry.npmjs.org/multer/-/multer-1.4.4.tgz",
"integrity": "sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw==",
"requires": {
"append-field": "^1.0.0",
"busboy": "^0.2.11",
@ -6513,9 +6578,9 @@
}
},
"postcss": {
"version": "8.4.0",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.0.tgz",
"integrity": "sha512-BRMNx3Wy7UI89jN8H4ZVS5lQMPM2OSMkOkvDCSjwXa7PWTs24k7Lm55NXLbMbs070LvraXaxN5l1npSOS6wMVw==",
"version": "8.4.4",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.4.tgz",
"integrity": "sha512-joU6fBsN6EIer28Lj6GDFoC/5yOZzLCfn0zHAn/MYXI7aPt4m4hK5KC5ovEZXy+lnCjmYIbQWngvju2ddyEr8Q==",
"requires": {
"nanoid": "^3.1.30",
"picocolors": "^1.0.0",
@ -6669,14 +6734,43 @@
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"raw-body": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
"integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz",
"integrity": "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ==",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.2",
"bytes": "3.1.1",
"http-errors": "1.8.1",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
},
"dependencies": {
"http-errors": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz",
"integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.1"
}
},
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
}
}
},
"rc": {
@ -6986,9 +7080,9 @@
}
},
"sanitize-html": {
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.6.0.tgz",
"integrity": "sha512-qc+NqTeaOi/QVAVs5gOY9tqIVk4r1pcUbx1Q2N1a609Os3TNlm85zll2d8g8m/RM6RWg9llir0SpAcePQVIC1w==",
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.6.1.tgz",
"integrity": "sha512-DzjSz3H5qDntD7s1TcWCSoRPmNR8UmA+y+xZQOvWgjATe2Br9ZW73+vD3Pj6Snrg0RuEuJdXgrKvnYuiuixRkA==",
"requires": {
"deepmerge": "^4.2.2",
"escape-string-regexp": "^4.0.0",
@ -8094,9 +8188,9 @@
}
},
"watchpack": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.0.tgz",
"integrity": "sha512-MnN0Q1OsvB/GGHETrFeZPQaOelWh/7O+EiFlj8sM9GPjtQkis7k01aAxrg/18kTfoIVcLL+haEVFlXDaSRwKRw==",
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz",
"integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==",
"dev": true,
"requires": {
"glob-to-regexp": "^0.4.1",
@ -8118,9 +8212,9 @@
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="
},
"webpack": {
"version": "5.64.4",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.64.4.tgz",
"integrity": "sha512-LWhqfKjCLoYJLKJY8wk2C3h77i8VyHowG3qYNZiIqD6D0ZS40439S/KVuc/PY48jp2yQmy0mhMknq8cys4jFMw==",
"version": "5.65.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz",
"integrity": "sha512-Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw==",
"dev": true,
"requires": {
"@types/eslint-scope": "^3.7.0",
@ -8145,7 +8239,7 @@
"schema-utils": "^3.1.0",
"tapable": "^2.1.1",
"terser-webpack-plugin": "^5.1.3",
"watchpack": "^2.3.0",
"watchpack": "^2.3.1",
"webpack-sources": "^3.2.2"
}
},

View File

@ -28,7 +28,7 @@
"async-mutex": "0.3.2",
"axios": "0.24.0",
"better-sqlite3": "7.4.5",
"body-parser": "1.19.0",
"body-parser": "1.19.1",
"chokidar": "3.5.2",
"cls-hooked": "4.2.2",
"commonmark": "0.30.0",
@ -67,7 +67,7 @@
"request": "^2.88.2",
"rimraf": "3.0.2",
"sanitize-filename": "1.6.3",
"sanitize-html": "2.6.0",
"sanitize-html": "2.6.1",
"sax": "1.2.4",
"semver": "7.3.5",
"serve-favicon": "2.5.0",

View File

@ -30,8 +30,6 @@ bundleService.getWidgetBundlesByParent().then(widgetBundles => {
noteTooltipService.setupGlobalTooltip();
noteAutocompleteService.init();
if (utils.isElectron()) {
const electron = utils.dynamicRequire('electron');

View File

@ -41,7 +41,7 @@ export async function showDialog(widget, text = '') {
$linkTitle.val(noteTitle);
}
noteAutocompleteService.initNoteAutocomplete($autoComplete, {
const ac = noteAutocompleteService.initNoteAutocomplete($autoComplete, {
allowExternalLinks: true,
allowCreatingNotes: true
});
@ -84,7 +84,7 @@ export async function showDialog(widget, text = '') {
});
if (text && text.trim()) {
noteAutocompleteService.setText($autoComplete, text);
noteAutocompleteService.setText(ac, text);
}
else {
noteAutocompleteService.showRecentNotes($autoComplete);

View File

@ -12,7 +12,12 @@ const KEEP_LAST_SEARCH_FOR_X_SECONDS = 120;
export async function showDialog() {
utils.openDialog($dialog);
noteAutocompleteService.initNoteAutocomplete($autoComplete, { hideGoToSelectedNoteButton: true })
const ac = noteAutocompleteService.initNoteAutocomplete($autoComplete, {
hideGoToSelectedNoteButton: true,
placeholder: "search for note by its name"
});
$autoComplete
// clear any event listener added in previous invocation of this function
.off('autocomplete:noteselected')
.on('autocomplete:noteselected', function(event, suggestion, dataset) {
@ -28,15 +33,12 @@ export async function showDialog() {
// so we'll keep the content.
// if it's outside of this time limit then we assume it's a completely new search and show recent notes instead.
if (Date.now() - lastOpenedTs > KEEP_LAST_SEARCH_FOR_X_SECONDS * 1000) {
noteAutocompleteService.showRecentNotes($autoComplete);
noteAutocompleteService.showRecentNotes(ac, $autoComplete);
}
else {
$autoComplete
// hack, the actual search value is stored in <pre> element next to the search input
// this is important because the search input value is replaced with the suggestion note's title
.autocomplete("val", $autoComplete.next().text())
.trigger('focus')
.trigger('select');
ac.setIsOpen(true);
ac.ext.focus();
ac.ext.select();
}
lastOpenedTs = Date.now();

View File

@ -8,7 +8,75 @@ import froca from "./froca.js";
// this key needs to have this value so it's hit by the tooltip
const SELECTED_NOTE_PATH_KEY = "data-note-path";
const SELECTED_EXTERNAL_LINK_KEY = "data-external-link";
const acMixin = {
selectedNotePath: "",
selectedExternalLink: "",
$el: "",
focus() {
this.$el.find('.aa-Input').focus();
},
select() {
this.$el.find('.aa-Input').select();
},
getQuery() {
return this?.lastState.query;
},
getSelectedNotePath() {
if (!this.getQuery()) {
return "";
} else {
return this.selectedNotePath;
}
},
getSelectedNoteId() {
const notePath = this.getSelectedNotePath();
const chunks = notePath.split('/');
return chunks.length >= 1 ? chunks[chunks.length - 1] : null;
},
setSelectedNotePath(notePath) {
notePath = notePath || "";
this.selectedNotePath = notePath;
$(this)
.closest(".input-group")
.find(".go-to-selected-note-button")
.toggleClass("disabled", !notePath.trim())
.attr(SELECTED_NOTE_PATH_KEY, notePath); // we also set attr here so tooltip can be displayed
},
getSelectedExternalLink() {
if (!$(this).val().trim()) {
return "";
} else {
return this.selectedExternalLink;
}
},
setSelectedExternalLink(externalLink) {
this.selectedExternalLink = externalLink;
$(this)
.closest(".input-group")
.find(".go-to-selected-note-button")
.toggleClass("disabled", true);
},
async setNote(noteId) {
const note = noteId ? await froca.getNote(noteId, true) : null;
$(this)
.val(note ? note.title : "")
.setSelectedNotePath(noteId);
}
}
async function autocompleteSourceForCKEditor(queryText) {
return await new Promise((res, rej) => {
@ -30,7 +98,7 @@ async function autocompleteSourceForCKEditor(queryText) {
});
}
async function autocompleteSource(term, cb, options = {}) {
async function autocompleteSource(term, options = {}) {
const activeNoteId = appContext.tabManager.getActiveContextNoteId();
let results = await server.get('autocomplete'
@ -58,206 +126,176 @@ async function autocompleteSource(term, cb, options = {}) {
].concat(results);
}
cb(results);
return results;
}
function clearText($el) {
function clearText(acObj) {
if (utils.isMobile()) {
return;
}
$el.setSelectedNotePath("");
$el.autocomplete("val", "").trigger('change');
acObj.ext.setSelectedNotePath("");
acObj.setQuery("");
}
function setText($el, text) {
function setText(ac, text) {
if (utils.isMobile()) {
return;
}
$el.setSelectedNotePath("");
$el
.autocomplete("val", text.trim())
.autocomplete("open");
ac.ext.setSelectedNotePath("");
ac.setQuery(text.trim());
ac.setIsOpen(true);
}
function showRecentNotes($el) {
function showRecentNotes(ac) {
if (utils.isMobile()) {
return;
}
$el.setSelectedNotePath("");
$el.autocomplete("val", "");
$el.trigger('focus');
ac.ext.$el.find(".aa-Input").val("").change();
ac.setQuery("");
ac.setIsOpen(true);
ac.update();
ac.ext.setSelectedNotePath("");
ac.ext.focus();
console.log("BBB");
}
function initNoteAutocomplete($el, options) {
if ($el.hasClass("note-autocomplete-input") || utils.isMobile()) {
function initNoteAutocomplete($container, options) {
if ($container.hasClass("note-autocomplete-container") || utils.isMobile()) {
// clear any event listener added in previous invocation of this function
$el.off('autocomplete:noteselected');
$container.off('autocomplete:noteselected');
return $el;
return $container.prop("acObj");
}
options = options || {};
$el.addClass("note-autocomplete-input");
const $el = $('<div class="note-autocomplete-input">');
const $sideButtons = $('<div>');
const $clearTextButton = $("<a>")
.addClass("input-group-text input-clearer-button bx bx-x")
.prop("title", "Clear text field");
$container.addClass("note-autocomplete-container")
.append($el)
.append($sideButtons);
const $showRecentNotesButton = $("<a>")
.addClass("input-group-text show-recent-notes-button bx bx-time")
.addClass("show-recent-notes-button bx bx-time")
.prop("title", "Show recent notes");
const $goToSelectedNoteButton = $("<a>")
.addClass("input-group-text go-to-selected-note-button bx bx-arrow-to-right")
.addClass("go-to-selected-note-button bx bx-arrow-to-right")
.attr("data-action", "note");
const $sideButtons = $("<div>")
.addClass("input-group-append")
.append($clearTextButton)
.append($showRecentNotesButton);
$sideButtons.append($showRecentNotesButton);
if (!options.hideGoToSelectedNoteButton) {
$sideButtons.append($goToSelectedNoteButton);
}
$el.after($sideButtons);
$clearTextButton.on('click', () => clearText($el));
$showRecentNotesButton.on('click', e => {
showRecentNotes($el);
showRecentNotes(acObj);
// this will cause the click not give focus to the "show recent notes" button
// this is important because otherwise input will lose focus immediatelly and not show the results
return false;
});
$el.autocomplete({
appendTo: document.querySelector('body'),
hint: false,
autoselect: true,
const { autocomplete } = window['@algolia/autocomplete-js'];
let acObj = autocomplete({
container: $el[0],
defaultActiveItemId: 0,
openOnFocus: true,
minLength: 0,
tabAutocomplete: false
}, [
{
source: (term, cb) => autocompleteSource(term, cb, options),
displayKey: 'notePathTitle',
templates: {
suggestion: suggestion => suggestion.highlightedNotePathTitle
},
// we can't cache identical searches because notes can be created / renamed, new recent notes can be added
cache: false
tabAutocomplete: false,
placeholder: options.placeholder,
onStateChange({ state }) {
acObj.lastState = state;
},
async getSources({ query }) {
const items = await autocompleteSource(query, options);
return [
{
getItems() {
return items;
},
onSelect({item}) {
acObj.ext.$el.trigger("autocomplete:selected", [item]);
},
displayKey: 'notePathTitle',
templates: {
item({ item, createElement }) {
return createElement('div', {
dangerouslySetInnerHTML: {
__html: item.highlightedNotePathTitle,
},
});
}
},
// we can't cache identical searches because notes can be created / renamed, new recent notes can be added
cache: false
}
]
}
]);
});
$el.on('autocomplete:selected', async (event, suggestion) => {
if (suggestion.action === 'external-link') {
$el.setSelectedNotePath(null);
$el.setSelectedExternalLink(suggestion.externalLink);
acObj.ext = {...acMixin, $el, $container };
$el.autocomplete("val", suggestion.externalLink);
$container.prop("acObj", acObj);
$el.autocomplete("close");
$container.on('autocomplete:selected', async (event, item) => {
if (item.action === 'external-link') {
acObj.ext.setSelectedNotePath(null);
acObj.ext.setSelectedExternalLink(item.externalLink);
$el.trigger('autocomplete:externallinkselected', [suggestion]);
acObj.setQuery(item.externalLink);
$container.autocomplete("close");
$container.trigger('autocomplete:externallinkselected', [item]);
return;
}
if (suggestion.action === 'create-note') {
const {note} = await noteCreateService.createNote(suggestion.parentNoteId, {
title: suggestion.noteTitle,
if (item.action === 'create-note') {
const {note} = await noteCreateService.createNote(item.parentNoteId, {
title: item.noteTitle,
activate: false
});
suggestion.notePath = treeService.getSomeNotePath(note);
item.notePath = treeService.getSomeNotePath(note);
}
$el.setSelectedNotePath(suggestion.notePath);
$el.setSelectedExternalLink(null);
acObj.ext.setSelectedNotePath(item.notePath);
acObj.ext.setSelectedExternalLink(null);
$el.autocomplete("val", suggestion.noteTitle);
acObj.setQuery(item.noteTitle);
$el.autocomplete("close");
acObj.setIsOpen(false);
$el.trigger('autocomplete:noteselected', [suggestion]);
$container.trigger('autocomplete:noteselected', [item]);
});
$el.on('autocomplete:closed', () => {
if (!$el.val().trim()) {
clearText($el);
$container.on('autocomplete:closed', () => {
if (!$container.val().trim()) {
clearText($container);
}
});
$el.on('autocomplete:opened', () => {
if ($el.attr("readonly")) {
$el.autocomplete('close');
$container.on('autocomplete:opened', () => {
if ($container.attr("readonly")) {
$container.autocomplete('close');
}
});
// clear any event listener added in previous invocation of this function
$el.off('autocomplete:noteselected');
$container.off('autocomplete:noteselected');
return $el;
}
function init() {
$.fn.getSelectedNotePath = function () {
if (!$(this).val().trim()) {
return "";
} else {
return $(this).attr(SELECTED_NOTE_PATH_KEY);
}
};
$.fn.getSelectedNoteId = function () {
const notePath = $(this).getSelectedNotePath();
const chunks = notePath.split('/');
return chunks.length >= 1 ? chunks[chunks.length - 1] : null;
}
$.fn.setSelectedNotePath = function (notePath) {
notePath = notePath || "";
$(this).attr(SELECTED_NOTE_PATH_KEY, notePath);
$(this)
.closest(".input-group")
.find(".go-to-selected-note-button")
.toggleClass("disabled", !notePath.trim())
.attr(SELECTED_NOTE_PATH_KEY, notePath); // we also set attr here so tooltip can be displayed
};
$.fn.getSelectedExternalLink = function () {
if (!$(this).val().trim()) {
return "";
} else {
return $(this).attr(SELECTED_EXTERNAL_LINK_KEY);
}
};
$.fn.setSelectedExternalLink = function (externalLink) {
$(this).attr(SELECTED_EXTERNAL_LINK_KEY, externalLink);
$(this)
.closest(".input-group")
.find(".go-to-selected-note-button")
.toggleClass("disabled", true);
}
$.fn.setNote = async function (noteId) {
const note = noteId ? await froca.getNote(noteId, true) : null;
$(this)
.val(note ? note.title : "")
.setSelectedNotePath(noteId);
}
return acObj;
}
export default {
@ -265,6 +303,5 @@ export default {
autocompleteSourceForCKEditor,
initNoteAutocomplete,
showRecentNotes,
setText,
init
setText
}

View File

@ -59,10 +59,10 @@ class NoteContext extends Component {
});
}
if (utils.isDesktop()) {
// close dangling autocompletes after closing the tab
$(".aa-input").autocomplete("close");
}
// if (utils.isDesktop()) {
// // close dangling autocompletes after closing the tab
// $(".aa-input").autocomplete("close");
// }
}
getSubContexts() {

View File

@ -292,7 +292,9 @@ export default class AttributeDetailWidget extends NoteContextAwareWidget {
this.$rowTargetNote = this.$widget.find('.attr-row-target-note');
this.$inputTargetNote = this.$widget.find('.attr-input-target-note');
noteAutocompleteService.initNoteAutocomplete(this.$inputTargetNote, {allowCreatingNotes: true})
noteAutocompleteService.initNoteAutocomplete(this.$inputTargetNote, {allowCreatingNotes: true});
this.$inputTargetNote
.on('autocomplete:noteselected', (event, suggestion, dataset) => {
if (!suggestion.notePath) {
return false;

View File

@ -358,9 +358,12 @@ pre:not(.CodeMirror-line) {
color: var(--button-disabled-background-color) !important;
}
.note-autocomplete-input {
/* this is for seamless integration of "input clearer" button */
border-right: 0;
.note-autocomplete-container {
display: flex;
}
.note-autocomplete-container .note-autocomplete-input {
flex-grow: 1;
}
table.promoted-attributes-in-tooltip {
@ -432,43 +435,6 @@ table.promoted-attributes-in-tooltip td, table.promoted-attributes-in-tooltip th
opacity: 1;
}
.algolia-autocomplete {
width: calc(100% - 30px);
z-index: 2000 !important;
}
.algolia-autocomplete .aa-input, .algolia-autocomplete .aa-hint {
width: 100%;
}
.algolia-autocomplete .aa-dropdown-menu {
width: 100%;
background-color: var(--main-background-color);
border: 1px solid var(--main-border-color);
border-top: none;
z-index: 2000 !important;
max-height: 500px;
overflow: auto;
padding: 0;
margin: 0;
}
.algolia-autocomplete .aa-dropdown-menu .aa-suggestion {
cursor: pointer;
padding: 5px;
margin: 0;
}
.algolia-autocomplete .aa-dropdown-menu .aa-suggestion p {
padding: 0;
margin: 0;
}
.algolia-autocomplete .aa-dropdown-menu .aa-suggestion.aa-cursor {
color: var(--hover-item-text-color);
background-color: var(--hover-item-background-color);
}
.help-button {
float: right;
background: none;
@ -958,3 +924,7 @@ input {
.note-split.full-content-width {
max-width: 999999px;
}
.aa-Panel {
z-index: 10000;
}

View File

@ -79,7 +79,8 @@
<script src="libraries/jquery.hotkeys.js"></script>
<script src="libraries/autocomplete.jquery.min.js"></script>
<link href="libraries/autocomplete-theme-classic.css" rel="stylesheet">
<script src="libraries/autocomplete.js"></script>
<script src="libraries/dayjs.min.js"></script>

View File

@ -10,9 +10,8 @@
<div class="modal-body">
<div class="form-group">
<label for="jump-to-note-autocomplete">Note</label>
<div class="input-group">
<input id="jump-to-note-autocomplete" class="form-control" placeholder="search for note by its name">
</div>
<div id="jump-to-note-autocomplete"></div>
</div>
</div>
<div class="modal-footer">