From 170d317589bb39006a94af1f3bdba37cde2960af Mon Sep 17 00:00:00 2001 From: azivner Date: Sun, 29 Jul 2018 16:06:13 +0200 Subject: [PATCH] #125, basic infrastructure for scripts attached to notes via relations --- src/public/javascripts/services/bundle.js | 11 +++++++++-- src/public/javascripts/services/note_detail.js | 13 +++++++++++-- src/public/javascripts/services/script_api.js | 10 +++++++--- src/public/javascripts/services/script_context.js | 4 ++-- src/routes/api/script.js | 3 ++- src/services/script.js | 9 +++++---- src/services/script_context.js | 8 +++++--- src/views/index.ejs | 2 ++ 8 files changed, 43 insertions(+), 17 deletions(-) diff --git a/src/public/javascripts/services/bundle.js b/src/public/javascripts/services/bundle.js index 89157a564..a1b0ae76c 100644 --- a/src/public/javascripts/services/bundle.js +++ b/src/public/javascripts/services/bundle.js @@ -1,8 +1,14 @@ import ScriptContext from "./script_context.js"; import server from "./server.js"; -async function executeBundle(bundle) { - const apiContext = ScriptContext(bundle.note, bundle.allNotes); +async function getAndExecuteBundle(noteId, targetNote = null) { + const bundle = await server.get('script/bundle/' + noteId); + + await executeBundle(bundle, targetNote); +} + +async function executeBundle(bundle, targetNote) { + const apiContext = ScriptContext(bundle.note, bundle.allNotes, targetNote); return await (function () { return eval(`const apiContext = this; (async function() { ${bundle.script}\r\n})()`); @@ -19,5 +25,6 @@ async function executeStartupBundles() { export default { executeBundle, + getAndExecuteBundle, executeStartupBundles } \ No newline at end of file diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js index b6710032a..7394e8023 100644 --- a/src/public/javascripts/services/note_detail.js +++ b/src/public/javascripts/services/note_detail.js @@ -15,6 +15,7 @@ import noteDetailText from './note_detail_text.js'; import noteDetailFile from './note_detail_file.js'; import noteDetailSearch from './note_detail_search.js'; import noteDetailRender from './note_detail_render.js'; +import bundleService from "./bundle.js"; const $noteTitle = $("#note-title"); @@ -30,6 +31,7 @@ const $labelListInner = $("#label-list-inner"); const $relationList = $("#relation-list"); const $relationListInner = $("#relation-list-inner"); const $childrenOverview = $("#children-overview"); +const $scriptArea = $("#note-detail-script-area"); let currentNote = null; @@ -144,6 +146,8 @@ async function handleProtectedSession() { } async function loadNoteDetail(noteId) { + $scriptArea.html(''); + currentNote = await loadNote(noteId); if (isNewNoteCreated) { @@ -183,10 +187,15 @@ async function loadNoteDetail(noteId) { const labels = await loadLabelList(); - loadRelationList(); // no need to wait - const hideChildrenOverview = labels.some(label => label.name === 'hideChildrenOverview'); await showChildrenOverview(hideChildrenOverview); + + const relations = await loadRelationList(); + const relationsToRun = relations.filter(relation => relation.name === 'runOnNoteView'); + + for (const relationToRun of relationsToRun) { + await bundleService.getAndExecuteBundle(relationToRun.targetNoteId, getCurrentNote()); + } } async function showChildrenOverview(hideChildrenOverview) { diff --git a/src/public/javascripts/services/script_api.js b/src/public/javascripts/services/script_api.js index dc1523d73..7183da5ab 100644 --- a/src/public/javascripts/services/script_api.js +++ b/src/public/javascripts/services/script_api.js @@ -2,8 +2,9 @@ import treeService from './tree.js'; import server from './server.js'; import utils from './utils.js'; import infoService from './info.js'; +import linkService from './link.js'; -function ScriptApi(startNote, currentNote) { +function ScriptApi(startNote, currentNote, targetNote = null) { const $pluginButtons = $("#plugin-buttons"); async function activateNote(notePath) { @@ -42,7 +43,8 @@ function ScriptApi(startNote, currentNote) { script: script, params: prepareParams(params), startNoteId: startNote.noteId, - currentNoteId: currentNote.noteId + currentNoteId: currentNote.noteId, + targetNoteId: targetNote ? targetNote.noteId : null }); return ret.executionResult; @@ -51,6 +53,7 @@ function ScriptApi(startNote, currentNote) { return { startNote: startNote, currentNote: currentNote, + targetNote: targetNote, addButtonToToolbar, activateNote, getInstanceName: () => window.glob.instanceName, @@ -59,7 +62,8 @@ function ScriptApi(startNote, currentNote) { parseDate: utils.parseDate, showMessage: infoService.showMessage, showError: infoService.showError, - reloadTree: treeService.reload + reloadTree: treeService.reload, + createNoteLink: linkService.createNoteLink } } diff --git a/src/public/javascripts/services/script_context.js b/src/public/javascripts/services/script_context.js index 7b60e22df..afd372aab 100644 --- a/src/public/javascripts/services/script_context.js +++ b/src/public/javascripts/services/script_context.js @@ -1,13 +1,13 @@ import ScriptApi from './script_api.js'; import utils from './utils.js'; -function ScriptContext(startNote, allNotes) { +function ScriptContext(startNote, allNotes, targetNote = null) { const modules = {}; return { modules: modules, notes: utils.toObject(allNotes, note => [note.noteId, note]), - apis: utils.toObject(allNotes, note => [note.noteId, ScriptApi(startNote, note)]), + apis: utils.toObject(allNotes, note => [note.noteId, ScriptApi(startNote, note, targetNote)]), require: moduleNoteIds => { return moduleName => { const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId)); diff --git a/src/routes/api/script.js b/src/routes/api/script.js index 4b645b1c8..a6aadd7f3 100644 --- a/src/routes/api/script.js +++ b/src/routes/api/script.js @@ -5,7 +5,8 @@ const scriptService = require('../../services/script'); const repository = require('../../services/repository'); async function exec(req) { - const result = await scriptService.executeScript(req.body.script, req.body.params, req.body.startNoteId, req.body.currentNoteId); + const result = await scriptService.executeScript(req.body.script, req.body.params, req.body.startNoteId, + req.body.currentNoteId, req.body.targetNoteId); return { executionResult: result }; } diff --git a/src/services/script.js b/src/services/script.js index 1e737c2bc..9b6d47210 100644 --- a/src/services/script.js +++ b/src/services/script.js @@ -14,7 +14,7 @@ async function executeNote(note) { await executeBundle(bundle); } -async function executeBundle(bundle, startNote) { +async function executeBundle(bundle, startNote, targetNote = null) { if (!startNote) { // this is the default case, the only exception is when we want to preserve frontend startNote startNote = bundle.note; @@ -23,7 +23,7 @@ async function executeBundle(bundle, startNote) { // last \r\n is necessary if script contains line comment on its last line const script = "async function() {\r\n" + bundle.script + "\r\n}"; - const ctx = new ScriptContext(startNote, bundle.allNotes); + const ctx = new ScriptContext(startNote, bundle.allNotes, targetNote); if (await bundle.note.hasLabel('manualTransactionHandling')) { return await execute(ctx, script, ''); @@ -37,9 +37,10 @@ async function executeBundle(bundle, startNote) { * This method preserves frontend startNode - that's why we start execution from currentNote and override * bundle's startNote. */ -async function executeScript(script, params, startNoteId, currentNoteId) { +async function executeScript(script, params, startNoteId, currentNoteId, targetNoteId) { const startNote = await repository.getNote(startNoteId); const currentNote = await repository.getNote(currentNoteId); + const targetNote = await repository.getNote(targetNoteId); currentNote.content = `return await (${script}\r\n)(${getParams(params)})`; currentNote.type = 'code'; @@ -47,7 +48,7 @@ async function executeScript(script, params, startNoteId, currentNoteId) { const bundle = await getScriptBundle(currentNote); - return await executeBundle(bundle, startNote); + return await executeBundle(bundle, startNote, targetNote); } async function execute(ctx, script, paramsStr) { diff --git a/src/services/script_context.js b/src/services/script_context.js index be8aa954b..68cef3a35 100644 --- a/src/services/script_context.js +++ b/src/services/script_context.js @@ -9,10 +9,10 @@ const config = require('./config'); const repository = require('./repository'); const axios = require('axios'); -function ScriptContext(startNote, allNotes) { +function ScriptContext(startNote, allNotes, targetNote = null) { this.modules = {}; this.notes = utils.toObject(allNotes, note => [note.noteId, note]); - this.apis = utils.toObject(allNotes, note => [note.noteId, new ScriptApi(startNote, note)]); + this.apis = utils.toObject(allNotes, note => [note.noteId, new ScriptApi(startNote, note, targetNote)]); this.require = moduleNoteIds => { return moduleName => { const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId)); @@ -27,9 +27,10 @@ function ScriptContext(startNote, allNotes) { }; } -function ScriptApi(startNote, currentNote) { +function ScriptApi(startNote, currentNote, targetNote) { this.startNote = startNote; this.currentNote = currentNote; + this.targetNote = targetNote; this.axios = axios; @@ -44,6 +45,7 @@ function ScriptApi(startNote, currentNote) { this.getNote = repository.getNote; this.getBranch = repository.getBranch; this.getLabel = repository.getLabel; + this.getRelation = repository.getRelation; this.getImage = repository.getImage; this.getEntity = repository.getEntity; this.getEntities = repository.getEntities; diff --git a/src/views/index.ejs b/src/views/index.ejs index 19dd4b7ed..740790de3 100644 --- a/src/views/index.ejs +++ b/src/views/index.ejs @@ -180,6 +180,8 @@
+
+