diff --git a/.gitignore b/.gitignore index 26d2bd355..fe971b317 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ yarn-error.log *.db config.ini cert.key -cert.crt \ No newline at end of file +cert.crt +docs/ \ No newline at end of file diff --git a/package.json b/package.json index b0ac5adad..a0f659589 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,9 @@ "package-forge": "electron-forge package", "make-forge": "electron-forge make", "publish-forge": "electron-forge publish", - "build-docs": "jsdoc src/entities/*.js src/services/backend_script_api.js" + "build-backend-docs": "jsdoc -d ./docs/backend_api src/entities/*.js src/services/backend_script_api.js", + "build-frontend-docs": "jsdoc -d ./docs/frontend_api src/public/javascripts/entities/*.js src/public/javascripts/services/frontend_script_api.js", + "build-docs": "npm run build-backend-docs && npm run build-frontend-docs" }, "dependencies": { "async-mutex": "^0.1.3", diff --git a/src/public/javascripts/dialogs/jump_to_note.js b/src/public/javascripts/dialogs/jump_to_note.js index 39715b1e6..dfedc06b7 100644 --- a/src/public/javascripts/dialogs/jump_to_note.js +++ b/src/public/javascripts/dialogs/jump_to_note.js @@ -31,7 +31,7 @@ async function showDialog() { const notePath = linkService.getNotePathFromLabel(ui.item.value); - treeService.activateNode(notePath); + treeService.activateNote(notePath); $dialog.dialog('close'); } diff --git a/src/public/javascripts/entities/branch.js b/src/public/javascripts/entities/branch.js index 2a2268e5d..b3179b812 100644 --- a/src/public/javascripts/entities/branch.js +++ b/src/public/javascripts/entities/branch.js @@ -1,19 +1,28 @@ +/** Represents mapping between note and parent note */ class Branch { constructor(treeCache, row) { this.treeCache = treeCache; + /** @param {string} primary key */ this.branchId = row.branchId; + /** @param {string} */ this.noteId = row.noteId; this.note = null; + /** @param {string} */ this.parentNoteId = row.parentNoteId; + /** @param {int} */ this.notePosition = row.notePosition; + /** @param {string} */ this.prefix = row.prefix; + /** @param {boolean} */ this.isExpanded = row.isExpanded; } + /** @returns {NoteShort} */ async getNote() { return await this.treeCache.getNote(this.noteId); } + /** @returns {boolean} true if it's top level, meaning its parent is root note */ isTopLevel() { return this.parentNoteId === 'root'; } diff --git a/src/public/javascripts/entities/note_full.js b/src/public/javascripts/entities/note_full.js index 4e6daf931..735e43526 100644 --- a/src/public/javascripts/entities/note_full.js +++ b/src/public/javascripts/entities/note_full.js @@ -1,13 +1,18 @@ import NoteShort from './note_short.js'; +/** + * Represents full note, specifically including note's content. + */ class NoteFull extends NoteShort { constructor(treeCache, row) { super(treeCache, row); + /** @param {string} */ this.content = row.content; if (this.content !== "" && this.isJson()) { try { + /** @param {object} */ this.jsonContent = JSON.parse(this.content); } catch(e) {} diff --git a/src/public/javascripts/entities/note_short.js b/src/public/javascripts/entities/note_short.js index ecbc91da1..62e08c325 100644 --- a/src/public/javascripts/entities/note_short.js +++ b/src/public/javascripts/entities/note_short.js @@ -1,19 +1,31 @@ +/** + * This note's representation is used in note tree and is kept in TreeCache. + * Its notable omission is the note content. + */ class NoteShort { constructor(treeCache, row) { this.treeCache = treeCache; + /** @param {string} */ this.noteId = row.noteId; + /** @param {string} */ this.title = row.title; + /** @param {boolean} */ this.isProtected = row.isProtected; + /** @param {string} one of 'text', 'code', 'file' or 'render' */ this.type = row.type; + /** @param {string} content-type, e.g. "application/json" */ this.mime = row.mime; + /** @param {boolean} */ this.archived = row.archived; this.cssClass = row.cssClass; } + /** @returns {boolean} */ isJson() { return this.mime === "application/json"; } + /** @returns {Promise>} */ async getBranches() { const branchIds = this.treeCache.parents[this.noteId].map( parentNoteId => this.treeCache.getBranchIdByChildParent(this.noteId, parentNoteId)); @@ -21,11 +33,13 @@ class NoteShort { return this.treeCache.getBranches(branchIds); } + /** @returns {boolean} */ hasChildren() { return this.treeCache.children[this.noteId] && this.treeCache.children[this.noteId].length > 0; } + /** @returns {Promise>} */ async getChildBranches() { if (!this.treeCache.children[this.noteId]) { return []; @@ -37,18 +51,22 @@ class NoteShort { return await this.treeCache.getBranches(branchIds); } + /** @returns {Array.} */ getParentNoteIds() { return this.treeCache.parents[this.noteId] || []; } + /** @returns {Promise>} */ async getParentNotes() { return await this.treeCache.getNotes(this.getParentNoteIds()); } + /** @returns {Array.} */ getChildNoteIds() { return this.treeCache.children[this.noteId] || []; } + /** @returns {Promise>} */ async getChildNotes() { return await this.treeCache.getNotes(this.getChildNoteIds()); } diff --git a/src/public/javascripts/services/bootstrap.js b/src/public/javascripts/services/bootstrap.js index 57d801919..5fb4889f0 100644 --- a/src/public/javascripts/services/bootstrap.js +++ b/src/public/javascripts/services/bootstrap.js @@ -17,7 +17,7 @@ import noteDetailService from './note_detail.js'; import noteType from './note_type.js'; import protected_session from './protected_session.js'; import searchNotesService from './search_notes.js'; -import ScriptApi from './script_api.js'; +import FrontendScriptApi from './frontend_script_api.js'; import ScriptContext from './script_context.js'; import sync from './sync.js'; import treeService from './tree.js'; @@ -88,7 +88,7 @@ if (utils.isElectron()) { await treeService.reload(); } - await treeService.activateNode(parentNoteId); + await treeService.activateNote(parentNoteId); setTimeout(() => { const node = treeService.getCurrentNode(); diff --git a/src/public/javascripts/services/file.js b/src/public/javascripts/services/file.js index bc222101f..2e473f4e8 100644 --- a/src/public/javascripts/services/file.js +++ b/src/public/javascripts/services/file.js @@ -21,7 +21,7 @@ $("#file-upload").change(async function() { await treeService.reload(); - await treeService.activateNode(resp.noteId); + await treeService.activateNote(resp.noteId); }); export default { diff --git a/src/public/javascripts/services/frontend_script_api.js b/src/public/javascripts/services/frontend_script_api.js new file mode 100644 index 000000000..53ffb24e9 --- /dev/null +++ b/src/public/javascripts/services/frontend_script_api.js @@ -0,0 +1,186 @@ +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'; +import treeCache from './tree_cache.js'; + +/** + * @constructor + * @hideconstructor + */ +function FrontendScriptApi(startNote, currentNote, originEntity = null) { + const $pluginButtons = $("#plugin-buttons"); + + /** @property {object} note where script started executing */ + this.startNote = startNote; + /** @property {object} note where script is currently executing */ + this.currentNote = currentNote; + /** @property {object|null} entity whose event triggered this execution */ + this.originEntity = originEntity; + + /** + * Activates note in the tree and in the note detail. + * + * @method + * @param {string} notePath (or noteId) + * @returns {Promise} + */ + this.activateNote = treeService.activateNote; + + /** + * Activates newly created note. Compared to this.activateNote() also refreshes tree. + * + * @param {string} notePath (or noteId) + * @return {Promise} + */ + this.activateNewNote = async notePath => { + await treeService.reload(); + + await treeService.activateNote(notePath, true); + }; + + /** + * Adds new button the the plugin area. + * + * @param {object} options + */ + this.addButtonToToolbar = opts => { + const buttonId = "toolbar-button-" + opts.title.replace(/[^a-zA-Z0-9]/g, "-"); + + $("#" + buttonId).remove(); + + const icon = $("") + .addClass("ui-icon ui-icon-" + opts.icon); + + const button = $('