refactoring utils into module

This commit is contained in:
azivner 2018-03-24 23:37:55 -04:00
parent 0f6b00e1c8
commit c8e456cdb1
21 changed files with 361 additions and 340 deletions

View File

@ -3,8 +3,8 @@ function ScriptContext(startNote, allNotes) {
return { return {
modules: modules, modules: modules,
notes: toObject(allNotes, note => [note.noteId, note]), notes: utils.toObject(allNotes, note => [note.noteId, note]),
apis: toObject(allNotes, note => [note.noteId, ScriptApi(startNote, note)]), apis: utils.toObject(allNotes, note => [note.noteId, ScriptApi(startNote, note)]),
require: moduleNoteIds => { require: moduleNoteIds => {
return moduleName => { return moduleName => {
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId)); const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));

View File

@ -26,7 +26,7 @@ const contextMenu = (function() {
// just do nothing // just do nothing
} }
else { else {
throwError("Unrecognized clipboard mode=" + clipboardMode); utils.throwError("Unrecognized clipboard mode=" + clipboardMode);
} }
} }
@ -49,7 +49,7 @@ const contextMenu = (function() {
// just do nothing // just do nothing
} }
else { else {
throwError("Unrecognized clipboard mode=" + mode); utils.throwError("Unrecognized clipboard mode=" + mode);
} }
} }
@ -57,14 +57,14 @@ const contextMenu = (function() {
clipboardIds = nodes.map(node => node.data.noteId); clipboardIds = nodes.map(node => node.data.noteId);
clipboardMode = 'copy'; clipboardMode = 'copy';
showMessage("Note(s) have been copied into clipboard."); utils.showMessage("Note(s) have been copied into clipboard.");
} }
function cut(nodes) { function cut(nodes) {
clipboardIds = nodes.map(node => node.key); clipboardIds = nodes.map(node => node.key);
clipboardMode = 'cut'; clipboardMode = 'cut';
showMessage("Note(s) have been cut into clipboard."); utils.showMessage("Note(s) have been cut into clipboard.");
} }
const contextMenuSettings = { const contextMenuSettings = {

View File

@ -18,7 +18,7 @@ const eventLog = (function() {
$list.html(''); $list.html('');
for (const event of result) { for (const event of result) {
const dateTime = formatDateTime(parseDate(event.dateAdded)); const dateTime = utils.formatDateTime(utils.parseDate(event.dateAdded));
if (event.noteId) { if (event.noteId) {
const noteLink = link.createNoteLink(event.noteId).prop('outerHTML'); const noteLink = link.createNoteLink(event.noteId).prop('outerHTML');

View File

@ -17,7 +17,7 @@ const jumpToNote = (function() {
}); });
await $autoComplete.autocomplete({ await $autoComplete.autocomplete({
source: await stopWatch("building autocomplete", treeService.getAutocompleteItems), source: await utils.stopWatch("building autocomplete", treeService.getAutocompleteItems),
minLength: 0 minLength: 0
}); });
} }

View File

@ -91,7 +91,7 @@ const labelsDialog = (function() {
addLastEmptyRow(); addLastEmptyRow();
showMessage("Labels have been saved."); utils.showMessage("Labels have been saved.");
noteEditor.loadLabelList(); noteEditor.loadLabelList();
}; };

View File

@ -28,11 +28,11 @@ const noteHistory = (function() {
historyItems = await server.get('notes-history/' + noteId); historyItems = await server.get('notes-history/' + noteId);
for (const item of historyItems) { for (const item of historyItems) {
const dateModified = parseDate(item.dateModifiedFrom); const dateModified = utils.parseDate(item.dateModifiedFrom);
$list.append($('<option>', { $list.append($('<option>', {
value: item.noteRevisionId, value: item.noteRevisionId,
text: formatDateTime(dateModified) text: utils.formatDateTime(dateModified)
})); }));
} }

View File

@ -22,10 +22,10 @@ const recentChanges = (function() {
for (const [dateDay, dayChanges] of groupedByDate) { for (const [dateDay, dayChanges] of groupedByDate) {
const changesListEl = $('<ul>'); const changesListEl = $('<ul>');
const dayEl = $('<div>').append($('<b>').html(formatDate(dateDay))).append(changesListEl); const dayEl = $('<div>').append($('<b>').html(utils.formatDate(dateDay))).append(changesListEl);
for (const change of dayChanges) { for (const change of dayChanges) {
const formattedTime = formatTime(parseDate(change.dateModifiedTo)); const formattedTime = utils.formatTime(utils.parseDate(change.dateModifiedTo));
const revLink = $("<a>", { const revLink = $("<a>", {
href: 'javascript:', href: 'javascript:',
@ -58,7 +58,7 @@ const recentChanges = (function() {
const dayCache = {}; const dayCache = {};
for (const row of result) { for (const row of result) {
let dateDay = parseDate(row.dateModifiedTo); let dateDay = utils.parseDate(row.dateModifiedTo);
dateDay.setHours(0); dateDay.setHours(0);
dateDay.setMinutes(0); dateDay.setMinutes(0);
dateDay.setSeconds(0); dateDay.setSeconds(0);

View File

@ -36,7 +36,7 @@ const settings = (function() {
value: settingValue value: settingValue
}); });
showMessage("Settings change have been saved."); utils.showMessage("Settings change have been saved.");
} }
$showDialogButton.click(showDialog); $showDialogButton.click(showDialog);
@ -82,7 +82,7 @@ settings.addModule((function() {
protected_session.resetProtectedSession(); protected_session.resetProtectedSession();
} }
else { else {
showError(result.message); utils.showError(result.message);
} }
}); });
@ -166,27 +166,27 @@ settings.addModule((async function () {
$forceFullSyncButton.click(async () => { $forceFullSyncButton.click(async () => {
await server.post('sync/force-full-sync'); await server.post('sync/force-full-sync');
showMessage("Full sync triggered"); utils.showMessage("Full sync triggered");
}); });
$fillSyncRowsButton.click(async () => { $fillSyncRowsButton.click(async () => {
await server.post('sync/fill-sync-rows'); await server.post('sync/fill-sync-rows');
showMessage("Sync rows filled successfully"); utils.showMessage("Sync rows filled successfully");
}); });
$anonymizeButton.click(async () => { $anonymizeButton.click(async () => {
await server.post('anonymization/anonymize'); await server.post('anonymization/anonymize');
showMessage("Created anonymized database"); utils.showMessage("Created anonymized database");
}); });
$cleanupSoftDeletedButton.click(async () => { $cleanupSoftDeletedButton.click(async () => {
if (confirm("Do you really want to clean up soft-deleted items?")) { if (confirm("Do you really want to clean up soft-deleted items?")) {
await server.post('cleanup/cleanup-soft-deleted-items'); await server.post('cleanup/cleanup-soft-deleted-items');
showMessage("Soft deleted items have been cleaned up"); utils.showMessage("Soft deleted items have been cleaned up");
} }
}); });
@ -194,14 +194,14 @@ settings.addModule((async function () {
if (confirm("Do you really want to clean up unused images?")) { if (confirm("Do you really want to clean up unused images?")) {
await server.post('cleanup/cleanup-unused-images'); await server.post('cleanup/cleanup-unused-images');
showMessage("Unused images have been cleaned up"); utils.showMessage("Unused images have been cleaned up");
} }
}); });
$vacuumDatabaseButton.click(async () => { $vacuumDatabaseButton.click(async () => {
await server.post('cleanup/vacuum-database'); await server.post('cleanup/vacuum-database');
showMessage("Database has been vacuumed"); utils.showMessage("Database has been vacuumed");
}); });
return {}; return {};

View File

@ -24,7 +24,7 @@ const sqlConsole = (function() {
async function initEditor() { async function initEditor() {
if (!codeEditor) { if (!codeEditor) {
await requireLibrary(CODE_MIRROR); await utils.requireLibrary(utils.CODE_MIRROR);
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess"; CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
CodeMirror.keyMap.default["Tab"] = "indentMore"; CodeMirror.keyMap.default["Tab"] = "indentMore";
@ -60,11 +60,11 @@ const sqlConsole = (function() {
}); });
if (!result.success) { if (!result.success) {
showError(result.error); utils.showError(result.error);
return; return;
} }
else { else {
showMessage("Query was executed successfully."); utils.showMessage("Query was executed successfully.");
} }
const rows = result.rows; const rows = result.rows;

View File

@ -1,10 +1,10 @@
"use strict"; "use strict";
function exportSubTree(noteId) { function exportSubTree(noteId) {
const url = getHost() + "/api/export/" + noteId + "?protectedSessionId=" const url = utils.getHost() + "/api/export/" + noteId + "?protectedSessionId="
+ encodeURIComponent(protected_session.getProtectedSessionId()); + encodeURIComponent(protected_session.getProtectedSessionId());
download(url); utils.download(url);
} }
let importNoteId; let importNoteId;

View File

@ -14,7 +14,7 @@ $(document).bind('keydown', 'alt+m', e => {
// hide (toggle) everything except for the note content for distraction free writing // hide (toggle) everything except for the note content for distraction free writing
$(document).bind('keydown', 'alt+t', e => { $(document).bind('keydown', 'alt+t', e => {
const date = new Date(); const date = new Date();
const dateString = formatDateTime(date); const dateString = utils.formatDateTime(date);
link.addTextToEditor(dateString); link.addTextToEditor(dateString);
@ -22,19 +22,19 @@ $(document).bind('keydown', 'alt+t', e => {
}); });
$(document).bind('keydown', 'f5', () => { $(document).bind('keydown', 'f5', () => {
reloadApp(); utils.reloadApp();
return false; return false;
}); });
$(document).bind('keydown', 'ctrl+r', () => { $(document).bind('keydown', 'ctrl+r', () => {
reloadApp(); utils.reloadApp();
return false; return false;
}); });
$(document).bind('keydown', 'ctrl+shift+i', () => { $(document).bind('keydown', 'ctrl+shift+i', () => {
if (isElectron()) { if (utils.isElectron()) {
require('electron').remote.getCurrentWindow().toggleDevTools(); require('electron').remote.getCurrentWindow().toggleDevTools();
return false; return false;
@ -42,7 +42,7 @@ $(document).bind('keydown', 'ctrl+shift+i', () => {
}); });
$(document).bind('keydown', 'ctrl+f', () => { $(document).bind('keydown', 'ctrl+f', () => {
if (isElectron()) { if (utils.isElectron()) {
const searchInPage = require('electron-in-page-search').default; const searchInPage = require('electron-in-page-search').default;
const remote = require('electron').remote; const remote = require('electron').remote;
@ -73,7 +73,7 @@ $(document).bind('keydown', "ctrl+shift+down", () => {
}); });
$(document).bind('keydown', 'ctrl+-', () => { $(document).bind('keydown', 'ctrl+-', () => {
if (isElectron()) { if (utils.isElectron()) {
const webFrame = require('electron').webFrame; const webFrame = require('electron').webFrame;
if (webFrame.getZoomFactor() > 0.2) { if (webFrame.getZoomFactor() > 0.2) {
@ -85,7 +85,7 @@ $(document).bind('keydown', 'ctrl+-', () => {
}); });
$(document).bind('keydown', 'ctrl+=', () => { $(document).bind('keydown', 'ctrl+=', () => {
if (isElectron()) { if (utils.isElectron()) {
const webFrame = require('electron').webFrame; const webFrame = require('electron').webFrame;
webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.1); webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.1);
@ -198,17 +198,17 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
return false; return false;
}; };
$("#logout-button").toggle(!isElectron()); $("#logout-button").toggle(!utils.isElectron());
$(document).ready(() => { $(document).ready(() => {
server.get("script/startup").then(scriptBundles => { server.get("script/startup").then(scriptBundles => {
for (const bundle of scriptBundles) { for (const bundle of scriptBundles) {
executeBundle(bundle); utils.executeBundle(bundle);
} }
}); });
}); });
if (isElectron()) { if (utils.isElectron()) {
require('electron').ipcRenderer.on('create-day-sub-note', async function(event, parentNoteId) { require('electron').ipcRenderer.on('create-day-sub-note', async function(event, parentNoteId) {
// this might occur when day note had to be created // this might occur when day note had to be created
if (!await treeService.noteExists(parentNoteId)) { if (!await treeService.noteExists(parentNoteId)) {

View File

@ -4,7 +4,7 @@ const messaging = (function() {
const $changesToPushCount = $("#changes-to-push-count"); const $changesToPushCount = $("#changes-to-push-count");
function logError(message) { function logError(message) {
console.log(now(), message); // needs to be separate from .trace() console.log(utils.now(), message); // needs to be separate from .trace()
console.trace(); console.trace();
if (ws && ws.readyState === 1) { if (ws && ws.readyState === 1) {
@ -22,7 +22,7 @@ const messaging = (function() {
lastPingTs = new Date().getTime(); lastPingTs = new Date().getTime();
if (message.data.length > 0) { if (message.data.length > 0) {
console.log(now(), "Sync data: ", message.data); console.log(utils.now(), "Sync data: ", message.data);
lastSyncId = message.data[message.data.length - 1].id; lastSyncId = message.data[message.data.length - 1].id;
} }
@ -32,19 +32,19 @@ const messaging = (function() {
if (syncData.some(sync => sync.entityName === 'branches') if (syncData.some(sync => sync.entityName === 'branches')
|| syncData.some(sync => sync.entityName === 'notes')) { || syncData.some(sync => sync.entityName === 'notes')) {
console.log(now(), "Reloading tree because of background changes"); console.log(utils.now(), "Reloading tree because of background changes");
treeService.reload(); treeService.reload();
} }
if (syncData.some(sync => sync.entityName === 'notes' && sync.entityId === noteEditor.getCurrentNoteId())) { if (syncData.some(sync => sync.entityName === 'notes' && sync.entityId === noteEditor.getCurrentNoteId())) {
showMessage('Reloading note because of background changes'); utils.showMessage('Reloading note because of background changes');
noteEditor.reload(); noteEditor.reload();
} }
if (syncData.some(sync => sync.entityName === 'recent_notes')) { if (syncData.some(sync => sync.entityName === 'recent_notes')) {
console.log(now(), "Reloading recent notes because of background changes"); console.log(utils.now(), "Reloading recent notes because of background changes");
recentNotes.reload(); recentNotes.reload();
} }
@ -55,10 +55,10 @@ const messaging = (function() {
$changesToPushCount.html(message.changesToPushCount); $changesToPushCount.html(message.changesToPushCount);
} }
else if (message.type === 'sync-hash-check-failed') { else if (message.type === 'sync-hash-check-failed') {
showError("Sync check failed!", 60000); utils.utils.showError("Sync check failed!", 60000);
} }
else if (message.type === 'consistency-checks-failed') { else if (message.type === 'consistency-checks-failed') {
showError("Consistency checks failed! See logs for details.", 50 * 60000); utils.showError("Consistency checks failed! See logs for details.", 50 * 60000);
} }
} }
@ -67,7 +67,7 @@ const messaging = (function() {
// use wss for secure messaging // use wss for secure messaging
const ws = new WebSocket(protocol + "://" + location.host); const ws = new WebSocket(protocol + "://" + location.host);
ws.onopen = event => console.log(now(), "Connected to server with WebSocket"); ws.onopen = event => console.log(utils.now(), "Connected to server with WebSocket");
ws.onmessage = messageHandler; ws.onmessage = messageHandler;
ws.onclose = function(){ ws.onclose = function(){
// Try to reconnect in 5 seconds // Try to reconnect in 5 seconds
@ -100,7 +100,7 @@ const messaging = (function() {
await connectionBrokenNotification.close(); await connectionBrokenNotification.close();
connectionBrokenNotification = null; connectionBrokenNotification = null;
showMessage("Re-connected to server"); utils.showMessage("Re-connected to server");
} }
ws.send(JSON.stringify({ ws.send(JSON.stringify({

View File

@ -103,7 +103,7 @@ const noteEditor = (function() {
// nothing // nothing
} }
else { else {
throwError("Unrecognized type: " + note.detail.type); utils.throwError("Unrecognized type: " + note.detail.type);
} }
const title = $noteTitle.val(); const title = $noteTitle.val();
@ -118,7 +118,7 @@ const noteEditor = (function() {
isNoteChanged = false; isNoteChanged = false;
showMessage("Saved!"); utils.showMessage("Saved!");
} }
function setNoteBackgroundIfProtected(note) { function setNoteBackgroundIfProtected(note) {
@ -138,7 +138,7 @@ const noteEditor = (function() {
async function setContent(content) { async function setContent(content) {
if (currentNote.detail.type === 'text') { if (currentNote.detail.type === 'text') {
if (!editor) { if (!editor) {
await requireLibrary(CKEDITOR); await utils.requireLibrary(utils.CKEDITOR);
editor = await BalloonEditor.create($noteDetail[0], {}); editor = await BalloonEditor.create($noteDetail[0], {});
@ -152,7 +152,7 @@ const noteEditor = (function() {
} }
else if (currentNote.detail.type === 'code') { else if (currentNote.detail.type === 'code') {
if (!codeEditor) { if (!codeEditor) {
await requireLibrary(CODE_MIRROR); await utils.requireLibrary(utils.CODE_MIRROR);
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess"; CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
CodeMirror.keyMap.default["Tab"] = "indentMore"; CodeMirror.keyMap.default["Tab"] = "indentMore";
@ -248,7 +248,7 @@ const noteEditor = (function() {
$noteDetailRender.html(bundle.html); $noteDetailRender.html(bundle.html);
executeBundle(bundle); utils.executeBundle(bundle);
} }
else if (currentNote.detail.type === 'file') { else if (currentNote.detail.type === 'file') {
$noteDetailAttachment.show(); $noteDetailAttachment.show();
@ -281,7 +281,7 @@ const noteEditor = (function() {
if (labels.length > 0) { if (labels.length > 0) {
for (const attr of labels) { for (const attr of labels) {
$labelListInner.append(formatLabel(attr) + " "); $labelListInner.append(utils.formatLabel(attr) + " ");
} }
$labelList.show(); $labelList.show();
@ -312,7 +312,7 @@ const noteEditor = (function() {
// do nothing // do nothing
} }
else { else {
throwError('Unrecognized type: ' + note.detail.type); utils.throwError('Unrecognized type: ' + note.detail.type);
} }
} }
@ -330,21 +330,21 @@ const noteEditor = (function() {
if (currentNote.detail.mime.endsWith("env=frontend")) { if (currentNote.detail.mime.endsWith("env=frontend")) {
const bundle = await server.get('script/bundle/' + getCurrentNoteId()); const bundle = await server.get('script/bundle/' + getCurrentNoteId());
executeBundle(bundle); utils.executeBundle(bundle);
} }
if (currentNote.detail.mime.endsWith("env=backend")) { if (currentNote.detail.mime.endsWith("env=backend")) {
await server.post('script/run/' + getCurrentNoteId()); await server.post('script/run/' + getCurrentNoteId());
} }
showMessage("Note executed"); utils.showMessage("Note executed");
} }
} }
$attachmentDownload.click(() => download(getAttachmentUrl())); $attachmentDownload.click(() => utils.download(getAttachmentUrl()));
$attachmentOpen.click(() => { $attachmentOpen.click(() => {
if (isElectron()) { if (utils.isElectron()) {
const open = require("open"); const open = require("open");
open(getAttachmentUrl()); open(getAttachmentUrl());
@ -356,7 +356,7 @@ const noteEditor = (function() {
function getAttachmentUrl() { function getAttachmentUrl() {
// electron needs absolute URL so we extract current host, port, protocol // electron needs absolute URL so we extract current host, port, protocol
return getHost() + "/api/attachments/download/" + getCurrentNoteId() return utils.getHost() + "/api/attachments/download/" + getCurrentNoteId()
+ "?protectedSessionId=" + encodeURIComponent(protected_session.getProtectedSessionId()); + "?protectedSessionId=" + encodeURIComponent(protected_session.getProtectedSessionId());
} }

View File

@ -135,38 +135,22 @@ const treeService = (function() {
const note = noteMap[noteId]; const note = noteMap[noteId];
if (!note) { if (!note) {
throwError("Can't find title for noteId='" + noteId + "'"); utils.throwError("Can't find title for noteId='" + noteId + "'");
} }
return note; return note;
} }
function getBranchId(parentNoteId, childNoteId) {
assertArguments(parentNoteId, childNoteId);
const key = parentNoteId + "-" + childNoteId;
// this can return undefined and client code should deal with it somehow
return parentChildToBranchId[key];
}
function getNoteTitle(noteId, parentNoteId = null) { function getNoteTitle(noteId, parentNoteId = null) {
assertArguments(noteId); utils.assertArguments(noteId);
let title = treeCache.getNote(noteId).title; let title = treeCache.getNote(noteId).title;
if (parentNoteId !== null) { if (parentNoteId !== null) {
const branchId = getBranchId(parentNoteId, noteId); const branch = treeCache.getBranch(noteId, parentNoteId);
if (branchId) { if (branch && branch.prefix) {
const branch = branchMap[branchId]; title = branch.prefix + ' - ' + title;
if (branch.prefix) {
title = branch.prefix + ' - ' + title;
}
} }
} }
@ -185,7 +169,7 @@ const treeService = (function() {
} }
function getNodesByBranchId(branchId) { function getNodesByBranchId(branchId) {
assertArguments(branchId); utils.assertArguments(branchId);
const branch = branchMap[branchId]; const branch = branchMap[branchId];
@ -193,14 +177,14 @@ const treeService = (function() {
} }
function getNodesByNoteId(noteId) { function getNodesByNoteId(noteId) {
assertArguments(noteId); utils.assertArguments(noteId);
const list = getTree().getNodesByRef(noteId); const list = getTree().getNodesByRef(noteId);
return list ? list : []; // if no nodes with this refKey are found, fancy tree returns null return list ? list : []; // if no nodes with this refKey are found, fancy tree returns null
} }
function setPrefix(branchId, prefix) { function setPrefix(branchId, prefix) {
assertArguments(branchId); utils.assertArguments(branchId);
branchMap[branchId].prefix = prefix; branchMap[branchId].prefix = prefix;
@ -215,11 +199,11 @@ const treeService = (function() {
const title = (prefix ? (prefix + " - ") : "") + noteTitle; const title = (prefix ? (prefix + " - ") : "") + noteTitle;
node.setTitle(escapeHtml(title)); node.setTitle(utils.escapeHtml(title));
} }
function removeParentChildRelation(parentNoteId, childNoteId) { function removeParentChildRelation(parentNoteId, childNoteId) {
assertArguments(parentNoteId, childNoteId); utils.assertArguments(parentNoteId, childNoteId);
const parentNote = noteMap[parentNoteId]; const parentNote = noteMap[parentNoteId];
const childNote = noteMap[childNoteId]; const childNote = noteMap[childNoteId];
@ -228,7 +212,7 @@ const treeService = (function() {
} }
function setParentChildRelation(branchId, parentNoteId, childNoteId) { function setParentChildRelation(branchId, parentNoteId, childNoteId) {
assertArguments(branchId, parentNoteId, childNoteId); utils.assertArguments(branchId, parentNoteId, childNoteId);
const parentNote = noteMap[parentNoteId]; const parentNote = noteMap[parentNoteId];
const childNote = noteMap[childNoteId]; const childNote = noteMap[childNoteId];
@ -237,7 +221,7 @@ const treeService = (function() {
} }
async function prepareBranch(noteRows, branchRows) { async function prepareBranch(noteRows, branchRows) {
assertArguments(noteRows); utils.assertArguments(noteRows);
treeCache = new TreeCache(noteRows, branchRows); treeCache = new TreeCache(noteRows, branchRows);
@ -245,7 +229,7 @@ const treeService = (function() {
} }
async function getExtraClasses(note) { async function getExtraClasses(note) {
assertArguments(note); utils.assertArguments(note);
const extraClasses = []; const extraClasses = [];
@ -263,7 +247,7 @@ const treeService = (function() {
} }
async function prepareBranchInner(parentNote) { async function prepareBranchInner(parentNote) {
assertArguments(parentNote); utils.assertArguments(parentNote);
const childBranches = await parentNote.getChildBranches(); const childBranches = await parentNote.getChildBranches();
@ -283,7 +267,7 @@ const treeService = (function() {
parentNoteId: branch.parentNoteId, parentNoteId: branch.parentNoteId,
branchId: branch.branchId, branchId: branch.branchId,
isProtected: note.isProtected, isProtected: note.isProtected,
title: escapeHtml(title), title: utils.escapeHtml(title),
extraClasses: getExtraClasses(note), extraClasses: getExtraClasses(note),
refKey: note.noteId, refKey: note.noteId,
expanded: note.type !== 'search' && branch.isExpanded expanded: note.type !== 'search' && branch.isExpanded
@ -309,7 +293,7 @@ const treeService = (function() {
} }
async function expandToNote(notePath, expandOpts) { async function expandToNote(notePath, expandOpts) {
assertArguments(notePath); utils.assertArguments(notePath);
const runPath = await getRunPath(notePath); const runPath = await getRunPath(notePath);
@ -332,7 +316,7 @@ const treeService = (function() {
} }
async function activateNode(notePath) { async function activateNode(notePath) {
assertArguments(notePath); utils.assertArguments(notePath);
const node = await expandToNote(notePath); const node = await expandToNote(notePath);
@ -346,7 +330,7 @@ const treeService = (function() {
* path change) or other corruption, in that case this will try to get some other valid path to the correct note. * path change) or other corruption, in that case this will try to get some other valid path to the correct note.
*/ */
async function getRunPath(notePath) { async function getRunPath(notePath) {
assertArguments(notePath); utils.assertArguments(notePath);
const path = notePath.split("/").reverse(); const path = notePath.split("/").reverse();
path.push('root'); path.push('root');
@ -372,10 +356,10 @@ const treeService = (function() {
} }
if (!parents.some(p => p.noteId === parentNoteId)) { if (!parents.some(p => p.noteId === parentNoteId)) {
console.log(now(), "Did not find parent " + parentNoteId + " for child " + childNoteId); console.log(utils.now(), "Did not find parent " + parentNoteId + " for child " + childNoteId);
if (parents.length > 0) { if (parents.length > 0) {
console.log(now(), "Available parents:", parents); console.log(utils.now(), "Available parents:", parents);
const someNotePath = await getSomeNotePath(parents[0]); const someNotePath = await getSomeNotePath(parents[0]);
@ -409,13 +393,13 @@ const treeService = (function() {
} }
async function showParentList(noteId, node) { async function showParentList(noteId, node) {
assertArguments(noteId, node); utils.assertArguments(noteId, node);
const note = treeCache.getNote(noteId); const note = treeCache.getNote(noteId);
const parents = await note.getParentNotes(); const parents = await note.getParentNotes();
if (!parents.length) { if (!parents.length) {
throwError("Can't find parents for noteId=" + noteId); utils.throwError("Can't find parents for noteId=" + noteId);
} }
if (parents.length <= 1) { if (parents.length <= 1) {
@ -446,7 +430,7 @@ const treeService = (function() {
} }
function getNotePathTitle(notePath) { function getNotePathTitle(notePath) {
assertArguments(notePath); utils.assertArguments(notePath);
const titlePath = []; const titlePath = [];
@ -462,7 +446,7 @@ const treeService = (function() {
} }
async function getSomeNotePath(note) { async function getSomeNotePath(note) {
assertArguments(note); utils.assertArguments(note);
const path = []; const path = [];
@ -474,7 +458,7 @@ const treeService = (function() {
const parents = await cur.getParentNotes(); const parents = await cur.getParentNotes();
if (!parents.length) { if (!parents.length) {
throwError("Can't find parents for " + cur); utils.throwError("Can't find parents for " + cur);
} }
cur = parents[0]; cur = parents[0];
@ -484,7 +468,7 @@ const treeService = (function() {
} }
async function setExpandedToServer(branchId, isExpanded) { async function setExpandedToServer(branchId, isExpanded) {
assertArguments(branchId); utils.assertArguments(branchId);
const expandedNum = isExpanded ? 1 : 0; const expandedNum = isExpanded ? 1 : 0;
@ -492,7 +476,7 @@ const treeService = (function() {
} }
function setCurrentNotePathToHash(node) { function setCurrentNotePathToHash(node) {
assertArguments(node); utils.assertArguments(node);
const currentNotePath = treeUtils.getNotePath(node); const currentNotePath = treeUtils.getNotePath(node);
const currentBranchId = node.data.branchId; const currentBranchId = node.data.branchId;
@ -519,7 +503,7 @@ const treeService = (function() {
} }
function initFancyTree(branch) { function initFancyTree(branch) {
assertArguments(branch); utils.assertArguments(branch);
const keybindings = { const keybindings = {
"del": node => { "del": node => {
@ -621,7 +605,7 @@ const treeService = (function() {
return false; return false;
}, },
"backspace": node => { "backspace": node => {
if (!isTopLevelNode(node)) { if (!utils.isTopLevelNode(node)) {
node.getParent().setActive().then(() => clearSelectedNodes()); node.getParent().setActive().then(() => clearSelectedNodes());
} }
}, },
@ -748,7 +732,7 @@ const treeService = (function() {
const noteIds = await server.get('search/' + encodeURIComponent(json.searchString)); const noteIds = await server.get('search/' + encodeURIComponent(json.searchString));
for (const noteId of noteIds) { for (const noteId of noteIds) {
const branchId = "virt" + randomString(10); const branchId = "virt" + utils.randomString(10);
branchMap[branchId] = { branchMap[branchId] = {
branchId: branchId, branchId: branchId,
@ -874,7 +858,7 @@ const treeService = (function() {
} }
function setNoteTitle(noteId, title) { function setNoteTitle(noteId, title) {
assertArguments(noteId); utils.assertArguments(noteId);
getNote(noteId).title = title; getNote(noteId).title = title;
@ -888,7 +872,7 @@ const treeService = (function() {
} }
async function createNote(node, parentNoteId, target, isProtected) { async function createNote(node, parentNoteId, target, isProtected) {
assertArguments(node, parentNoteId, target); utils.assertArguments(node, parentNoteId, target);
// if isProtected isn't available (user didn't enter password yet), then note is created as unencrypted // 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 // but this is quite weird since user doesn't see WHERE the note is being created so it shouldn't occur often
@ -946,12 +930,12 @@ const treeService = (function() {
node.renderTitle(); node.renderTitle();
} }
else { else {
throwError("Unrecognized target: " + target); utils.throwError("Unrecognized target: " + target);
} }
clearSelectedNodes(); // to unmark previously active node clearSelectedNodes(); // to unmark previously active node
showMessage("Created!"); utils.showMessage("Created!");
} }
async function sortAlphabetically(noteId) { async function sortAlphabetically(noteId) {
@ -1010,7 +994,7 @@ const treeService = (function() {
} }
}); });
if (isElectron()) { if (utils.isElectron()) {
$(document).bind('keydown', 'alt+left', e => { $(document).bind('keydown', 'alt+left', e => {
window.history.back(); window.history.back();

View File

@ -73,7 +73,7 @@ const noteType = (function() {
// ignore and do nothing, "type" will be hidden since it's not possible to switch to and from search // ignore and do nothing, "type" will be hidden since it's not possible to switch to and from search
} }
else { else {
throwError('Unrecognized type: ' + type); utils.throwError('Unrecognized type: ' + type);
} }
}; };

View File

@ -56,7 +56,7 @@ const protected_session = (function() {
const response = await enterProtectedSession(password); const response = await enterProtectedSession(password);
if (!response.success) { if (!response.success) {
showError("Wrong password."); utils.showError("Wrong password.");
return; return;
} }
@ -103,7 +103,7 @@ const protected_session = (function() {
// most secure solution - guarantees nothing remained in memory // most secure solution - guarantees nothing remained in memory
// since this expires because user doesn't use the app, it shouldn't be disruptive // since this expires because user doesn't use the app, it shouldn't be disruptive
reloadApp(); utils.reloadApp();
} }
function isProtectedSessionAvailable() { function isProtectedSessionAvailable() {
@ -153,7 +153,7 @@ const protected_session = (function() {
await server.put('notes/' + noteId + "/protect-sub-tree/" + (protect ? 1 : 0)); await server.put('notes/' + noteId + "/protect-sub-tree/" + (protect ? 1 : 0));
showMessage("Request to un/protect sub tree has finished successfully"); utils.showMessage("Request to un/protect sub tree has finished successfully");
treeService.reload(); treeService.reload();
noteEditor.reload(); noteEditor.reload();

View File

@ -35,14 +35,14 @@ const server = (function() {
const reqResolves = {}; const reqResolves = {};
async function call(method, url, data) { async function call(method, url, data) {
if (isElectron()) { if (utils.isElectron()) {
const ipc = require('electron').ipcRenderer; const ipc = require('electron').ipcRenderer;
const requestId = i++; const requestId = i++;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
reqResolves[requestId] = resolve; reqResolves[requestId] = resolve;
console.log(now(), "Request #" + requestId + " to " + method + " " + url); console.log(utils.now(), "Request #" + requestId + " to " + method + " " + url);
ipc.send('server-request', { ipc.send('server-request', {
requestId: requestId, requestId: requestId,
@ -58,11 +58,11 @@ const server = (function() {
} }
} }
if (isElectron()) { if (utils.isElectron()) {
const ipc = require('electron').ipcRenderer; const ipc = require('electron').ipcRenderer;
ipc.on('server-response', (event, arg) => { ipc.on('server-response', (event, arg) => {
console.log(now(), "Response #" + arg.requestId + ": " + arg.statusCode); console.log(utils.now(), "Response #" + arg.requestId + ": " + arg.statusCode);
reqResolves[arg.requestId](arg.body); reqResolves[arg.requestId](arg.body);
@ -84,8 +84,8 @@ const server = (function() {
return await $.ajax(options).catch(e => { return await $.ajax(options).catch(e => {
const message = "Error when calling " + method + " " + url + ": " + e.status + " - " + e.statusText; const message = "Error when calling " + method + " " + url + ": " + e.status + " - " + e.statusText;
showError(message); utils.showError(message);
throwError(message); utils.throwError(message);
}); });
} }

View File

@ -4,14 +4,14 @@ async function syncNow() {
const result = await server.post('sync/now'); const result = await server.post('sync/now');
if (result.success) { if (result.success) {
showMessage("Sync finished successfully."); utils.showMessage("Sync finished successfully.");
} }
else { else {
if (result.message.length > 50) { if (result.message.length > 50) {
result.message = result.message.substr(0, 50); result.message = result.message.substr(0, 50);
} }
showError("Sync failed: " + result.message); utils.showError("Sync failed: " + result.message);
} }
} }
@ -20,5 +20,5 @@ $("#sync-now-button").click(syncNow);
async function forceNoteSync(noteId) { async function forceNoteSync(noteId) {
const result = await server.post('sync/force-note-sync/' + noteId); const result = await server.post('sync/force-note-sync/' + noteId);
showMessage("Note added to sync queue."); utils.showMessage("Note added to sync queue.");
} }

View File

@ -72,7 +72,7 @@ const treeChanges = (function() {
next = nodes[0].getPrevSibling(); next = nodes[0].getPrevSibling();
} }
if (!next && !isTopLevelNode(nodes[0])) { if (!next && !utils.isTopLevelNode(nodes[0])) {
next = nodes[0].getParent(); next = nodes[0].getParent();
} }
@ -85,11 +85,11 @@ const treeChanges = (function() {
treeService.reload(); treeService.reload();
showMessage("Note(s) has been deleted."); utils.showMessage("Note(s) has been deleted.");
} }
async function moveNodeUpInHierarchy(node) { async function moveNodeUpInHierarchy(node) {
if (isTopLevelNode(node)) { if (utils.isTopLevelNode(node)) {
return; return;
} }
@ -100,7 +100,7 @@ const treeChanges = (function() {
return; return;
} }
if (!isTopLevelNode(node) && node.getParent().getChildren().length <= 1) { if (!utils.isTopLevelNode(node) && node.getParent().getChildren().length <= 1) {
node.getParent().folder = false; node.getParent().folder = false;
node.getParent().renderTitle(); node.getParent().renderTitle();
} }
@ -109,13 +109,13 @@ const treeChanges = (function() {
} }
function changeNode(node, func) { function changeNode(node, func) {
assertArguments(node.data.parentNoteId, node.data.noteId); utils.assertArguments(node.data.parentNoteId, node.data.noteId);
treeService.removeParentChildRelation(node.data.parentNoteId, node.data.noteId); treeService.removeParentChildRelation(node.data.parentNoteId, node.data.noteId);
func(node); func(node);
node.data.parentNoteId = isTopLevelNode(node) ? 'root' : node.getParent().data.noteId; node.data.parentNoteId = utils.isTopLevelNode(node) ? 'root' : node.getParent().data.noteId;
treeService.setParentChildRelation(node.data.branchId, node.data.parentNoteId, node.data.noteId); treeService.setParentChildRelation(node.data.branchId, node.data.parentNoteId, node.data.noteId);

View File

@ -4,7 +4,7 @@ const treeUtils = (function() {
const $tree = $("#tree"); const $tree = $("#tree");
function getParentProtectedStatus(node) { function getParentProtectedStatus(node) {
return isTopLevelNode(node) ? 0 : node.getParent().data.isProtected; return utils.isTopLevelNode(node) ? 0 : node.getParent().data.isProtected;
} }
function getNodeByKey(key) { function getNodeByKey(key) {
@ -20,7 +20,7 @@ const treeUtils = (function() {
function getNotePath(node) { function getNotePath(node) {
const path = []; const path = [];
while (node && !isRootNode(node)) { while (node && !utils.isRootNode(node)) {
if (node.data.noteId) { if (node.data.noteId) {
path.push(node.data.noteId); path.push(node.data.noteId);
} }

View File

@ -1,233 +1,270 @@
"use strict"; "use strict";
function reloadApp() { const utils = (function() {
window.location.reload(true); function reloadApp() {
} window.location.reload(true);
function showMessage(message) {
console.log(now(), "message: ", message);
$.notify({
// options
message: message
},{
// settings
type: 'success',
delay: 3000
});
}
function showError(message, delay = 10000) {
console.log(now(), "error: ", message);
$.notify({
// options
message: message
},{
// settings
type: 'danger',
delay: delay
});
}
function throwError(message) {
messaging.logError(message);
throw new Error(message);
}
function parseDate(str) {
try {
return new Date(Date.parse(str));
} }
catch (e) {
throw new Error("Can't parse date from " + str + ": " + e.stack); function showMessage(message) {
console.log(now(), "message: ", message);
$.notify({
// options
message: message
}, {
// settings
type: 'success',
delay: 3000
});
} }
}
function padNum(num) { function showError(message, delay = 10000) {
return (num <= 9 ? "0" : "") + num; console.log(now(), "error: ", message);
}
function formatTime(date) { $.notify({
return padNum(date.getHours()) + ":" + padNum(date.getMinutes()); // options
} message: message
}, {
// settings
type: 'danger',
delay: delay
});
}
function formatTimeWithSeconds(date) { function throwError(message) {
return padNum(date.getHours()) + ":" + padNum(date.getMinutes()) + ":" + padNum(date.getSeconds()); messaging.logError(message);
}
function formatDate(date) { throw new Error(message);
return padNum(date.getDate()) + ". " + padNum(date.getMonth() + 1) + ". " + date.getFullYear(); }
}
function formatDateISO(date) { function parseDate(str) {
return date.getFullYear() + "-" + padNum(date.getMonth() + 1) + "-" + padNum(date.getDate()); try {
} return new Date(Date.parse(str));
}
function formatDateTime(date) { catch (e) {
return formatDate(date) + " " + formatTime(date); throw new Error("Can't parse date from " + str + ": " + e.stack);
}
function now() {
return formatTimeWithSeconds(new Date());
}
function isElectron() {
return window && window.process && window.process.type;
}
function assertArguments() {
for (const i in arguments) {
if (!arguments[i]) {
throwError(`Argument idx#${i} should not be falsy: ${arguments[i]}`);
} }
} }
}
function assert(expr, message) { function padNum(num) {
if (!expr) { return (num <= 9 ? "0" : "") + num;
throwError(message);
}
}
function isTopLevelNode(node) {
return isRootNode(node.getParent());
}
function isRootNode(node) {
return node.key === "root_1";
}
function escapeHtml(str) {
return $('<div/>').text(str).html();
}
async function stopWatch(what, func) {
const start = new Date();
const ret = await func();
const tookMs = new Date().getTime() - start.getTime();
console.log(`${what} took ${tookMs}ms`);
return ret;
}
async function executeBundle(bundle) {
const apiContext = ScriptContext(bundle.note, bundle.allNotes);
return await (function() { return eval(`const apiContext = this; (async function() { ${bundle.script}\r\n})()`); }.call(apiContext));
}
function formatValueWithWhitespace(val) {
return /[^\w_-]/.test(val) ? '"' + val + '"' : val;
}
function formatLabel(attr) {
let str = "@" + formatValueWithWhitespace(attr.name);
if (attr.value !== "") {
str += "=" + formatValueWithWhitespace(attr.value);
} }
return str; function formatTime(date) {
} return padNum(date.getHours()) + ":" + padNum(date.getMinutes());
const CKEDITOR = { "js": ["libraries/ckeditor/ckeditor.js"] };
const CODE_MIRROR = {
js: [
"libraries/codemirror/codemirror.js",
"libraries/codemirror/addon/mode/loadmode.js",
"libraries/codemirror/addon/fold/xml-fold.js",
"libraries/codemirror/addon/edit/matchbrackets.js",
"libraries/codemirror/addon/edit/matchtags.js",
"libraries/codemirror/addon/search/match-highlighter.js",
"libraries/codemirror/mode/meta.js",
"libraries/codemirror/addon/lint/lint.js",
"libraries/codemirror/addon/lint/eslint.js"
],
css: [
"libraries/codemirror/codemirror.css",
"libraries/codemirror/addon/lint/lint.css"
]
};
const ESLINT = { js: [ "libraries/eslint.js" ] };
async function requireLibrary(library) {
if (library.css) {
library.css.map(cssUrl => requireCss(cssUrl));
} }
if (library.js) { function formatTimeWithSeconds(date) {
for (const scriptUrl of library.js) { return padNum(date.getHours()) + ":" + padNum(date.getMinutes()) + ":" + padNum(date.getSeconds());
await requireScript(scriptUrl); }
function formatDate(date) {
return padNum(date.getDate()) + ". " + padNum(date.getMonth() + 1) + ". " + date.getFullYear();
}
function formatDateISO(date) {
return date.getFullYear() + "-" + padNum(date.getMonth() + 1) + "-" + padNum(date.getDate());
}
function formatDateTime(date) {
return formatDate(date) + " " + formatTime(date);
}
function now() {
return formatTimeWithSeconds(new Date());
}
function isElectron() {
return window && window.process && window.process.type;
}
function assertArguments() {
for (const i in arguments) {
if (!arguments[i]) {
throwError(`Argument idx#${i} should not be falsy: ${arguments[i]}`);
}
} }
} }
}
const dynamicallyLoadedScripts = []; function assert(expr, message) {
if (!expr) {
async function requireScript(url) { throwError(message);
if (!dynamicallyLoadedScripts.includes(url)) { }
dynamicallyLoadedScripts.push(url);
return await $.ajax({
url: url,
dataType: "script",
cache: true
})
}
}
async function requireCss(url) {
const css = Array
.from(document.querySelectorAll('link'))
.map(scr => scr.href);
if (!css.includes(url)) {
$('head').append($('<link rel="stylesheet" type="text/css" />').attr('href', url));
}
}
function getHost() {
const url = new URL(window.location.href);
return url.protocol + "//" + url.hostname + ":" + url.port;
}
function download(url) {
if (isElectron()) {
const remote = require('electron').remote;
remote.getCurrentWebContents().downloadURL(url);
}
else {
window.location.href = url;
}
}
function toObject(array, fn) {
const obj = {};
for (const item of array) {
const ret = fn(item);
obj[ret[0]] = ret[1];
} }
return obj; function isTopLevelNode(node) {
} return isRootNode(node.getParent());
function randomString(len) {
let text = "";
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < len; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
} }
return text; function isRootNode(node) {
} return node.key === "root_1";
}
function escapeHtml(str) {
return $('<div/>').text(str).html();
}
async function stopWatch(what, func) {
const start = new Date();
const ret = await func();
const tookMs = new Date().getTime() - start.getTime();
console.log(`${what} took ${tookMs}ms`);
return ret;
}
async function executeBundle(bundle) {
const apiContext = ScriptContext(bundle.note, bundle.allNotes);
return await (function () {
return eval(`const apiContext = this; (async function() { ${bundle.script}\r\n})()`);
}.call(apiContext));
}
function formatValueWithWhitespace(val) {
return /[^\w_-]/.test(val) ? '"' + val + '"' : val;
}
function formatLabel(attr) {
let str = "@" + formatValueWithWhitespace(attr.name);
if (attr.value !== "") {
str += "=" + formatValueWithWhitespace(attr.value);
}
return str;
}
const CKEDITOR = {"js": ["libraries/ckeditor/ckeditor.js"]};
const CODE_MIRROR = {
js: [
"libraries/codemirror/codemirror.js",
"libraries/codemirror/addon/mode/loadmode.js",
"libraries/codemirror/addon/fold/xml-fold.js",
"libraries/codemirror/addon/edit/matchbrackets.js",
"libraries/codemirror/addon/edit/matchtags.js",
"libraries/codemirror/addon/search/match-highlighter.js",
"libraries/codemirror/mode/meta.js",
"libraries/codemirror/addon/lint/lint.js",
"libraries/codemirror/addon/lint/eslint.js"
],
css: [
"libraries/codemirror/codemirror.css",
"libraries/codemirror/addon/lint/lint.css"
]
};
const ESLINT = {js: ["libraries/eslint.js"]};
async function requireLibrary(library) {
if (library.css) {
library.css.map(cssUrl => requireCss(cssUrl));
}
if (library.js) {
for (const scriptUrl of library.js) {
await requireScript(scriptUrl);
}
}
}
const dynamicallyLoadedScripts = [];
async function requireScript(url) {
if (!dynamicallyLoadedScripts.includes(url)) {
dynamicallyLoadedScripts.push(url);
return await $.ajax({
url: url,
dataType: "script",
cache: true
})
}
}
async function requireCss(url) {
const css = Array
.from(document.querySelectorAll('link'))
.map(scr => scr.href);
if (!css.includes(url)) {
$('head').append($('<link rel="stylesheet" type="text/css" />').attr('href', url));
}
}
function getHost() {
const url = new URL(window.location.href);
return url.protocol + "//" + url.hostname + ":" + url.port;
}
function download(url) {
if (isElectron()) {
const remote = require('electron').remote;
remote.getCurrentWebContents().downloadURL(url);
}
else {
window.location.href = url;
}
}
function toObject(array, fn) {
const obj = {};
for (const item of array) {
const ret = fn(item);
obj[ret[0]] = ret[1];
}
return obj;
}
function randomString(len) {
let text = "";
const possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (let i = 0; i < len; i++) {
text += possible.charAt(Math.floor(Math.random() * possible.length));
}
return text;
}
return {
reloadApp,
showMessage,
showError,
throwError,
parseDate,
padNum,
formatTime,
formatTimeWithSeconds,
formatDate,
formatDateISO,
formatDateTime,
now,
isElectron,
assertArguments,
assert,
isTopLevelNode,
isRootNode,
escapeHtml,
stopWatch,
executeBundle,
formatValueWithWhitespace,
formatLabel,
requireLibrary,
CKEDITOR,
CODE_MIRROR,
ESLINT,
getHost,
download,
toObject,
randomString
};
})();