Compare commits

...

6 Commits

Author SHA1 Message Date
azivner
a8774353fd release 0.23.1 2018-10-25 18:13:37 +02:00
azivner
0c007566ad fixes for invalid operations on root note 2018-10-21 22:42:20 +02:00
azivner
bfa2b5fa62 add a check for root parent 2018-10-21 21:37:34 +02:00
azivner
1de06b4fc9 fix links in README 2018-10-12 18:38:57 +02:00
azivner
949456212a fix for ckeditor stretching body 2018-10-12 13:40:06 +02:00
azivner
06a867773e minor library updates 2018-10-12 12:37:03 +02:00
16 changed files with 2056 additions and 2990 deletions

View File

@@ -12,10 +12,10 @@ See other pictures in [screenshot tour](https://github.com/zadam/trilium/wiki/Sc
* Notes can be arranged into arbitrarily deep hierarchy (tree) * Notes can be arranged into arbitrarily deep hierarchy (tree)
* Notes can have more than 1 parents - see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes) * Notes can have more than 1 parents - see [cloning](https://github.com/zadam/trilium/wiki/Cloning-notes)
* Rich WYSIWYG note editing including e.g. tables and images with markdown [autoformat](https://github.com/zadam/trilium/wiki/Text-editor#autoformat) * Rich WYSIWYG note editing including e.g. tables and images with markdown [autoformat](https://github.com/zadam/trilium/wiki/Text-editor#autoformat)
* Support for editing [notes with source code](https://raw.githubusercontent.com/wiki/zadam/trilium/images/code-note.png), including syntax highlighting * Support for editing [notes with source code](https://github.com/zadam/trilium/wiki/Code-notes), including syntax highlighting
* Fast and easy [navigation between notes](https://github.com/zadam/trilium/wiki/Note-navigation) * Fast and easy [navigation between notes](https://github.com/zadam/trilium/wiki/Note-navigation)
* Seamless [note versioning](https://github.com/zadam/trilium/wiki/Note-revisions) * Seamless [note versioning](https://github.com/zadam/trilium/wiki/Note-revisions)
* Note [attributes](https://github.com/zadam/trilium/wiki/Attributes) can be used for note organization, querying and advanced [[scripting|scripts]] * Note [attributes](https://github.com/zadam/trilium/wiki/Attributes) can be used for note organization, querying and advanced [scripting](https://github.com/zadam/trilium/wiki/Scripts)
* [Synchronization](https://github.com/zadam/trilium/wiki/Synchronization) with self-hosted sync server * [Synchronization](https://github.com/zadam/trilium/wiki/Synchronization) with self-hosted sync server
* Strong [note encryption](https://github.com/zadam/trilium/wiki/Protected-notes) * Strong [note encryption](https://github.com/zadam/trilium/wiki/Protected-notes)
* [Scripting](https://github.com/zadam/trilium/wiki/Scripts) - see [Advanced showcases](https://github.com/zadam/trilium/wiki/Advanced-showcases) * [Scripting](https://github.com/zadam/trilium/wiki/Scripts) - see [Advanced showcases](https://github.com/zadam/trilium/wiki/Advanced-showcases)

View File

@@ -27,7 +27,7 @@ WIN_RES_DIR=./dist/trilium-win32-x64/resources/app
cp -r bin/deps/sqlite/* $WIN_RES_DIR/node_modules/sqlite3/lib/binding/ cp -r bin/deps/sqlite/* $WIN_RES_DIR/node_modules/sqlite3/lib/binding/
cp bin/deps/image/cjpeg.exe $WIN_RES_DIR/node_modules/mozjpeg/vendor/ cp bin/deps/image/cjpeg.exe $WIN_RES_DIR/node_modules/mozjpeg/vendor/
cp bin/deps/image/pngquant.exe $WIN_RES_DIR/node_modules/imagemin-pngquant/node_modules/pngquant-bin/vendor/ cp bin/deps/image/pngquant.exe $WIN_RES_DIR/node_modules/pngquant-bin/vendor/
cp bin/deps/image/gifsicle.exe $WIN_RES_DIR/node_modules/giflossy/vendor/ cp bin/deps/image/gifsicle.exe $WIN_RES_DIR/node_modules/giflossy/vendor/
cp bin/deps/scrypt.node $WIN_RES_DIR/node_modules/@mlink/scrypt/build/Release/ cp bin/deps/scrypt.node $WIN_RES_DIR/node_modules/@mlink/scrypt/build/Release/

View File

@@ -0,0 +1 @@
update branches set parentNoteId = 'none' where branchId = 'root'

4951
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{ {
"name": "trilium", "name": "trilium",
"description": "Trilium Notes", "description": "Trilium Notes",
"version": "0.23.0", "version": "0.23.1",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"main": "electron.js", "main": "electron.js",
"bin": { "bin": {
@@ -33,17 +33,17 @@
"cls-hooked": "4.2.2", "cls-hooked": "4.2.2",
"commonmark": "0.28.1", "commonmark": "0.28.1",
"cookie-parser": "1.4.3", "cookie-parser": "1.4.3",
"debug": "4.0.1", "debug": "4.1.0",
"devtron": "1.4.0", "devtron": "1.4.0",
"ejs": "2.6.1", "ejs": "2.6.1",
"electron-debug": "2.0.0", "electron-debug": "2.0.0",
"electron-dl": "1.12.0", "electron-dl": "1.12.0",
"electron-in-page-search": "1.3.2", "electron-in-page-search": "1.3.2",
"express": "4.16.3", "express": "4.16.4",
"express-session": "1.15.6", "express-session": "1.15.6",
"fs-extra": "7.0.0", "fs-extra": "7.0.0",
"get-port": "4.0.0", "get-port": "4.0.0",
"helmet": "3.13.0", "helmet": "3.14.0",
"html": "1.0.0", "html": "1.0.0",
"image-type": "3.0.0", "image-type": "3.0.0",
"imagemin": "6.0.0", "imagemin": "6.0.0",
@@ -51,9 +51,9 @@
"imagemin-mozjpeg": "7.0.0", "imagemin-mozjpeg": "7.0.0",
"imagemin-pngquant": "6.0.0", "imagemin-pngquant": "6.0.0",
"ini": "1.3.5", "ini": "1.3.5",
"jimp": "0.5.3", "jimp": "0.5.4",
"moment": "2.22.2", "moment": "2.22.2",
"multer": "1.4.0", "multer": "1.4.1",
"open": "0.0.5", "open": "0.0.5",
"rand-token": "0.4.0", "rand-token": "0.4.0",
"rcedit": "1.1.1", "rcedit": "1.1.1",

View File

@@ -5,6 +5,13 @@ import infoService from "./info.js";
import treeCache from "./tree_cache.js"; import treeCache from "./tree_cache.js";
async function moveBeforeNode(nodesToMove, beforeNode) { async function moveBeforeNode(nodesToMove, beforeNode) {
nodesToMove = filterRootNote(nodesToMove);
if (beforeNode.data.noteId === 'root') {
alert('Cannot move notes before root note.');
return;
}
for (const nodeToMove of nodesToMove) { for (const nodeToMove of nodesToMove) {
const resp = await server.put('branches/' + nodeToMove.data.branchId + '/move-before/' + beforeNode.data.branchId); const resp = await server.put('branches/' + nodeToMove.data.branchId + '/move-before/' + beforeNode.data.branchId);
@@ -18,6 +25,13 @@ async function moveBeforeNode(nodesToMove, beforeNode) {
} }
async function moveAfterNode(nodesToMove, afterNode) { async function moveAfterNode(nodesToMove, afterNode) {
nodesToMove = filterRootNote(nodesToMove);
if (afterNode.data.noteId === 'root') {
alert('Cannot move notes after root note.');
return;
}
nodesToMove.reverse(); // need to reverse to keep the note order nodesToMove.reverse(); // need to reverse to keep the note order
for (const nodeToMove of nodesToMove) { for (const nodeToMove of nodesToMove) {
@@ -33,6 +47,8 @@ async function moveAfterNode(nodesToMove, afterNode) {
} }
async function moveToNode(nodesToMove, toNode) { async function moveToNode(nodesToMove, toNode) {
nodesToMove = filterRootNote(nodesToMove);
for (const nodeToMove of nodesToMove) { for (const nodeToMove of nodesToMove) {
const resp = await server.put('branches/' + nodeToMove.data.branchId + '/move-to/' + toNode.data.noteId); const resp = await server.put('branches/' + nodeToMove.data.branchId + '/move-to/' + toNode.data.noteId);
@@ -58,8 +74,13 @@ async function moveToNode(nodesToMove, toNode) {
} }
} }
function filterRootNote(nodes) {
// some operations are not possible on root notes
return nodes.filter(node => node.data.noteId !== 'root');
}
async function deleteNodes(nodes) { async function deleteNodes(nodes) {
nodes = nodes.filter(node => node.data.noteId !== 'root'); nodes = filterRootNote(nodes);
if (nodes.length === 0 || !confirm('Are you sure you want to delete select note(s) and all the sub-notes?')) { if (nodes.length === 0 || !confirm('Are you sure you want to delete select note(s) and all the sub-notes?')) {
return; return;
@@ -94,7 +115,7 @@ async function deleteNodes(nodes) {
} }
async function moveNodeUpInHierarchy(node) { async function moveNodeUpInHierarchy(node) {
if (utils.isTopLevelNode(node)) { if (utils.isRootNode(node) || utils.isTopLevelNode(node)) {
return; return;
} }

View File

@@ -14,6 +14,10 @@ const dragAndDropSetup = {
preventVoidMoves: true, // Prevent dropping nodes 'before self', etc. preventVoidMoves: true, // Prevent dropping nodes 'before self', etc.
dragStart: (node, data) => { dragStart: (node, data) => {
if (node.data.noteId === 'root') {
return false;
}
// This function MUST be defined to enable dragging for the tree. // This function MUST be defined to enable dragging for the tree.
// Return false to cancel dragging of node. // Return false to cancel dragging of node.
return true; return true;

View File

@@ -105,7 +105,7 @@ const keyBindings = {
return false; return false;
}, },
"backspace": node => { "backspace": node => {
if (!utils.isTopLevelNode(node)) { if (!utils.isRootNode(node)) {
node.getParent().setActive().then(treeService.clearSelectedNodes); node.getParent().setActive().then(treeService.clearSelectedNodes);
} }
}, },

View File

@@ -4,7 +4,7 @@ import treeCache from "./tree_cache.js";
const $tree = $("#tree"); const $tree = $("#tree");
function getParentProtectedStatus(node) { function getParentProtectedStatus(node) {
return utils.isTopLevelNode(node) ? 0 : node.getParent().data.isProtected; return utils.isRootNode(node) ? 0 : node.getParent().data.isProtected;
} }
function getNodeByKey(key) { function getNodeByKey(key) {
@@ -32,6 +32,8 @@ function getNotePath(node) {
node = node.getParent(); node = node.getParent();
} }
path.push('root');
return path.reverse().join("/"); return path.reverse().join("/");
} }

View File

@@ -59,7 +59,7 @@ function isTopLevelNode(node) {
} }
function isRootNode(node) { function isRootNode(node) {
return node.key === "root_1"; return node.data.noteId === "root";
} }
function escapeHtml(str) { function escapeHtml(str) {

View File

@@ -9,6 +9,12 @@ h6 {
font-weight: 600; font-weight: 600;
} }
body {
/* Fix for CKEditor block gutter icon "stretching" body and causing scrollbar to appear after pressing enter
on the last line of the editor. */
position: fixed;
}
#container { #container {
margin: 0 auto; /* center */ margin: 0 auto; /* center */
height: 100vh; height: 100vh;

View File

@@ -21,7 +21,7 @@ async function moveBranchToParent(req) {
const validationResult = await tree.validateParentChild(parentNoteId, noteToMove.noteId, branchId); const validationResult = await tree.validateParentChild(parentNoteId, noteToMove.noteId, branchId);
if (!validationResult.success) { if (!validationResult.success) {
return [400, validationResult]; return [200, validationResult];
} }
const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [parentNoteId]); const maxNotePos = await sql.getValue('SELECT MAX(notePosition) FROM branches WHERE parentNoteId = ? AND isDeleted = 0', [parentNoteId]);
@@ -45,7 +45,7 @@ async function moveBranchBeforeNote(req) {
const validationResult = await tree.validateParentChild(beforeNote.parentNoteId, noteToMove.noteId, branchId); const validationResult = await tree.validateParentChild(beforeNote.parentNoteId, noteToMove.noteId, branchId);
if (!validationResult.success) { if (!validationResult.success) {
return [400, validationResult]; return [200, validationResult];
} }
// we don't change dateModified so other changes are prioritized in case of conflict // we don't change dateModified so other changes are prioritized in case of conflict
@@ -73,7 +73,7 @@ async function moveBranchAfterNote(req) {
const validationResult = await tree.validateParentChild(afterNote.parentNoteId, noteToMove.noteId, branchId); const validationResult = await tree.validateParentChild(afterNote.parentNoteId, noteToMove.noteId, branchId);
if (!validationResult.success) { if (!validationResult.success) {
return [400, validationResult]; return [200, validationResult];
} }
// we don't change dateModified so other changes are prioritized in case of conflict // we don't change dateModified so other changes are prioritized in case of conflict

View File

@@ -3,7 +3,7 @@
const build = require('./build'); const build = require('./build');
const packageJson = require('../../package'); const packageJson = require('../../package');
const APP_DB_VERSION = 113; const APP_DB_VERSION = 114;
const SYNC_VERSION = 1; const SYNC_VERSION = 1;
module.exports = { module.exports = {

View File

@@ -1 +1 @@
module.exports = { buildDate:"2018-10-09T21:08:11+02:00", buildRevision: "5352f388a79e3424264beb8021fc3c31f51a1a6a" }; module.exports = { buildDate:"2018-10-25T18:13:37+02:00", buildRevision: "0c007566ad31a98ad585fa97435fc9306ec0a3c8" };

View File

@@ -28,10 +28,7 @@ async function checkTreeCycles(errorList) {
const childNoteId = row.noteId; const childNoteId = row.noteId;
const parentNoteId = row.parentNoteId; const parentNoteId = row.parentNoteId;
if (!childToParents[childNoteId]) { childToParents[childNoteId] = childToParents[childNoteId] || [];
childToParents[childNoteId] = [];
}
childToParents[childNoteId].push(parentNoteId); childToParents[childNoteId].push(parentNoteId);
} }
@@ -40,6 +37,11 @@ async function checkTreeCycles(errorList) {
return; return;
} }
if (!childToParents[noteId] || childToParents[noteId].length === 0) {
errorList.push(`No parents found for noteId=${noteId}`);
return;
}
for (const parentNoteId of childToParents[noteId]) { for (const parentNoteId of childToParents[noteId]) {
if (path.includes(parentNoteId)) { if (path.includes(parentNoteId)) {
errorList.push(`Tree cycle detected at parent-child relationship: ${parentNoteId} - ${noteId}, whole path: ${path}`); errorList.push(`Tree cycle detected at parent-child relationship: ${parentNoteId} - ${noteId}, whole path: ${path}`);
@@ -58,6 +60,10 @@ async function checkTreeCycles(errorList) {
for (const noteId of noteIds) { for (const noteId of noteIds) {
checkTreeCycle(noteId, [], errorList); checkTreeCycle(noteId, [], errorList);
} }
if (childToParents['root'].length !== 1 || childToParents['root'][0] !== 'none') {
errorList.push('Incorrect root parent: ' + JSON.stringify(childToParents['root']));
}
} }
async function runSyncRowChecks(table, key, errorList) { async function runSyncRowChecks(table, key, errorList) {

View File

@@ -7,6 +7,15 @@ const syncTableService = require('./sync_table');
const protectedSessionService = require('./protected_session'); const protectedSessionService = require('./protected_session');
async function validateParentChild(parentNoteId, childNoteId, branchId = null) { async function validateParentChild(parentNoteId, childNoteId, branchId = null) {
if (childNoteId === 'root') {
return { success: false, message: 'Cannot move root note.'};
}
if (parentNoteId === 'none') {
// this shouldn't happen
return { success: false, message: 'Cannot move anything into root parent.' };
}
const existing = await getExistingBranch(parentNoteId, childNoteId); const existing = await getExistingBranch(parentNoteId, childNoteId);
if (existing && (branchId === null || existing.branchId !== branchId)) { if (existing && (branchId === null || existing.branchId !== branchId)) {