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 {
modules: modules,
notes: toObject(allNotes, note => [note.noteId, note]),
apis: toObject(allNotes, note => [note.noteId, ScriptApi(startNote, note)]),
notes: utils.toObject(allNotes, note => [note.noteId, note]),
apis: utils.toObject(allNotes, note => [note.noteId, ScriptApi(startNote, note)]),
require: moduleNoteIds => {
return moduleName => {
const candidates = allNotes.filter(note => moduleNoteIds.includes(note.noteId));

View file

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

View file

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

View file

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

View file

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

View file

@ -28,11 +28,11 @@ const noteHistory = (function() {
historyItems = await server.get('notes-history/' + noteId);
for (const item of historyItems) {
const dateModified = parseDate(item.dateModifiedFrom);
const dateModified = utils.parseDate(item.dateModifiedFrom);
$list.append($('<option>', {
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) {
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) {
const formattedTime = formatTime(parseDate(change.dateModifiedTo));
const formattedTime = utils.formatTime(utils.parseDate(change.dateModifiedTo));
const revLink = $("<a>", {
href: 'javascript:',
@ -58,7 +58,7 @@ const recentChanges = (function() {
const dayCache = {};
for (const row of result) {
let dateDay = parseDate(row.dateModifiedTo);
let dateDay = utils.parseDate(row.dateModifiedTo);
dateDay.setHours(0);
dateDay.setMinutes(0);
dateDay.setSeconds(0);

View file

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

View file

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

View file

@ -1,10 +1,10 @@
"use strict";
function exportSubTree(noteId) {
const url = getHost() + "/api/export/" + noteId + "?protectedSessionId="
const url = utils.getHost() + "/api/export/" + noteId + "?protectedSessionId="
+ encodeURIComponent(protected_session.getProtectedSessionId());
download(url);
utils.download(url);
}
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
$(document).bind('keydown', 'alt+t', e => {
const date = new Date();
const dateString = formatDateTime(date);
const dateString = utils.formatDateTime(date);
link.addTextToEditor(dateString);
@ -22,19 +22,19 @@ $(document).bind('keydown', 'alt+t', e => {
});
$(document).bind('keydown', 'f5', () => {
reloadApp();
utils.reloadApp();
return false;
});
$(document).bind('keydown', 'ctrl+r', () => {
reloadApp();
utils.reloadApp();
return false;
});
$(document).bind('keydown', 'ctrl+shift+i', () => {
if (isElectron()) {
if (utils.isElectron()) {
require('electron').remote.getCurrentWindow().toggleDevTools();
return false;
@ -42,7 +42,7 @@ $(document).bind('keydown', 'ctrl+shift+i', () => {
});
$(document).bind('keydown', 'ctrl+f', () => {
if (isElectron()) {
if (utils.isElectron()) {
const searchInPage = require('electron-in-page-search').default;
const remote = require('electron').remote;
@ -73,7 +73,7 @@ $(document).bind('keydown', "ctrl+shift+down", () => {
});
$(document).bind('keydown', 'ctrl+-', () => {
if (isElectron()) {
if (utils.isElectron()) {
const webFrame = require('electron').webFrame;
if (webFrame.getZoomFactor() > 0.2) {
@ -85,7 +85,7 @@ $(document).bind('keydown', 'ctrl+-', () => {
});
$(document).bind('keydown', 'ctrl+=', () => {
if (isElectron()) {
if (utils.isElectron()) {
const webFrame = require('electron').webFrame;
webFrame.setZoomFactor(webFrame.getZoomFactor() + 0.1);
@ -198,17 +198,17 @@ window.onerror = function (msg, url, lineNo, columnNo, error) {
return false;
};
$("#logout-button").toggle(!isElectron());
$("#logout-button").toggle(!utils.isElectron());
$(document).ready(() => {
server.get("script/startup").then(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) {
// this might occur when day note had to be created
if (!await treeService.noteExists(parentNoteId)) {

View file

@ -4,7 +4,7 @@ const messaging = (function() {
const $changesToPushCount = $("#changes-to-push-count");
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();
if (ws && ws.readyState === 1) {
@ -22,7 +22,7 @@ const messaging = (function() {
lastPingTs = new Date().getTime();
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;
}
@ -32,19 +32,19 @@ const messaging = (function() {
if (syncData.some(sync => sync.entityName === 'branches')
|| 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();
}
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();
}
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();
}
@ -55,10 +55,10 @@ const messaging = (function() {
$changesToPushCount.html(message.changesToPushCount);
}
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') {
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
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.onclose = function(){
// Try to reconnect in 5 seconds
@ -100,7 +100,7 @@ const messaging = (function() {
await connectionBrokenNotification.close();
connectionBrokenNotification = null;
showMessage("Re-connected to server");
utils.showMessage("Re-connected to server");
}
ws.send(JSON.stringify({

View file

@ -103,7 +103,7 @@ const noteEditor = (function() {
// nothing
}
else {
throwError("Unrecognized type: " + note.detail.type);
utils.throwError("Unrecognized type: " + note.detail.type);
}
const title = $noteTitle.val();
@ -118,7 +118,7 @@ const noteEditor = (function() {
isNoteChanged = false;
showMessage("Saved!");
utils.showMessage("Saved!");
}
function setNoteBackgroundIfProtected(note) {
@ -138,7 +138,7 @@ const noteEditor = (function() {
async function setContent(content) {
if (currentNote.detail.type === 'text') {
if (!editor) {
await requireLibrary(CKEDITOR);
await utils.requireLibrary(utils.CKEDITOR);
editor = await BalloonEditor.create($noteDetail[0], {});
@ -152,7 +152,7 @@ const noteEditor = (function() {
}
else if (currentNote.detail.type === 'code') {
if (!codeEditor) {
await requireLibrary(CODE_MIRROR);
await utils.requireLibrary(utils.CODE_MIRROR);
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
CodeMirror.keyMap.default["Tab"] = "indentMore";
@ -248,7 +248,7 @@ const noteEditor = (function() {
$noteDetailRender.html(bundle.html);
executeBundle(bundle);
utils.executeBundle(bundle);
}
else if (currentNote.detail.type === 'file') {
$noteDetailAttachment.show();
@ -281,7 +281,7 @@ const noteEditor = (function() {
if (labels.length > 0) {
for (const attr of labels) {
$labelListInner.append(formatLabel(attr) + " ");
$labelListInner.append(utils.formatLabel(attr) + " ");
}
$labelList.show();
@ -312,7 +312,7 @@ const noteEditor = (function() {
// do nothing
}
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")) {
const bundle = await server.get('script/bundle/' + getCurrentNoteId());
executeBundle(bundle);
utils.executeBundle(bundle);
}
if (currentNote.detail.mime.endsWith("env=backend")) {
await server.post('script/run/' + getCurrentNoteId());
}
showMessage("Note executed");
utils.showMessage("Note executed");
}
}
$attachmentDownload.click(() => download(getAttachmentUrl()));
$attachmentDownload.click(() => utils.download(getAttachmentUrl()));
$attachmentOpen.click(() => {
if (isElectron()) {
if (utils.isElectron()) {
const open = require("open");
open(getAttachmentUrl());
@ -356,7 +356,7 @@ const noteEditor = (function() {
function getAttachmentUrl() {
// 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());
}

View file

@ -135,38 +135,22 @@ const treeService = (function() {
const note = noteMap[noteId];
if (!note) {
throwError("Can't find title for noteId='" + noteId + "'");
utils.throwError("Can't find title for noteId='" + noteId + "'");
}
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) {
assertArguments(noteId);
utils.assertArguments(noteId);
let title = treeCache.getNote(noteId).title;
if (parentNoteId !== null) {
const branchId = getBranchId(parentNoteId, noteId);
const branch = treeCache.getBranch(noteId, parentNoteId);
if (branchId) {
const branch = branchMap[branchId];
if (branch.prefix) {
title = branch.prefix + ' - ' + title;
}
if (branch && branch.prefix) {
title = branch.prefix + ' - ' + title;
}
}
@ -185,7 +169,7 @@ const treeService = (function() {
}
function getNodesByBranchId(branchId) {
assertArguments(branchId);
utils.assertArguments(branchId);
const branch = branchMap[branchId];
@ -193,14 +177,14 @@ const treeService = (function() {
}
function getNodesByNoteId(noteId) {
assertArguments(noteId);
utils.assertArguments(noteId);
const list = getTree().getNodesByRef(noteId);
return list ? list : []; // if no nodes with this refKey are found, fancy tree returns null
}
function setPrefix(branchId, prefix) {
assertArguments(branchId);
utils.assertArguments(branchId);
branchMap[branchId].prefix = prefix;
@ -215,11 +199,11 @@ const treeService = (function() {
const title = (prefix ? (prefix + " - ") : "") + noteTitle;
node.setTitle(escapeHtml(title));
node.setTitle(utils.escapeHtml(title));
}
function removeParentChildRelation(parentNoteId, childNoteId) {
assertArguments(parentNoteId, childNoteId);
utils.assertArguments(parentNoteId, childNoteId);
const parentNote = noteMap[parentNoteId];
const childNote = noteMap[childNoteId];
@ -228,7 +212,7 @@ const treeService = (function() {
}
function setParentChildRelation(branchId, parentNoteId, childNoteId) {
assertArguments(branchId, parentNoteId, childNoteId);
utils.assertArguments(branchId, parentNoteId, childNoteId);
const parentNote = noteMap[parentNoteId];
const childNote = noteMap[childNoteId];
@ -237,7 +221,7 @@ const treeService = (function() {
}
async function prepareBranch(noteRows, branchRows) {
assertArguments(noteRows);
utils.assertArguments(noteRows);
treeCache = new TreeCache(noteRows, branchRows);
@ -245,7 +229,7 @@ const treeService = (function() {
}
async function getExtraClasses(note) {
assertArguments(note);
utils.assertArguments(note);
const extraClasses = [];
@ -263,7 +247,7 @@ const treeService = (function() {
}
async function prepareBranchInner(parentNote) {
assertArguments(parentNote);
utils.assertArguments(parentNote);
const childBranches = await parentNote.getChildBranches();
@ -283,7 +267,7 @@ const treeService = (function() {
parentNoteId: branch.parentNoteId,
branchId: branch.branchId,
isProtected: note.isProtected,
title: escapeHtml(title),
title: utils.escapeHtml(title),
extraClasses: getExtraClasses(note),
refKey: note.noteId,
expanded: note.type !== 'search' && branch.isExpanded
@ -309,7 +293,7 @@ const treeService = (function() {
}
async function expandToNote(notePath, expandOpts) {
assertArguments(notePath);
utils.assertArguments(notePath);
const runPath = await getRunPath(notePath);
@ -332,7 +316,7 @@ const treeService = (function() {
}
async function activateNode(notePath) {
assertArguments(notePath);
utils.assertArguments(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.
*/
async function getRunPath(notePath) {
assertArguments(notePath);
utils.assertArguments(notePath);
const path = notePath.split("/").reverse();
path.push('root');
@ -372,10 +356,10 @@ const treeService = (function() {
}
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) {
console.log(now(), "Available parents:", parents);
console.log(utils.now(), "Available parents:", parents);
const someNotePath = await getSomeNotePath(parents[0]);
@ -409,13 +393,13 @@ const treeService = (function() {
}
async function showParentList(noteId, node) {
assertArguments(noteId, node);
utils.assertArguments(noteId, node);
const note = treeCache.getNote(noteId);
const parents = await note.getParentNotes();
if (!parents.length) {
throwError("Can't find parents for noteId=" + noteId);
utils.throwError("Can't find parents for noteId=" + noteId);
}
if (parents.length <= 1) {
@ -446,7 +430,7 @@ const treeService = (function() {
}
function getNotePathTitle(notePath) {
assertArguments(notePath);
utils.assertArguments(notePath);
const titlePath = [];
@ -462,7 +446,7 @@ const treeService = (function() {
}
async function getSomeNotePath(note) {
assertArguments(note);
utils.assertArguments(note);
const path = [];
@ -474,7 +458,7 @@ const treeService = (function() {
const parents = await cur.getParentNotes();
if (!parents.length) {
throwError("Can't find parents for " + cur);
utils.throwError("Can't find parents for " + cur);
}
cur = parents[0];
@ -484,7 +468,7 @@ const treeService = (function() {
}
async function setExpandedToServer(branchId, isExpanded) {
assertArguments(branchId);
utils.assertArguments(branchId);
const expandedNum = isExpanded ? 1 : 0;
@ -492,7 +476,7 @@ const treeService = (function() {
}
function setCurrentNotePathToHash(node) {
assertArguments(node);
utils.assertArguments(node);
const currentNotePath = treeUtils.getNotePath(node);
const currentBranchId = node.data.branchId;
@ -519,7 +503,7 @@ const treeService = (function() {
}
function initFancyTree(branch) {
assertArguments(branch);
utils.assertArguments(branch);
const keybindings = {
"del": node => {
@ -621,7 +605,7 @@ const treeService = (function() {
return false;
},
"backspace": node => {
if (!isTopLevelNode(node)) {
if (!utils.isTopLevelNode(node)) {
node.getParent().setActive().then(() => clearSelectedNodes());
}
},
@ -748,7 +732,7 @@ const treeService = (function() {
const noteIds = await server.get('search/' + encodeURIComponent(json.searchString));
for (const noteId of noteIds) {
const branchId = "virt" + randomString(10);
const branchId = "virt" + utils.randomString(10);
branchMap[branchId] = {
branchId: branchId,
@ -874,7 +858,7 @@ const treeService = (function() {
}
function setNoteTitle(noteId, title) {
assertArguments(noteId);
utils.assertArguments(noteId);
getNote(noteId).title = title;
@ -888,7 +872,7 @@ const treeService = (function() {
}
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
// 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();
}
else {
throwError("Unrecognized target: " + target);
utils.throwError("Unrecognized target: " + target);
}
clearSelectedNodes(); // to unmark previously active node
showMessage("Created!");
utils.showMessage("Created!");
}
async function sortAlphabetically(noteId) {
@ -1010,7 +994,7 @@ const treeService = (function() {
}
});
if (isElectron()) {
if (utils.isElectron()) {
$(document).bind('keydown', 'alt+left', e => {
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
}
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);
if (!response.success) {
showError("Wrong password.");
utils.showError("Wrong password.");
return;
}
@ -103,7 +103,7 @@ const protected_session = (function() {
// most secure solution - guarantees nothing remained in memory
// since this expires because user doesn't use the app, it shouldn't be disruptive
reloadApp();
utils.reloadApp();
}
function isProtectedSessionAvailable() {
@ -153,7 +153,7 @@ const protected_session = (function() {
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();
noteEditor.reload();

View file

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

View file

@ -4,14 +4,14 @@ async function syncNow() {
const result = await server.post('sync/now');
if (result.success) {
showMessage("Sync finished successfully.");
utils.showMessage("Sync finished successfully.");
}
else {
if (result.message.length > 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) {
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();
}
if (!next && !isTopLevelNode(nodes[0])) {
if (!next && !utils.isTopLevelNode(nodes[0])) {
next = nodes[0].getParent();
}
@ -85,11 +85,11 @@ const treeChanges = (function() {
treeService.reload();
showMessage("Note(s) has been deleted.");
utils.showMessage("Note(s) has been deleted.");
}
async function moveNodeUpInHierarchy(node) {
if (isTopLevelNode(node)) {
if (utils.isTopLevelNode(node)) {
return;
}
@ -100,7 +100,7 @@ const treeChanges = (function() {
return;
}
if (!isTopLevelNode(node) && node.getParent().getChildren().length <= 1) {
if (!utils.isTopLevelNode(node) && node.getParent().getChildren().length <= 1) {
node.getParent().folder = false;
node.getParent().renderTitle();
}
@ -109,13 +109,13 @@ const treeChanges = (function() {
}
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);
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);

View file

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

View file

@ -1,233 +1,270 @@
"use strict";
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));
const utils = (function() {
function reloadApp() {
window.location.reload(true);
}
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) {
return (num <= 9 ? "0" : "") + num;
}
function showError(message, delay = 10000) {
console.log(now(), "error: ", message);
function formatTime(date) {
return padNum(date.getHours()) + ":" + padNum(date.getMinutes());
}
$.notify({
// options
message: message
}, {
// settings
type: 'danger',
delay: delay
});
}
function formatTimeWithSeconds(date) {
return padNum(date.getHours()) + ":" + padNum(date.getMinutes()) + ":" + padNum(date.getSeconds());
}
function throwError(message) {
messaging.logError(message);
function formatDate(date) {
return padNum(date.getDate()) + ". " + padNum(date.getMonth() + 1) + ". " + date.getFullYear();
}
throw new Error(message);
}
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]}`);
function parseDate(str) {
try {
return new Date(Date.parse(str));
}
catch (e) {
throw new Error("Can't parse date from " + str + ": " + e.stack);
}
}
}
function assert(expr, message) {
if (!expr) {
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);
function padNum(num) {
return (num <= 9 ? "0" : "") + num;
}
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));
function formatTime(date) {
return padNum(date.getHours()) + ":" + padNum(date.getMinutes());
}
if (library.js) {
for (const scriptUrl of library.js) {
await requireScript(scriptUrl);
function formatTimeWithSeconds(date) {
return padNum(date.getHours()) + ":" + padNum(date.getMinutes()) + ":" + padNum(date.getSeconds());
}
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 = [];
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];
function assert(expr, message) {
if (!expr) {
throwError(message);
}
}
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));
function isTopLevelNode(node) {
return isRootNode(node.getParent());
}
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
};
})();