autocomplete for attribute names, issue #31

This commit is contained in:
azivner 2018-02-04 19:27:27 -05:00
parent bc4aa3e40a
commit a3b31fab54
6 changed files with 47 additions and 12 deletions

View file

@ -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
};

View file

@ -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();

View file

@ -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;

View file

@ -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);

View file

@ -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
};

View file

@ -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>