added new label "sorted" which will keep children notes alphabetically sorted, fixes #82

This commit is contained in:
azivner 2018-08-01 09:26:02 +02:00
parent 9452fc236b
commit 2d24bf81dd
12 changed files with 100 additions and 10 deletions

View File

@ -11,6 +11,7 @@ const os = require('os');
const sessionSecret = require('./services/session_secret');
const cls = require('./services/cls');
require('./entities/entity_constructor');
require('./services/handlers');
const app = express();

View File

@ -30,6 +30,10 @@ class Note extends Entity {
catch(e) {}
}
isRoot() {
return this.noteId === 'root';
}
isJson() {
return this.mime === "application/json";
}

View File

@ -3,6 +3,7 @@ import infoService from "./info.js";
const $outstandingSyncsCount = $("#outstanding-syncs-count");
const syncMessageHandlers = [];
const messageHandlers = [];
let ws;
@ -25,9 +26,17 @@ function subscribeToMessages(messageHandler) {
messageHandlers.push(messageHandler);
}
function subscribeToSyncMessages(messageHandler) {
syncMessageHandlers.push(messageHandler);
}
function handleMessage(event) {
const message = JSON.parse(event.data);
for (const messageHandler of messageHandlers) {
messageHandler(message);
}
if (message.type === 'sync') {
lastPingTs = new Date().getTime();
@ -39,8 +48,8 @@ function handleMessage(event) {
const syncData = message.data.filter(sync => sync.sourceId !== glob.sourceId);
for (const messageHandler of messageHandlers) {
messageHandler(syncData);
for (const syncMessageHandler of syncMessageHandlers) {
syncMessageHandler(syncData);
}
$outstandingSyncsCount.html(message.outstandingSyncs);
@ -104,5 +113,6 @@ setTimeout(() => {
export default {
logError,
subscribeToMessages
subscribeToMessages,
subscribeToSyncMessages
};

View File

@ -276,7 +276,7 @@ function focus() {
getComponent(note.type).focus();
}
messagingService.subscribeToMessages(syncData => {
messagingService.subscribeToSyncMessages(syncData => {
if (syncData.some(sync => sync.entityName === 'notes' && sync.entityId === getCurrentNoteId())) {
infoService.showMessage('Reloading note because of background changes');

View File

@ -505,7 +505,13 @@ async function showTree() {
initFancyTree(tree);
}
messagingService.subscribeToMessages(syncData => {
messagingService.subscribeToMessages(message => {
if (message.type === 'refresh-tree') {
reload();
}
});
messagingService.subscribeToSyncMessages(syncData => {
if (syncData.some(sync => sync.entityName === 'branches')
|| syncData.some(sync => sync.entityName === 'notes')) {

View File

@ -42,6 +42,7 @@ async function getRootCalendarNote() {
})).note;
await labelService.createLabel(rootNote.noteId, CALENDAR_ROOT_LABEL);
await labelService.createLabel(rootNote.noteId, 'sorted');
}
return rootNote;
@ -60,6 +61,7 @@ async function getYearNote(dateTimeStr, rootNote) {
}
await labelService.createLabel(yearNote.noteId, YEAR_LABEL, yearStr);
await labelService.createLabel(yearNote.noteId, 'sorted');
}
return yearNote;
@ -85,6 +87,7 @@ async function getMonthNote(dateTimeStr, rootNote) {
}
await labelService.createLabel(monthNote.noteId, MONTH_LABEL, monthStr);
await labelService.createLabel(monthNote.noteId, 'sorted');
}
return monthNote;

View File

@ -1,3 +1,4 @@
const NOTE_TITLE_CHANGED = "NOTE_TITLE_CHANGED";
const ENTER_PROTECTED_SESSION = "ENTER_PROTECTED_SESSION";
const ENTITY_CHANGED = "ENTITY_CHANGED";
@ -19,10 +20,22 @@ function emit(eventType, data) {
}
}
async function syncEmit(eventType, data) {
const listeners = eventListeners[eventType];
if (listeners) {
for (const listener of listeners) {
await listener(data);
}
}
}
module.exports = {
subscribe,
emit,
syncEmit,
// event types:
NOTE_TITLE_CHANGED,
ENTER_PROTECTED_SESSION,
ENTITY_CHANGED
};

27
src/services/handlers.js Normal file
View File

@ -0,0 +1,27 @@
const eventService = require('./events');
const scriptService = require('./script');
const relationService = require('./relations');
const treeService = require('./tree');
const messagingService = require('./messaging');
eventService.subscribe(eventService.NOTE_TITLE_CHANGED, async note => {
const relations = await relationService.getEffectiveRelations(note.noteId, 'runOnNoteTitleChange');
for (const relation of relations) {
const scriptNote = await relation.getTargetNote();
await scriptService.executeNote(scriptNote, scriptNote, note);
}
if (!note.isRoot()) {
const parents = await note.getParentNotes();
for (const parent of parents) {
if (await parent.hasLabel("sorted")) {
await treeService.sortNotesAlphabetically(parent.noteId);
messagingService.sendMessageToAllClients({ type: 'refresh-tree' });
}
}
}
});

View File

@ -3,6 +3,7 @@ const optionService = require('./options');
const dateUtils = require('./date_utils');
const syncTableService = require('./sync_table');
const labelService = require('./labels');
const eventService = require('./events');
const repository = require('./repository');
const Note = require('../entities/note');
const NoteImage = require('../entities/note_image');
@ -34,6 +35,10 @@ async function getNewNotePosition(parentNoteId, noteData) {
return newNotePos;
}
async function triggerNoteTitleChanged(note) {
await eventService.emit(eventService.NOTE_TITLE_CHANGED, note);
}
async function createNewNote(parentNoteId, noteData) {
const newNotePos = await getNewNotePosition(parentNoteId, noteData);
@ -60,6 +65,8 @@ async function createNewNote(parentNoteId, noteData) {
isExpanded: 0
}).save();
await triggerNoteTitleChanged(note);
return {
note,
branch
@ -92,6 +99,8 @@ async function createNote(parentNoteId, title, content = "", extraOptions = {})
}
}
await triggerNoteTitleChanged(note);
return {note, branch};
}
@ -200,11 +209,17 @@ async function updateNote(noteId, noteUpdates) {
await saveNoteRevision(note);
const noteTitleChanged = note.title !== noteUpdates.title;
note.title = noteUpdates.title;
note.setContent(noteUpdates.content);
note.isProtected = noteUpdates.isProtected;
await note.save();
if (noteTitleChanged) {
await triggerNoteTitleChanged(note);
}
await saveNoteImages(note);
await protectNoteRevisions(note);

View File

@ -4,7 +4,8 @@ const repository = require('./repository');
const Relation = require('../entities/relation');
const BUILTIN_RELATIONS = [
'runOnNoteView'
'runOnNoteView',
'runOnNoteTitleChange'
];
async function getNotesWithRelation(name, targetNoteId) {
@ -36,8 +37,8 @@ async function createRelation(sourceNoteId, name, targetNoteId) {
}).save();
}
async function getEffectiveRelations(noteId) {
return await repository.getEntities(`
async function getEffectiveRelations(noteId, relationName) {
const relations = await repository.getEntities(`
WITH RECURSIVE tree(noteId) AS (
SELECT ?
UNION
@ -48,6 +49,13 @@ async function getEffectiveRelations(noteId) {
)
SELECT relations.* FROM relations JOIN tree ON relations.sourceNoteId = tree.noteId
WHERE relations.isDeleted = 0 AND (relations.isInheritable = 1 OR relations.sourceNoteId = ?)`, [noteId, noteId]);
if (relationName) {
return relations.filter(relation => relation.name === relationName);
}
else {
return relations;
}
}
module.exports = {

View File

@ -4,14 +4,14 @@ const repository = require('./repository');
const cls = require('./cls');
const sourceIdService = require('./source_id');
async function executeNote(note) {
async function executeNote(note, targetNote) {
if (!note.isJavaScript()) {
return;
}
const bundle = await getScriptBundle(note);
await executeBundle(bundle);
await executeBundle(bundle, note, targetNote);
}
async function executeBundle(bundle, startNote, targetNote = null) {

View File

@ -5,6 +5,7 @@ const utils = require('./utils');
const dateUtils = require('./date_utils');
const labelService = require('./labels');
const dateNoteService = require('./date_notes');
const treeService = require('./tree');
const config = require('./config');
const repository = require('./repository');
const axios = require('axios');
@ -61,6 +62,8 @@ function ScriptApi(startNote, currentNote, targetNote) {
this.getRootCalendarNote = dateNoteService.getRootCalendarNote;
this.getDateNote = dateNoteService.getDateNote;
this.sortNotesAlphabetically = treeService.sortNotesAlphabetically;
this.transactional = sql.transactional;
}