mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
autocomplete for attribute names, issue #31
This commit is contained in:
parent
bc4aa3e40a
commit
a3b31fab54
@ -3,6 +3,7 @@
|
|||||||
const attributesDialog = (function() {
|
const attributesDialog = (function() {
|
||||||
const dialogEl = $("#attributes-dialog");
|
const dialogEl = $("#attributes-dialog");
|
||||||
const attributesModel = new AttributesModel();
|
const attributesModel = new AttributesModel();
|
||||||
|
let attributeNames = [];
|
||||||
|
|
||||||
function AttributesModel() {
|
function AttributesModel() {
|
||||||
const self = this;
|
const self = this;
|
||||||
@ -17,6 +18,10 @@ const attributesDialog = (function() {
|
|||||||
self.attributes(attributes.map(ko.observable));
|
self.attributes(attributes.map(ko.observable));
|
||||||
|
|
||||||
addLastEmptyRow();
|
addLastEmptyRow();
|
||||||
|
|
||||||
|
attributeNames = await server.get('attributes/names');
|
||||||
|
|
||||||
|
$(".attribute-name:last").focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
function isValid() {
|
function isValid() {
|
||||||
@ -54,11 +59,7 @@ const attributesDialog = (function() {
|
|||||||
const attrs = self.attributes();
|
const attrs = self.attributes();
|
||||||
const last = attrs[attrs.length - 1]();
|
const last = attrs[attrs.length - 1]();
|
||||||
|
|
||||||
// console.log("last", attrs.map(attr => attr()));
|
|
||||||
|
|
||||||
if (last.name.trim() !== "" || last.value !== "") {
|
if (last.name.trim() !== "" || last.value !== "") {
|
||||||
console.log("Adding new row");
|
|
||||||
|
|
||||||
self.attributes.push(ko.observable({
|
self.attributes.push(ko.observable({
|
||||||
attributeId: '',
|
attributeId: '',
|
||||||
name: '',
|
name: '',
|
||||||
@ -68,8 +69,6 @@ const attributesDialog = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.attributeChanged = function (row) {
|
this.attributeChanged = function (row) {
|
||||||
console.log(row);
|
|
||||||
|
|
||||||
addLastEmptyRow();
|
addLastEmptyRow();
|
||||||
|
|
||||||
for (const attr of self.attributes()) {
|
for (const attr of self.attributes()) {
|
||||||
@ -124,6 +123,22 @@ const attributesDialog = (function() {
|
|||||||
|
|
||||||
ko.applyBindings(attributesModel, document.getElementById('attributes-dialog'));
|
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 {
|
return {
|
||||||
showDialog
|
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
|
// 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) => {
|
$.ui.autocomplete.filter = (array, terms) => {
|
||||||
if (!terms) {
|
if (!terms) {
|
||||||
return [];
|
return array;
|
||||||
}
|
}
|
||||||
|
|
||||||
const startDate = new Date();
|
const startDate = new Date();
|
||||||
|
@ -7,14 +7,15 @@ const auth = require('../../services/auth');
|
|||||||
const sync_table = require('../../services/sync_table');
|
const sync_table = require('../../services/sync_table');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const wrap = require('express-promise-wrap').wrap;
|
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;
|
const noteId = req.params.noteId;
|
||||||
|
|
||||||
res.send(await sql.getRows("SELECT * FROM attributes WHERE noteId = ? ORDER BY dateCreated", [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 noteId = req.params.noteId;
|
||||||
const attributes = req.body;
|
const attributes = req.body;
|
||||||
const now = utils.nowDate();
|
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]));
|
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;
|
module.exports = router;
|
@ -40,7 +40,7 @@ function register(app) {
|
|||||||
app.use('/api/notes', notesApiRoute);
|
app.use('/api/notes', notesApiRoute);
|
||||||
app.use('/api/tree', treeChangesApiRoute);
|
app.use('/api/tree', treeChangesApiRoute);
|
||||||
app.use('/api/notes', cloningApiRoute);
|
app.use('/api/notes', cloningApiRoute);
|
||||||
app.use('/api/notes', attributesRoute);
|
app.use('/api', attributesRoute);
|
||||||
app.use('/api/notes-history', noteHistoryApiRoute);
|
app.use('/api/notes-history', noteHistoryApiRoute);
|
||||||
app.use('/api/recent-changes', recentChangesApiRoute);
|
app.use('/api/recent-changes', recentChangesApiRoute);
|
||||||
app.use('/api/settings', settingsApiRoute);
|
app.use('/api/settings', settingsApiRoute);
|
||||||
|
@ -5,6 +5,8 @@ const utils = require('./utils');
|
|||||||
const sync_table = require('./sync_table');
|
const sync_table = require('./sync_table');
|
||||||
const Repository = require('./repository');
|
const Repository = require('./repository');
|
||||||
|
|
||||||
|
const BUILTIN_ATTRIBUTES = [ 'run_on_startup', 'disable_versioning' ];
|
||||||
|
|
||||||
async function getNoteAttributeMap(noteId) {
|
async function getNoteAttributeMap(noteId) {
|
||||||
return await sql.getMap(`SELECT name, value FROM attributes WHERE noteId = ?`, [noteId]);
|
return await sql.getMap(`SELECT name, value FROM attributes WHERE noteId = ?`, [noteId]);
|
||||||
}
|
}
|
||||||
@ -64,5 +66,6 @@ module.exports = {
|
|||||||
getNotesWithAttribute,
|
getNotesWithAttribute,
|
||||||
getNoteWithAttribute,
|
getNoteWithAttribute,
|
||||||
getNoteIdsWithAttribute,
|
getNoteIdsWithAttribute,
|
||||||
createAttribute
|
createAttribute,
|
||||||
|
BUILTIN_ATTRIBUTES
|
||||||
};
|
};
|
@ -400,7 +400,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td data-bind="text: attributeId"></td>
|
<td data-bind="text: attributeId"></td>
|
||||||
<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.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>
|
<div style="color: red" data-bind="if: $parent.isEmptyName($index())">Attribute name can't be empty.</div>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user