refactored note creation methods into a separate service

This commit is contained in:
zadam 2020-02-03 20:07:34 +01:00
parent 822a8509b3
commit 66204811cf
9 changed files with 138 additions and 110 deletions

View file

@ -103,6 +103,11 @@ class NoteShort {
}
}
/** @returns {string[]} */
getBranchIds() {
return Object.values(this.parentToBranch);
}
/** @returns {Promise<Branch[]>} */
async getBranches() {
const branchIds = Object.values(this.parentToBranch);

View file

@ -5,6 +5,7 @@ import contextMenuWidget from "./services/context_menu.js";
import treeChangesService from "./services/branches.js";
import utils from "./services/utils.js";
import appContext from "./services/app_context.js";
import noteCreateService from "./services/note_create.js";
window.glob.isDesktop = utils.isDesktop;
window.glob.isMobile = utils.isMobile;
@ -111,10 +112,14 @@ $detail.on("click", ".note-menu-button", async e => {
const parentNoteId = node.data.parentNoteId;
const isProtected = await treeService.getParentProtectedStatus(node);
treeService.createNote(node, parentNoteId, 'after', { isProtected: isProtected });
noteCreateService.createNote(parentNoteId, {
isProtected: isProtected,
target: 'after',
targetBranchId: node.data.branchId
});
}
else if (cmd === "insertChildNote") {
treeService.createNote(node, node.data.noteId, 'into');
noteCreateService.createNote(node.data.noteId);
}
else if (cmd === "delete") {
if (await treeChangesService.deleteNodes([node])) {

View file

@ -495,4 +495,26 @@ $(window).on('beforeunload', () => {
appContext.trigger('beforeUnload');
});
function isNotePathInAddress() {
const [notePath, tabId] = getHashValueFromAddress();
return notePath.startsWith("root")
// empty string is for empty/uninitialized tab
|| (notePath === '' && !!tabId);
}
function getHashValueFromAddress() {
const str = document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
return str.split("-");
}
$(window).on('hashchange', function() {
if (isNotePathInAddress()) {
const [notePath, tabId] = getHashValueFromAddress();
appContext.switchToTab(tabId, notePath);
}
});
export default appContext;

View file

@ -0,0 +1,89 @@
import hoistedNoteService from "./hoisted_note.js";
import appContext from "./app_context.js";
import utils from "./utils.js";
import protectedSessionHolder from "./protected_session_holder.js";
import server from "./server.js";
import ws from "./ws.js";
import treeCache from "./tree_cache.js";
import toastService from "./toast.js";
async function createNewTopLevelNote() {
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
await createNote(hoistedNoteId);
}
async function createNote(parentNoteId, options = {}) {
options = Object.assign({
activate: true,
target: 'into'
}, options);
// if isProtected isn't available (user didn't enter password yet), then note is created as unencrypted
// but this is quite weird since user doesn't see WHERE the note is being created so it shouldn't occur often
if (!options.isProtected || !protectedSessionHolder.isProtectedSessionAvailable()) {
options.isProtected = false;
}
if (appContext.getActiveTabNoteType() !== 'text') {
options.saveSelection = false;
}
if (options.saveSelection && utils.isCKEditorInitialized()) {
[options.title, options.content] = parseSelectedHtml(window.cutToNote.getSelectedHtml());
}
const newNoteName = options.title || "new note";
const {note, branch} = await server.post(`notes/${parentNoteId}/children?target=${options.target}&targetBranchId=${options.targetBranchId}`, {
title: newNoteName,
content: options.content || "",
isProtected: options.isProtected,
type: options.type
});
if (options.saveSelection && utils.isCKEditorInitialized()) {
// we remove the selection only after it was saved to server to make sure we don't lose anything
window.cutToNote.removeSelection();
}
if (options.activate) {
const activeTabContext = appContext.getActiveTabContext();
activeTabContext.setNote(note.noteId);
}
return {note, branch};
}
/* If first element is heading, parse it out and use it as a new heading. */
function parseSelectedHtml(selectedHtml) {
const dom = $.parseHTML(selectedHtml);
if (dom.length > 0 && dom[0].tagName && dom[0].tagName.match(/h[1-6]/i)) {
const title = $(dom[0]).text();
// remove the title from content (only first occurence)
const content = selectedHtml.replace(dom[0].outerHTML, "");
return [title, content];
}
else {
return [null, selectedHtml];
}
}
async function duplicateNote(noteId, parentNoteId) {
const {note} = await server.post(`notes/${noteId}/duplicate/${parentNoteId}`);
await ws.waitForMaxKnownSyncId();
await appContext.activateOrOpenNote(note.noteId);
const origNote = await treeCache.getNote(noteId);
toastService.showMessage(`Note "${origNote.title}" has been duplicated`);
}
export default {
createNote,
createNewTopLevelNote,
duplicateNote
};

View file

@ -133,85 +133,6 @@ async function getSomeNotePath(note) {
return path.reverse().join('/');
}
function isNotePathInAddress() {
const [notePath, tabId] = getHashValueFromAddress();
return notePath.startsWith("root")
// empty string is for empty/uninitialized tab
|| (notePath === '' && !!tabId);
}
function getHashValueFromAddress() {
const str = document.location.hash ? document.location.hash.substr(1) : ""; // strip initial #
return str.split("-");
}
async function createNewTopLevelNote() {
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
const rootNode = appContext.getMainNoteTree().getNodesByNoteId(hoistedNoteId)[0];
await createNote(rootNode, hoistedNoteId, "into");
}
async function createNote(node, parentNoteId, target, extraOptions = {}) {
utils.assertArguments(node, parentNoteId, target);
extraOptions.activate = extraOptions.activate === undefined ? true : !!extraOptions.activate;
// if isProtected isn't available (user didn't enter password yet), then note is created as unencrypted
// but this is quite weird since user doesn't see WHERE the note is being created so it shouldn't occur often
if (!extraOptions.isProtected || !protectedSessionHolder.isProtectedSessionAvailable()) {
extraOptions.isProtected = false;
}
if (appContext.getActiveTabNoteType() !== 'text') {
extraOptions.saveSelection = false;
}
if (extraOptions.saveSelection && utils.isCKEditorInitialized()) {
[extraOptions.title, extraOptions.content] = parseSelectedHtml(window.cutToNote.getSelectedHtml());
}
const newNoteName = extraOptions.title || "new note";
const {note, branch} = await server.post(`notes/${parentNoteId}/children?target=${target}&targetBranchId=${node.data.branchId}`, {
title: newNoteName,
content: extraOptions.content || "",
isProtected: extraOptions.isProtected,
type: extraOptions.type
});
if (extraOptions.saveSelection && utils.isCKEditorInitialized()) {
// we remove the selection only after it was saved to server to make sure we don't lose anything
window.cutToNote.removeSelection();
}
if (extraOptions.activate) {
const activeTabContext = appContext.getActiveTabContext();
activeTabContext.setNote(note.noteId);
}
return {note, branch};
}
/* If first element is heading, parse it out and use it as a new heading. */
function parseSelectedHtml(selectedHtml) {
const dom = $.parseHTML(selectedHtml);
if (dom.length > 0 && dom[0].tagName && dom[0].tagName.match(/h[1-6]/i)) {
const title = $(dom[0]).text();
// remove the title from content (only first occurence)
const content = selectedHtml.replace(dom[0].outerHTML, "");
return [title, content];
}
else {
return [null, selectedHtml];
}
}
async function sortAlphabetically(noteId) {
await server.put('notes/' + noteId + '/sort');
}
@ -228,25 +149,6 @@ ws.subscribeToMessages(message => {
}
});
$(window).on('hashchange', function() {
if (isNotePathInAddress()) {
const [notePath, tabId] = getHashValueFromAddress();
appContext.switchToTab(tabId, notePath);
}
});
async function duplicateNote(noteId, parentNoteId) {
const {note} = await server.post(`notes/${noteId}/duplicate/${parentNoteId}`);
await ws.waitForMaxKnownSyncId();
await appContext.activateOrOpenNote(note.noteId);
const origNote = await treeCache.getNote(noteId);
toastService.showMessage(`Note "${origNote.title}" has been duplicated`);
}
async function getParentProtectedStatus(node) {
return await hoistedNoteService.isRootNode(node) ? 0 : node.getParent().data.isProtected;
}
@ -361,12 +263,9 @@ async function getNotePathTitle(notePath) {
}
export default {
createNote,
sortAlphabetically,
resolveNotePath,
getSomeNotePath,
createNewTopLevelNote,
duplicateNote,
getRunPath,
getParentProtectedStatus,
getNotePath,

View file

@ -8,6 +8,7 @@ import hoistedNoteService from './hoisted_note.js';
import clipboard from './clipboard.js';
import protectedSessionHolder from "./protected_session_holder.js";
import appContext from "./app_context.js";
import noteCreateService from "./note_create.js";
class TreeContextMenu {
/**
@ -110,7 +111,9 @@ class TreeContextMenu {
const isProtected = await treeService.getParentProtectedStatus(this.node);
const type = cmd.split("_")[1];
treeService.createNote(this.node, parentNoteId, 'after', {
noteCreateService.createNote(parentNoteId, {
target: 'after',
targetBranchId: this.node.data.branchId,
type: type,
isProtected: isProtected
});
@ -118,7 +121,7 @@ class TreeContextMenu {
else if (cmd.startsWith("insertChildNote")) {
const type = cmd.split("_")[1];
treeService.createNote(this.node, this.node.data.noteId, 'into', {
noteCreateService.createNote(noteId, {
type: type,
isProtected: this.node.data.isProtected
});

View file

@ -12,6 +12,7 @@ import ws from "../services/ws.js";
import appContext from "../services/app_context.js";
import TabAwareWidget from "./tab_aware_widget.js";
import server from "../services/server.js";
import noteCreateService from "../services/note_create.js";
const TPL = `
<div class="tree">
@ -545,7 +546,9 @@ export default class NoteTreeWidget extends TabAwareWidget {
return;
}
await treeService.createNote(node, parentNoteId, 'after', {
await noteCreateService.createNote(parentNoteId, {
target: 'after',
targetBranchId: node.data.branchId,
isProtected: isProtected,
saveSelection: true
});
@ -555,7 +558,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
const node = this.getActiveNode();
if (node) {
await treeService.createNote(node, node.data.noteId, 'into', {
await noteCreateService.createNote(node.data.noteId, {
isProtected: node.data.isProtected,
saveSelection: false
});
@ -566,7 +569,7 @@ export default class NoteTreeWidget extends TabAwareWidget {
const node = this.getActiveNode();
if (node) {
await treeService.createNote(node, node.data.noteId, 'into', {
await noteCreateService.createNote(node.data.noteId, {
isProtected: node.data.isProtected,
saveSelection: true
});

View file

@ -3,6 +3,7 @@ import treeService from "../services/tree.js";
import treeCache from "../services/tree_cache.js";
import toastService from "../services/toast.js";
import appContext from "../services/app_context.js";
import noteCreateService from "../services/note_create.js";
const helpText = `
<strong>Search tips</strong> - also see <button class="btn btn-sm" type="button" data-help-page="Search">complete help on search</button>
@ -128,7 +129,7 @@ export default class SearchBoxWidget extends BasicWidget {
activeNode = activeNode.getParent();
}
await treeService.createNote(activeNode, activeNode.data.noteId, 'into', {
await noteCreateService.createNote(activeNode.data.noteId, {
type: "search",
mime: "application/json",
title: searchString,

View file

@ -485,11 +485,12 @@ eventService.subscribe([eventService.ENTITY_CHANGED, eventService.ENTITY_DELETED
delete childParentToBranchId[branch.noteId + '-' + branch.parentNoteId];
}
else {
// ... and then we create new records
if (branch.prefix) {
prefixes[branch.noteId + '-' + branch.parentNoteId] = branch.prefix;
}
childToParent[branch.noteId] = childToParent[branch.noteId] || [];
if (!childToParent[branch.noteId].includes(branch.parentNoteId)) {
childToParent[branch.noteId].push(branch.parentNoteId);
}