basic saving of attributes in the widget

This commit is contained in:
zadam 2020-06-05 17:25:14 +02:00
parent ad48b59893
commit f245d51746
8 changed files with 130 additions and 20 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -541,13 +541,14 @@ class Note extends Entity {
/**
* @return {Promise<Attribute>}
*/
async addAttribute(type, name, value = "", isInheritable = false) {
async addAttribute(type, name, value = "", isInheritable = false, position = 1000) {
const attr = new Attribute({
noteId: this.noteId,
type: type,
name: name,
value: value,
isInheritable: isInheritable
isInheritable: isInheritable,
position: position
});
await attr.save();

View File

@ -1,9 +1,19 @@
function preprocessRelations(str) {
return str.replace(/<a[^>]+href="(#root[A-Za-z0-9/]*)"[^>]*>[^<]*<\/a>/g, "$1");
function preprocess(str) {
if (str.startsWith('<p>')) {
str = str.substr(3);
}
if (str.endsWith('</p>')) {
str = str.substr(0, str.length - 4);
}
str = str.replace("&nbsp;", " ");
return str.replace(/<a[^>]+href="(#[A-Za-z0-9/]*)"[^>]*>[^<]*<\/a>/g, "$1");
}
function lexer(str) {
str = preprocessRelations(str);
str = preprocess(str);
const expressionTokens = [];
@ -108,7 +118,8 @@ function parser(tokens) {
if (token.startsWith('#')) {
const attr = {
type: 'label',
name: token.substr(1)
name: token.substr(1),
isInheritable: false // FIXME
};
if (tokens[i + 1] === "=") {
@ -124,18 +135,25 @@ function parser(tokens) {
attrs.push(attr);
}
else if (token.startsWith('~')) {
const attr = {
type: 'relation',
name: token.substr(1)
};
if (i + 2 >= tokens.length || tokens[i + 1] !== '=') {
throw new Error(`Relation "${token}" should point to a note.`);
}
i += 2;
attr.value = tokens[i];
let notePath = tokens[i];
if (notePath.startsWith("#")) {
notePath = notePath.substr(1);
}
const noteId = notePath.split('/').pop();
const attr = {
type: 'relation',
name: token.substr(1),
isInheritable: false, // FIXME
value: noteId
};
attrs.push(attr);
}
@ -147,7 +165,14 @@ function parser(tokens) {
return attrs;
}
function lexAndParse(str) {
const tokens = lexer(str);
return parser(tokens);
}
export default {
lexer,
parser
parser,
lexAndParse
}

View File

@ -6,7 +6,7 @@ import server from "../services/server.js";
import utils from "../services/utils.js";
import ws from "../services/ws.js";
import SpacedUpdate from "../services/spaced_update.js";
import protectedSessionHolder from "../services/protected_session_holder.js";
import attributesParser from "../services/attribute_parser.js";
const mentionSetup = {
feeds: [
@ -15,8 +15,6 @@ const mentionSetup = {
feed: queryText => {
return new Promise((res, rej) => {
noteAutocompleteService.autocompleteSource(queryText, rows => {
console.log("rows", rows);
res(rows.map(row => {
return {
id: '@' + row.notePathTitle,
@ -51,7 +49,8 @@ const mentionSetup = {
}
});
},
minimumCharacters: 0
minimumCharacters: 0,
attributeMention: true
},
{
marker: '~',
@ -65,7 +64,8 @@ const mentionSetup = {
}
});
},
minimumCharacters: 0
minimumCharacters: 0,
attributeMention: true
}
]
};
@ -92,6 +92,17 @@ export default class NoteAttributesWidget extends TabAwareWidget {
this.$editor = this.$widget.find('.note-attributes-editor');
this.initialized = this.initEditor();
this.$editor.keypress(async e => {
const keycode = (e.keyCode ? e.keyCode : e.which);
if (keycode === 13) {
const attributes = attributesParser.lexAndParse(this.textEditor.getData());
await server.put(`notes/${this.noteId}/attributes2`, attributes, this.componentId);
console.log("Saved!");
}
})
return this.$widget;
}

View File

@ -800,3 +800,7 @@ body {
.hidden-int, .hidden-ext {
display: none !important;
}
.ck.ck-mentions > .ck-list__item {
max-width: 600px;
}

View File

@ -1,6 +1,7 @@
"use strict";
const sql = require('../../services/sql');
const log = require('../../services/log');
const attributeService = require('../../services/attributes');
const repository = require('../../services/repository');
const Attribute = require('../../entities/attribute');
@ -82,6 +83,72 @@ async function deleteNoteAttribute(req) {
}
}
async function updateNoteAttributes2(req) {
const noteId = req.params.noteId;
const incomingAttributes = req.body;
const note = await repository.getNote(noteId);
let existingAttrs = await note.getAttributes();
let position = 0;
for (const incAttr of incomingAttributes) {
position += 10;
const perfectMatchAttr = existingAttrs.find(attr =>
attr.type === incAttr.type &&
attr.name === incAttr.name &&
attr.isInheritable === incAttr.isInheritable &&
attr.value === incAttr.value);
if (perfectMatchAttr) {
existingAttrs = existingAttrs.filter(attr => attr.attributeId !== perfectMatchAttr.attributeId);
if (perfectMatchAttr.position !== position) {
perfectMatchAttr.position = position;
await perfectMatchAttr.save();
}
continue; // nothing to update
}
if (incAttr.type === 'relation') {
const targetNote = await repository.getNote(incAttr.value);
if (!targetNote || targetNote.isDeleted) {
log.error(`Target note of relation ${JSON.stringify(incAttr)} does not exist or is deleted`);
continue;
}
}
const matchedAttr = existingAttrs.find(attr =>
attr.type === incAttr.type &&
attr.name === incAttr.name &&
attr.isInheritable === incAttr.isInheritable);
if (matchedAttr) {
matchedAttr.value = incAttr.value;
matchedAttr.position = position;
await matchedAttr.save();
existingAttrs = existingAttrs.filter(attr => attr.attributeId !== matchedAttr.attributeId);
continue;
}
// no existing attribute has been matched so we need to create a new one
// type, name and isInheritable are immutable so even if there is an attribute with matching type & name, we need to create a new one and delete the former one
await note.addAttribute(incAttr.type, incAttr.name, incAttr.value, incAttr.isInheritable, position);
}
// all the remaining existing attributes are not defined anymore and should be deleted
for (const toDeleteAttr of existingAttrs) {
toDeleteAttr.isDeleted = true;
await toDeleteAttr.save();
}
}
async function updateNoteAttributes(req) {
const noteId = req.params.noteId;
const attributes = req.body;
@ -193,6 +260,7 @@ async function deleteRelation(req) {
module.exports = {
updateNoteAttributes,
updateNoteAttributes2,
updateNoteAttribute,
deleteNoteAttribute,
getAttributeNames,

View File

@ -167,6 +167,7 @@ function register(app) {
apiRoute(GET, '/api/notes/:noteId/attributes', attributesRoute.getEffectiveNoteAttributes);
apiRoute(PUT, '/api/notes/:noteId/attributes', attributesRoute.updateNoteAttributes);
apiRoute(PUT, '/api/notes/:noteId/attributes2', attributesRoute.updateNoteAttributes2);
apiRoute(PUT, '/api/notes/:noteId/attribute', attributesRoute.updateNoteAttribute);
apiRoute(PUT, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.createRelation);
apiRoute(DELETE, '/api/notes/:noteId/relations/:name/to/:targetNoteId', attributesRoute.deleteRelation);