mirror of
https://github.com/zadam/trilium.git
synced 2025-02-23 14:35:40 +08:00
autocomplete for attribute names, issue #31
This commit is contained in:
parent
bc4aa3e40a
commit
a3b31fab54
6 changed files with 47 additions and 12 deletions
|
@ -3,6 +3,7 @@
|
|||
const attributesDialog = (function() {
|
||||
const dialogEl = $("#attributes-dialog");
|
||||
const attributesModel = new AttributesModel();
|
||||
let attributeNames = [];
|
||||
|
||||
function AttributesModel() {
|
||||
const self = this;
|
||||
|
@ -17,6 +18,10 @@ const attributesDialog = (function() {
|
|||
self.attributes(attributes.map(ko.observable));
|
||||
|
||||
addLastEmptyRow();
|
||||
|
||||
attributeNames = await server.get('attributes/names');
|
||||
|
||||
$(".attribute-name:last").focus();
|
||||
};
|
||||
|
||||
function isValid() {
|
||||
|
@ -54,11 +59,7 @@ const attributesDialog = (function() {
|
|||
const attrs = self.attributes();
|
||||
const last = attrs[attrs.length - 1]();
|
||||
|
||||
// console.log("last", attrs.map(attr => attr()));
|
||||
|
||||
if (last.name.trim() !== "" || last.value !== "") {
|
||||
console.log("Adding new row");
|
||||
|
||||
self.attributes.push(ko.observable({
|
||||
attributeId: '',
|
||||
name: '',
|
||||
|
@ -68,8 +69,6 @@ const attributesDialog = (function() {
|
|||
}
|
||||
|
||||
this.attributeChanged = function (row) {
|
||||
console.log(row);
|
||||
|
||||
addLastEmptyRow();
|
||||
|
||||
for (const attr of self.attributes()) {
|
||||
|
@ -124,6 +123,22 @@ const attributesDialog = (function() {
|
|||
|
||||
ko.applyBindings(attributesModel, document.getElementById('attributes-dialog'));
|
||||
|
||||
$(document).on('focus', '.attribute-name:not(.ui-autocomplete-input)', function (e) {
|
||||
$(this).autocomplete({
|
||||
// shouldn't be required and autocomplete should just accept array of strings, but that fails
|
||||
// because we have overriden filter() function in init.js
|
||||
source: attributeNames.map(attr => {
|
||||
return {
|
||||
label: attr,
|
||||
value: attr
|
||||
}
|
||||
}),
|
||||
minLength: 0
|
||||
});
|
||||
|
||||
$(this).autocomplete("search", $(this).val());
|
||||
});
|
||||
|
||||
return {
|
||||
showDialog
|
||||
};
|
||||
|
|
|
@ -105,7 +105,7 @@ $(window).on('beforeunload', () => {
|
|||
// Overrides the default autocomplete filter function to search for matched on atleast 1 word in each of the input term's words
|
||||
$.ui.autocomplete.filter = (array, terms) => {
|
||||
if (!terms) {
|
||||
return [];
|
||||
return array;
|
||||
}
|
||||
|
||||
const startDate = new Date();
|
||||
|
|
|
@ -7,14 +7,15 @@ const auth = require('../../services/auth');
|
|||
const sync_table = require('../../services/sync_table');
|
||||
const utils = require('../../services/utils');
|
||||
const wrap = require('express-promise-wrap').wrap;
|
||||
const attributes = require('../../services/attributes');
|
||||
|
||||
router.get('/:noteId/attributes', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
router.get('/notes/:noteId/attributes', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
const noteId = req.params.noteId;
|
||||
|
||||
res.send(await sql.getRows("SELECT * FROM attributes WHERE noteId = ? ORDER BY dateCreated", [noteId]));
|
||||
}));
|
||||
|
||||
router.put('/:noteId/attributes', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
router.put('/notes/:noteId/attributes', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
const noteId = req.params.noteId;
|
||||
const attributes = req.body;
|
||||
const now = utils.nowDate();
|
||||
|
@ -45,4 +46,20 @@ router.put('/:noteId/attributes', auth.checkApiAuth, wrap(async (req, res, next)
|
|||
res.send(await sql.getRows("SELECT * FROM attributes WHERE noteId = ? ORDER BY dateCreated", [noteId]));
|
||||
}));
|
||||
|
||||
router.get('/attributes/names', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||
const noteId = req.params.noteId;
|
||||
|
||||
const names = await sql.getColumn("SELECT DISTINCT name FROM attributes");
|
||||
|
||||
for (const attr of attributes.BUILTIN_ATTRIBUTES) {
|
||||
if (!names.includes(attr)) {
|
||||
names.push(attr);
|
||||
}
|
||||
}
|
||||
|
||||
names.sort();
|
||||
|
||||
res.send(names);
|
||||
}));
|
||||
|
||||
module.exports = router;
|
|
@ -40,7 +40,7 @@ function register(app) {
|
|||
app.use('/api/notes', notesApiRoute);
|
||||
app.use('/api/tree', treeChangesApiRoute);
|
||||
app.use('/api/notes', cloningApiRoute);
|
||||
app.use('/api/notes', attributesRoute);
|
||||
app.use('/api', attributesRoute);
|
||||
app.use('/api/notes-history', noteHistoryApiRoute);
|
||||
app.use('/api/recent-changes', recentChangesApiRoute);
|
||||
app.use('/api/settings', settingsApiRoute);
|
||||
|
|
|
@ -5,6 +5,8 @@ const utils = require('./utils');
|
|||
const sync_table = require('./sync_table');
|
||||
const Repository = require('./repository');
|
||||
|
||||
const BUILTIN_ATTRIBUTES = [ 'run_on_startup', 'disable_versioning' ];
|
||||
|
||||
async function getNoteAttributeMap(noteId) {
|
||||
return await sql.getMap(`SELECT name, value FROM attributes WHERE noteId = ?`, [noteId]);
|
||||
}
|
||||
|
@ -64,5 +66,6 @@ module.exports = {
|
|||
getNotesWithAttribute,
|
||||
getNoteWithAttribute,
|
||||
getNoteIdsWithAttribute,
|
||||
createAttribute
|
||||
createAttribute,
|
||||
BUILTIN_ATTRIBUTES
|
||||
};
|
|
@ -400,7 +400,7 @@
|
|||
<tr>
|
||||
<td data-bind="text: attributeId"></td>
|
||||
<td>
|
||||
<input type="text" data-bind="value: name, event: { change: $parent.attributeChanged }"/>
|
||||
<input type="text" class="attribute-name" data-bind="value: name, event: { change: $parent.attributeChanged }"/>
|
||||
|
||||
<div style="color: red" data-bind="if: $parent.isNotUnique($index())">Attribute name must be unique per note.</div>
|
||||
<div style="color: red" data-bind="if: $parent.isEmptyName($index())">Attribute name can't be empty.</div>
|
||||
|
|
Loading…
Reference in a new issue