mirror of
https://github.com/zadam/trilium.git
synced 2025-03-01 14:22:32 +01:00
basic saving of attributes in the widget
This commit is contained in:
parent
ad48b59893
commit
f245d51746
2
libraries/ckeditor/ckeditor.js
vendored
2
libraries/ckeditor/ckeditor.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -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();
|
||||
|
@ -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(" ", " ");
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -800,3 +800,7 @@ body {
|
||||
.hidden-int, .hidden-ext {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.ck.ck-mentions > .ck-list__item {
|
||||
max-width: 600px;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user