mirror of
https://github.com/zadam/trilium.git
synced 2025-10-29 17:26:38 +01:00
Compare commits
18 Commits
v0.6.1
...
v0.7.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8c52e25f0 | ||
|
|
a149c6a105 | ||
|
|
131af9ab12 | ||
|
|
aa2bbc6575 | ||
|
|
78e8c15786 | ||
|
|
fda4146150 | ||
|
|
ddc885066e | ||
|
|
08bc2afb49 | ||
|
|
1d0220b03d | ||
|
|
3033f7cc08 | ||
|
|
6b9ff47c88 | ||
|
|
fd02c6102d | ||
|
|
30c712a6be | ||
|
|
3928c96640 | ||
|
|
d86f655658 | ||
|
|
abdad1c3ae | ||
|
|
9e5f1a0a87 | ||
|
|
cdde6a4d8e |
23
db/migrations/0077__non_null_attribute_value.sql
Normal file
23
db/migrations/0077__non_null_attribute_value.sql
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
UPDATE attributes SET value = '' WHERE value IS NULL;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS "attributes_mig"
|
||||||
|
(
|
||||||
|
attributeId TEXT PRIMARY KEY NOT NULL,
|
||||||
|
noteId TEXT NOT NULL,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
value TEXT NOT NULL DEFAULT '',
|
||||||
|
position INT NOT NULL DEFAULT 0,
|
||||||
|
dateCreated TEXT NOT NULL,
|
||||||
|
dateModified TEXT NOT NULL,
|
||||||
|
isDeleted INT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
INSERT INTO attributes_mig (attributeId, noteId, name, value, position, dateCreated, dateModified, isDeleted)
|
||||||
|
SELECT attributeId, noteId, name, value, position, dateCreated, dateModified, isDeleted FROM attributes;
|
||||||
|
|
||||||
|
DROP TABLE attributes;
|
||||||
|
|
||||||
|
ALTER TABLE attributes_mig RENAME TO attributes;
|
||||||
|
|
||||||
|
CREATE INDEX IDX_attributes_noteId ON attributes (noteId);
|
||||||
|
CREATE INDEX IDX_attributes_name_value ON attributes (name, value);
|
||||||
10
electron.js
10
electron.js
@@ -3,11 +3,11 @@
|
|||||||
const electron = require('electron');
|
const electron = require('electron');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const config = require('./src/services/config');
|
const config = require('./src/services/config');
|
||||||
|
const log = require('./src/services/log');
|
||||||
const url = require("url");
|
const url = require("url");
|
||||||
|
|
||||||
const app = electron.app;
|
const app = electron.app;
|
||||||
const globalShortcut = electron.globalShortcut;
|
const globalShortcut = electron.globalShortcut;
|
||||||
const clipboard = electron.clipboard;
|
|
||||||
|
|
||||||
// Adds debug features like hotkeys for triggering dev tools and reload
|
// Adds debug features like hotkeys for triggering dev tools and reload
|
||||||
require('electron-debug')();
|
require('electron-debug')();
|
||||||
@@ -15,6 +15,8 @@ require('electron-debug')();
|
|||||||
// Prevent window being garbage collected
|
// Prevent window being garbage collected
|
||||||
let mainWindow;
|
let mainWindow;
|
||||||
|
|
||||||
|
require('electron-dl')({ saveAs: true });
|
||||||
|
|
||||||
function onClosed() {
|
function onClosed() {
|
||||||
// Dereference the window
|
// Dereference the window
|
||||||
// For multiple windows store them in an array
|
// For multiple windows store them in an array
|
||||||
@@ -70,7 +72,7 @@ app.on('activate', () => {
|
|||||||
app.on('ready', () => {
|
app.on('ready', () => {
|
||||||
mainWindow = createMainWindow();
|
mainWindow = createMainWindow();
|
||||||
|
|
||||||
globalShortcut.register('CommandOrControl+Alt+P', async () => {
|
const result = globalShortcut.register('CommandOrControl+Alt+P', async () => {
|
||||||
const date_notes = require('./src/services/date_notes');
|
const date_notes = require('./src/services/date_notes');
|
||||||
const utils = require('./src/services/utils');
|
const utils = require('./src/services/utils');
|
||||||
|
|
||||||
@@ -81,6 +83,10 @@ app.on('ready', () => {
|
|||||||
|
|
||||||
mainWindow.webContents.send('create-day-sub-note', parentNoteId);
|
mainWindow.webContents.send('create-day-sub-note', parentNoteId);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
log.error("Could not register global shortcut CTRL+ALT+P");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.on('will-quit', () => {
|
app.on('will-quit', () => {
|
||||||
|
|||||||
148
package-lock.json
generated
148
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"version": "0.4.1",
|
"version": "0.6.2",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -3061,19 +3061,19 @@
|
|||||||
"integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo="
|
"integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo="
|
||||||
},
|
},
|
||||||
"electron": {
|
"electron": {
|
||||||
"version": "1.8.2-beta.4",
|
"version": "1.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/electron/-/electron-1.8.2-beta.4.tgz",
|
"resolved": "https://registry.npmjs.org/electron/-/electron-1.8.2.tgz",
|
||||||
"integrity": "sha1-GDayBO6s6dx3Bi7Ugg/bxsvZoZU=",
|
"integrity": "sha512-0TV5Hy92g8ACnPn+PVol6a/2uk+khzmRtWxhah/FcKs6StCytm5hD14QqOdZxEdJN8HljXIVCayN/wJX+0wDiQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "8.5.9",
|
"@types/node": "8.9.4",
|
||||||
"electron-download": "3.3.0",
|
"electron-download": "3.3.0",
|
||||||
"extract-zip": "1.6.5"
|
"extract-zip": "1.6.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "8.5.9",
|
"version": "8.9.4",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.9.4.tgz",
|
||||||
"integrity": "sha512-s+c3AjymyAccTI4hcgNFK4mToH8l+hyPDhu4LIkn71lRy56FLijGu00fyLgldjM/846Pmk9N4KFUs2P8GDs0pA=="
|
"integrity": "sha512-dSvD36qnQs78G1BPsrZFdPpvLgMW/dnvr5+nTW2csMs5TiP9MOXrjUbnMZOEwnIuBklXtn7b6TPA2Cuq07bDHA=="
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -3206,6 +3206,16 @@
|
|||||||
"electron-localshortcut": "3.1.0"
|
"electron-localshortcut": "3.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"electron-dl": {
|
||||||
|
"version": "1.11.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/electron-dl/-/electron-dl-1.11.0.tgz",
|
||||||
|
"integrity": "sha512-iL9qHzzWOuL9bus+UT+P72SwrDQcFTV6QHqcbhwgqjCC9/K5jhdRzG0dIMB3TzYlk6rmApanPqh9DvWykwIH1Q==",
|
||||||
|
"requires": {
|
||||||
|
"ext-name": "5.0.0",
|
||||||
|
"pupa": "1.0.0",
|
||||||
|
"unused-filename": "1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"electron-download": {
|
"electron-download": {
|
||||||
"version": "3.3.0",
|
"version": "3.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/electron-download/-/electron-download-3.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/electron-download/-/electron-download-3.3.0.tgz",
|
||||||
@@ -3325,9 +3335,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron-packager": {
|
"electron-packager": {
|
||||||
"version": "10.1.1",
|
"version": "11.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-10.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/electron-packager/-/electron-packager-11.0.1.tgz",
|
||||||
"integrity": "sha1-MWp/ossf/CYz9YBcn8IJE8vAnZQ=",
|
"integrity": "sha1-wtH/nsqBEL6evIGCbiqSHATRIA4=",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"asar": "0.14.0",
|
"asar": "0.14.0",
|
||||||
@@ -3343,13 +3353,19 @@
|
|||||||
"pify": "3.0.0",
|
"pify": "3.0.0",
|
||||||
"plist": "2.1.0",
|
"plist": "2.1.0",
|
||||||
"pruner": "0.0.7",
|
"pruner": "0.0.7",
|
||||||
"rcedit": "0.9.0",
|
"rcedit": "1.0.0",
|
||||||
"resolve": "1.4.0",
|
"resolve": "1.4.0",
|
||||||
"sanitize-filename": "1.6.1",
|
"sanitize-filename": "1.6.1",
|
||||||
"semver": "5.4.1",
|
"semver": "5.4.1",
|
||||||
"yargs-parser": "8.1.0"
|
"yargs-parser": "9.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"camelcase": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
|
||||||
|
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"electron-download": {
|
"electron-download": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/electron-download/-/electron-download-4.1.0.tgz",
|
||||||
@@ -3437,6 +3453,12 @@
|
|||||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"rcedit": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/rcedit/-/rcedit-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-W7DNa34x/3OgWyDHsI172AG/Lr/lZ+PkavFkHj0QhhkBRcV9QTmRJE1tDKrWkx8XHPSBsmZkNv9OKue6pncLFQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"sumchecker": {
|
"sumchecker": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/sumchecker/-/sumchecker-2.0.2.tgz",
|
||||||
@@ -3456,20 +3478,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"yargs-parser": {
|
||||||
|
"version": "9.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-9.0.2.tgz",
|
||||||
|
"integrity": "sha1-nM9qQ0YP5O1Aqbto9I1DuKaMwHc=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"camelcase": "4.1.0"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"electron-prebuilt-compile": {
|
"electron-prebuilt-compile": {
|
||||||
"version": "1.8.2-beta.4",
|
"version": "1.8.2",
|
||||||
"resolved": "https://registry.npmjs.org/electron-prebuilt-compile/-/electron-prebuilt-compile-1.8.2-beta.4.tgz",
|
"resolved": "https://registry.npmjs.org/electron-prebuilt-compile/-/electron-prebuilt-compile-1.8.2.tgz",
|
||||||
"integrity": "sha512-whVdRgFEDovWSFrAsbMXIiush6RQ8IV3XhYdL59zShck4U1eXGmdkaBCy+2tlkGmUGr0fRu+S4FpUx2ebBkRhQ==",
|
"integrity": "sha512-wiDVjy8S0PA/K/TUM0lw5gzZ+SmyVVGQ0qt9iFYXHJc6t8TzDXFY3DsoK37H3A7nWnkvXvoPdpJ5/h9KbTMoAw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"babel-plugin-array-includes": "2.0.3",
|
"babel-plugin-array-includes": "2.0.3",
|
||||||
"babel-plugin-transform-async-to-generator": "6.24.1",
|
"babel-plugin-transform-async-to-generator": "6.24.1",
|
||||||
"babel-preset-es2016-node5": "1.1.2",
|
"babel-preset-es2016-node5": "1.1.2",
|
||||||
"babel-preset-react": "6.24.1",
|
"babel-preset-react": "6.24.1",
|
||||||
"electron": "1.8.2-beta.4",
|
"electron": "1.8.2",
|
||||||
"electron-compile": "6.4.2",
|
"electron-compile": "6.4.2",
|
||||||
"electron-compilers": "5.9.0",
|
"electron-compilers": "5.9.0",
|
||||||
"yargs": "6.6.0"
|
"yargs": "6.6.0"
|
||||||
@@ -4353,6 +4384,23 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ext-list": {
|
||||||
|
"version": "2.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz",
|
||||||
|
"integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==",
|
||||||
|
"requires": {
|
||||||
|
"mime-db": "1.30.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ext-name": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==",
|
||||||
|
"requires": {
|
||||||
|
"ext-list": "2.2.2",
|
||||||
|
"sort-keys-length": "1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"extend": {
|
"extend": {
|
||||||
"version": "3.0.1",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
|
||||||
@@ -5901,8 +5949,7 @@
|
|||||||
"is-plain-obj": {
|
"is-plain-obj": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
|
||||||
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
|
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"is-png": {
|
"is-png": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
@@ -7131,6 +7178,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"modify-filename": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/modify-filename/-/modify-filename-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-mi3sg4Bvuy2XXyK+7IWcoms5OqE="
|
||||||
|
},
|
||||||
"moment": {
|
"moment": {
|
||||||
"version": "2.20.1",
|
"version": "2.20.1",
|
||||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
|
"resolved": "https://registry.npmjs.org/moment/-/moment-2.20.1.tgz",
|
||||||
@@ -7543,6 +7595,11 @@
|
|||||||
"mimic-fn": "1.1.0"
|
"mimic-fn": "1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"open": {
|
||||||
|
"version": "0.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/open/-/open-0.0.5.tgz",
|
||||||
|
"integrity": "sha1-QsPhjslUZra/DcQvOilFw/DK2Pw="
|
||||||
|
},
|
||||||
"optimist": {
|
"optimist": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
|
||||||
@@ -8370,6 +8427,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||||
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
|
||||||
},
|
},
|
||||||
|
"pupa": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/pupa/-/pupa-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-mpVopa9+ZXuEYqbp1TKHQ1YM7/Y="
|
||||||
|
},
|
||||||
"q": {
|
"q": {
|
||||||
"version": "1.5.1",
|
"version": "1.5.1",
|
||||||
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
||||||
@@ -8472,12 +8534,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rcedit": {
|
|
||||||
"version": "0.9.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/rcedit/-/rcedit-0.9.0.tgz",
|
|
||||||
"integrity": "sha1-ORDfVzRTmeKwMl9KUZAH+J5V7xw=",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"read-all-stream": {
|
"read-all-stream": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz",
|
||||||
@@ -9171,11 +9227,18 @@
|
|||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
|
||||||
"integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
|
"integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-plain-obj": "1.1.0"
|
"is-plain-obj": "1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sort-keys-length": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=",
|
||||||
|
"requires": {
|
||||||
|
"sort-keys": "1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"source-map": {
|
"source-map": {
|
||||||
"version": "0.5.7",
|
"version": "0.5.7",
|
||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||||
@@ -10948,6 +11011,22 @@
|
|||||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||||
},
|
},
|
||||||
|
"unused-filename": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/unused-filename/-/unused-filename-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-00CID3GuIRXrqhMlvvBcxmhEacY=",
|
||||||
|
"requires": {
|
||||||
|
"modify-filename": "1.1.0",
|
||||||
|
"path-exists": "3.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"path-exists": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"unzip-response": {
|
"unzip-response": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
|
||||||
@@ -11694,23 +11773,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"yargs-parser": {
|
|
||||||
"version": "8.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz",
|
|
||||||
"integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"camelcase": "4.1.0"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"camelcase": {
|
|
||||||
"version": "4.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
|
|
||||||
"integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
|
|
||||||
"dev": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"yauzl": {
|
"yauzl": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.4.1.tgz",
|
||||||
|
|||||||
10
package.json
10
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"description": "Trilium Notes",
|
"description": "Trilium Notes",
|
||||||
"version": "0.6.1",
|
"version": "0.7.0-beta",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"main": "electron.js",
|
"main": "electron.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
@@ -27,8 +27,9 @@
|
|||||||
"debug": "~3.1.0",
|
"debug": "~3.1.0",
|
||||||
"devtron": "^1.4.0",
|
"devtron": "^1.4.0",
|
||||||
"ejs": "~2.5.7",
|
"ejs": "~2.5.7",
|
||||||
"electron": "^1.8.2-beta.4",
|
"electron": "^1.8.2",
|
||||||
"electron-debug": "^1.5.0",
|
"electron-debug": "^1.5.0",
|
||||||
|
"electron-dl": "^1.11.0",
|
||||||
"electron-in-page-search": "^1.2.4",
|
"electron-in-page-search": "^1.2.4",
|
||||||
"express": "~4.16.2",
|
"express": "~4.16.2",
|
||||||
"express-promise-wrap": "^0.2.2",
|
"express-promise-wrap": "^0.2.2",
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
"jimp": "^0.2.28",
|
"jimp": "^0.2.28",
|
||||||
"moment": "^2.20.1",
|
"moment": "^2.20.1",
|
||||||
"multer": "^1.3.0",
|
"multer": "^1.3.0",
|
||||||
|
"open": "0.0.5",
|
||||||
"rand-token": "^0.4.0",
|
"rand-token": "^0.4.0",
|
||||||
"request": "^2.83.0",
|
"request": "^2.83.0",
|
||||||
"request-promise": "^4.2.2",
|
"request-promise": "^4.2.2",
|
||||||
@@ -60,8 +62,8 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron-compile": "^6.4.2",
|
"electron-compile": "^6.4.2",
|
||||||
"electron-packager": "^10.1.1",
|
"electron-packager": "^11.0.1",
|
||||||
"electron-prebuilt-compile": "1.8.2-beta.4",
|
"electron-prebuilt-compile": "1.8.2",
|
||||||
"electron-rebuild": "^1.7.3",
|
"electron-rebuild": "^1.7.3",
|
||||||
"tape": "^4.8.0",
|
"tape": "^4.8.0",
|
||||||
"xo": "^0.18.0"
|
"xo": "^0.18.0"
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ class Note extends Entity {
|
|||||||
return this.type === "code" && this.mime === "application/json";
|
return this.type === "code" && this.mime === "application/json";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isJavaScript() {
|
||||||
|
return this.type === "code" && this.mime === "application/javascript";
|
||||||
|
}
|
||||||
|
|
||||||
async getAttributes() {
|
async getAttributes() {
|
||||||
return this.repository.getEntities("SELECT * FROM attributes WHERE noteId = ? AND isDeleted = 0", [this.noteId]);
|
return this.repository.getEntities("SELECT * FROM attributes WHERE noteId = ? AND isDeleted = 0", [this.noteId]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
const api = (function() {
|
const api = (function() {
|
||||||
const pluginButtonsEl = $("#plugin-buttons");
|
const $pluginButtons = $("#plugin-buttons");
|
||||||
|
|
||||||
async function activateNote(notePath) {
|
async function activateNote(notePath) {
|
||||||
await noteTree.activateNode(notePath);
|
await noteTree.activateNode(notePath);
|
||||||
@@ -10,7 +10,7 @@ const api = (function() {
|
|||||||
|
|
||||||
button.attr('id', buttonId);
|
button.attr('id', buttonId);
|
||||||
|
|
||||||
pluginButtonsEl.append(button);
|
$pluginButtons.append(button);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const contextMenu = (function() {
|
const contextMenu = (function() {
|
||||||
const treeEl = $("#tree");
|
const $tree = $("#tree");
|
||||||
|
|
||||||
let clipboardIds = [];
|
let clipboardIds = [];
|
||||||
let clipboardMode = null;
|
let clipboardMode = null;
|
||||||
@@ -93,8 +93,8 @@ const contextMenu = (function() {
|
|||||||
beforeOpen: (event, ui) => {
|
beforeOpen: (event, ui) => {
|
||||||
const node = $.ui.fancytree.getNode(ui.target);
|
const node = $.ui.fancytree.getNode(ui.target);
|
||||||
// Modify menu entries depending on node status
|
// Modify menu entries depending on node status
|
||||||
treeEl.contextmenu("enableEntry", "pasteAfter", clipboardIds.length > 0);
|
$tree.contextmenu("enableEntry", "pasteAfter", clipboardIds.length > 0);
|
||||||
treeEl.contextmenu("enableEntry", "pasteInto", clipboardIds.length > 0);
|
$tree.contextmenu("enableEntry", "pasteInto", clipboardIds.length > 0);
|
||||||
|
|
||||||
// Activate node on right-click
|
// Activate node on right-click
|
||||||
node.setActive();
|
node.setActive();
|
||||||
|
|||||||
@@ -17,26 +17,34 @@ const sqlConsole = (function() {
|
|||||||
width: $(window).width(),
|
width: $(window).width(),
|
||||||
height: $(window).height(),
|
height: $(window).height(),
|
||||||
open: function() {
|
open: function() {
|
||||||
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
|
initEditor();
|
||||||
CodeMirror.keyMap.default["Tab"] = "indentMore";
|
|
||||||
|
|
||||||
CodeMirror.modeURL = 'libraries/codemirror/mode/%N/%N.js';
|
|
||||||
|
|
||||||
codeEditor = CodeMirror($query[0], {
|
|
||||||
value: "",
|
|
||||||
viewportMargin: Infinity,
|
|
||||||
indentUnit: 4,
|
|
||||||
highlightSelectionMatches: { showToken: /\w/, annotateScrollbar: false }
|
|
||||||
});
|
|
||||||
|
|
||||||
codeEditor.setOption("mode", "text/x-sqlite");
|
|
||||||
CodeMirror.autoLoadMode(codeEditor, "sql");
|
|
||||||
|
|
||||||
codeEditor.focus();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function initEditor() {
|
||||||
|
if (!codeEditor) {
|
||||||
|
await requireLibrary(CODE_MIRROR);
|
||||||
|
|
||||||
|
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
|
||||||
|
CodeMirror.keyMap.default["Tab"] = "indentMore";
|
||||||
|
|
||||||
|
CodeMirror.modeURL = 'libraries/codemirror/mode/%N/%N.js';
|
||||||
|
|
||||||
|
codeEditor = CodeMirror($query[0], {
|
||||||
|
value: "",
|
||||||
|
viewportMargin: Infinity,
|
||||||
|
indentUnit: 4,
|
||||||
|
highlightSelectionMatches: {showToken: /\w/, annotateScrollbar: false}
|
||||||
|
});
|
||||||
|
|
||||||
|
codeEditor.setOption("mode", "text/x-sqlite");
|
||||||
|
CodeMirror.autoLoadMode(codeEditor, "sql");
|
||||||
|
}
|
||||||
|
|
||||||
|
codeEditor.focus();
|
||||||
|
}
|
||||||
|
|
||||||
async function execute() {
|
async function execute() {
|
||||||
const sqlQuery = codeEditor.getValue();
|
const sqlQuery = codeEditor.getValue();
|
||||||
|
|
||||||
|
|||||||
@@ -207,8 +207,32 @@ if (isElectron()) {
|
|||||||
|
|
||||||
await noteTree.activateNode(parentNoteId);
|
await noteTree.activateNode(parentNoteId);
|
||||||
|
|
||||||
const node = noteTree.getCurrentNode();
|
setTimeout(() => {
|
||||||
|
const node = noteTree.getCurrentNode();
|
||||||
|
|
||||||
await noteTree.createNote(node, node.data.noteId, 'into', node.data.isProtected);
|
noteTree.createNote(node, node.data.noteId, 'into', node.data.isProtected);
|
||||||
|
}, 500);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function uploadAttachment() {
|
||||||
|
$("#file-upload").trigger('click');
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#file-upload").change(async function() {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('upload', this.files[0]);
|
||||||
|
|
||||||
|
const resp = await $.ajax({
|
||||||
|
url: baseApiUrl + 'attachments/upload/' + noteEditor.getCurrentNoteId(),
|
||||||
|
headers: server.getHeaders(),
|
||||||
|
data: formData,
|
||||||
|
type: 'POST',
|
||||||
|
contentType: false, // NEEDED, DON'T OMIT THIS
|
||||||
|
processData: false, // NEEDED, DON'T OMIT THIS
|
||||||
|
});
|
||||||
|
|
||||||
|
await noteTree.reload();
|
||||||
|
|
||||||
|
await noteTree.activateNode(resp.noteId);
|
||||||
|
});
|
||||||
@@ -41,11 +41,11 @@ const link = (function() {
|
|||||||
function goToLink(e) {
|
function goToLink(e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
const linkEl = $(e.target);
|
const $link = $(e.target);
|
||||||
let notePath = linkEl.attr("note-path");
|
let notePath = $link.attr("note-path");
|
||||||
|
|
||||||
if (!notePath) {
|
if (!notePath) {
|
||||||
const address = linkEl.attr("note-path") ? linkEl.attr("note-path") : linkEl.attr('href');
|
const address = $link.attr("note-path") ? $link.attr("note-path") : $link.attr('href');
|
||||||
|
|
||||||
if (!address) {
|
if (!address) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const messaging = (function() {
|
const messaging = (function() {
|
||||||
const changesToPushCountEl = $("#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(now(), message); // needs to be separate from .trace()
|
||||||
@@ -52,7 +52,7 @@ const messaging = (function() {
|
|||||||
// we don't detect image changes here since images themselves are immutable and references should be
|
// we don't detect image changes here since images themselves are immutable and references should be
|
||||||
// updated in note detail as well
|
// updated in note detail as well
|
||||||
|
|
||||||
changesToPushCountEl.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);
|
showError("Sync check failed!", 60000);
|
||||||
|
|||||||
@@ -1,16 +1,24 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const noteEditor = (function() {
|
const noteEditor = (function() {
|
||||||
const noteTitleEl = $("#note-title");
|
const $noteTitle = $("#note-title");
|
||||||
const noteDetailEl = $('#note-detail');
|
|
||||||
const noteDetailCodeEl = $('#note-detail-code');
|
const $noteDetail = $('#note-detail');
|
||||||
const noteDetailRenderEl = $('#note-detail-render');
|
const $noteDetailCode = $('#note-detail-code');
|
||||||
const protectButton = $("#protect-button");
|
const $noteDetailRender = $('#note-detail-render');
|
||||||
const unprotectButton = $("#unprotect-button");
|
const $noteDetailAttachment = $('#note-detail-attachment');
|
||||||
const noteDetailWrapperEl = $("#note-detail-wrapper");
|
|
||||||
const noteIdDisplayEl = $("#note-id-display");
|
const $protectButton = $("#protect-button");
|
||||||
const attributeListEl = $("#attribute-list");
|
const $unprotectButton = $("#unprotect-button");
|
||||||
const attributeListInnerEl = $("#attribute-list-inner");
|
const $noteDetailWrapper = $("#note-detail-wrapper");
|
||||||
|
const $noteIdDisplay = $("#note-id-display");
|
||||||
|
const $attributeList = $("#attribute-list");
|
||||||
|
const $attributeListInner = $("#attribute-list-inner");
|
||||||
|
const $attachmentFileName = $("#attachment-filename");
|
||||||
|
const $attachmentFileType = $("#attachment-filetype");
|
||||||
|
const $attachmentFileSize = $("#attachment-filesize");
|
||||||
|
const $attachmentDownload = $("#attachment-download");
|
||||||
|
const $attachmentOpen = $("#attachment-open");
|
||||||
|
|
||||||
let editor = null;
|
let editor = null;
|
||||||
let codeEditor = null;
|
let codeEditor = null;
|
||||||
@@ -80,14 +88,14 @@ const noteEditor = (function() {
|
|||||||
else if (note.detail.type === 'code') {
|
else if (note.detail.type === 'code') {
|
||||||
note.detail.content = codeEditor.getValue();
|
note.detail.content = codeEditor.getValue();
|
||||||
}
|
}
|
||||||
else if (note.detail.type === 'render') {
|
else if (note.detail.type === 'render' || note.detail.type === 'file') {
|
||||||
// nothing
|
// nothing
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throwError("Unrecognized type: " + note.detail.type);
|
throwError("Unrecognized type: " + note.detail.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = noteTitleEl.val();
|
const title = $noteTitle.val();
|
||||||
|
|
||||||
note.detail.title = title;
|
note.detail.title = title;
|
||||||
|
|
||||||
@@ -105,9 +113,9 @@ const noteEditor = (function() {
|
|||||||
function setNoteBackgroundIfProtected(note) {
|
function setNoteBackgroundIfProtected(note) {
|
||||||
const isProtected = !!note.detail.isProtected;
|
const isProtected = !!note.detail.isProtected;
|
||||||
|
|
||||||
noteDetailWrapperEl.toggleClass("protected", isProtected);
|
$noteDetailWrapper.toggleClass("protected", isProtected);
|
||||||
protectButton.toggle(!isProtected);
|
$protectButton.toggle(!isProtected);
|
||||||
unprotectButton.toggle(isProtected);
|
$unprotectButton.toggle(isProtected);
|
||||||
}
|
}
|
||||||
|
|
||||||
let isNewNoteCreated = false;
|
let isNewNoteCreated = false;
|
||||||
@@ -116,19 +124,43 @@ const noteEditor = (function() {
|
|||||||
isNewNoteCreated = true;
|
isNewNoteCreated = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function setContent(content) {
|
async function setContent(content) {
|
||||||
if (currentNote.detail.type === 'text') {
|
if (currentNote.detail.type === 'text') {
|
||||||
|
if (!editor) {
|
||||||
|
await requireLibrary(CKEDITOR);
|
||||||
|
|
||||||
|
editor = await BalloonEditor.create($noteDetail[0], {});
|
||||||
|
|
||||||
|
editor.document.on('change', noteChanged);
|
||||||
|
}
|
||||||
|
|
||||||
// temporary workaround for https://github.com/ckeditor/ckeditor5-enter/issues/49
|
// temporary workaround for https://github.com/ckeditor/ckeditor5-enter/issues/49
|
||||||
editor.setData(content ? content : "<p></p>");
|
editor.setData(content ? content : "<p></p>");
|
||||||
|
|
||||||
noteDetailEl.show();
|
$noteDetail.show();
|
||||||
noteDetailCodeEl.hide();
|
|
||||||
noteDetailRenderEl.html('').hide();
|
|
||||||
}
|
}
|
||||||
else if (currentNote.detail.type === 'code') {
|
else if (currentNote.detail.type === 'code') {
|
||||||
noteDetailEl.hide();
|
if (!codeEditor) {
|
||||||
noteDetailCodeEl.show();
|
await requireLibrary(CODE_MIRROR);
|
||||||
noteDetailRenderEl.html('').hide();
|
|
||||||
|
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
|
||||||
|
CodeMirror.keyMap.default["Tab"] = "indentMore";
|
||||||
|
|
||||||
|
CodeMirror.modeURL = 'libraries/codemirror/mode/%N/%N.js';
|
||||||
|
|
||||||
|
codeEditor = CodeMirror($("#note-detail-code")[0], {
|
||||||
|
value: "",
|
||||||
|
viewportMargin: Infinity,
|
||||||
|
indentUnit: 4,
|
||||||
|
matchBrackets: true,
|
||||||
|
matchTags: { bothTags: true },
|
||||||
|
highlightSelectionMatches: { showToken: /\w/, annotateScrollbar: false }
|
||||||
|
});
|
||||||
|
|
||||||
|
codeEditor.on('change', noteChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
$noteDetailCode.show();
|
||||||
|
|
||||||
// this needs to happen after the element is shown, otherwise the editor won't be refresheds
|
// this needs to happen after the element is shown, otherwise the editor won't be refresheds
|
||||||
codeEditor.setValue(content);
|
codeEditor.setValue(content);
|
||||||
@@ -148,10 +180,10 @@ const noteEditor = (function() {
|
|||||||
if (isNewNoteCreated) {
|
if (isNewNoteCreated) {
|
||||||
isNewNoteCreated = false;
|
isNewNoteCreated = false;
|
||||||
|
|
||||||
noteTitleEl.focus().select();
|
$noteTitle.focus().select();
|
||||||
}
|
}
|
||||||
|
|
||||||
noteIdDisplayEl.html(noteId);
|
$noteIdDisplay.html(noteId);
|
||||||
|
|
||||||
await protected_session.ensureProtectedSession(currentNote.detail.isProtected, false);
|
await protected_session.ensureProtectedSession(currentNote.detail.isProtected, false);
|
||||||
|
|
||||||
@@ -163,26 +195,36 @@ const noteEditor = (function() {
|
|||||||
// to login, but we chose instead to come to another node - at that point the dialog is still visible and this will close it.
|
// to login, but we chose instead to come to another node - at that point the dialog is still visible and this will close it.
|
||||||
protected_session.ensureDialogIsClosed();
|
protected_session.ensureDialogIsClosed();
|
||||||
|
|
||||||
noteDetailWrapperEl.show();
|
$noteDetailWrapper.show();
|
||||||
|
|
||||||
noteChangeDisabled = true;
|
noteChangeDisabled = true;
|
||||||
|
|
||||||
noteTitleEl.val(currentNote.detail.title);
|
$noteTitle.val(currentNote.detail.title);
|
||||||
|
|
||||||
noteType.setNoteType(currentNote.detail.type);
|
noteType.setNoteType(currentNote.detail.type);
|
||||||
noteType.setNoteMime(currentNote.detail.mime);
|
noteType.setNoteMime(currentNote.detail.mime);
|
||||||
|
|
||||||
|
$noteDetail.hide();
|
||||||
|
$noteDetailCode.hide();
|
||||||
|
$noteDetailRender.html('').hide();
|
||||||
|
$noteDetailAttachment.hide();
|
||||||
|
|
||||||
if (currentNote.detail.type === 'render') {
|
if (currentNote.detail.type === 'render') {
|
||||||
noteDetailEl.hide();
|
$noteDetailRender.show();
|
||||||
noteDetailCodeEl.hide();
|
|
||||||
noteDetailRenderEl.html('').show();
|
|
||||||
|
|
||||||
const subTree = await server.get('script/subtree/' + getCurrentNoteId());
|
const subTree = await server.get('script/subtree/' + getCurrentNoteId());
|
||||||
|
|
||||||
noteDetailRenderEl.html(subTree);
|
$noteDetailRender.html(subTree);
|
||||||
|
}
|
||||||
|
else if (currentNote.detail.type === 'file') {
|
||||||
|
$noteDetailAttachment.show();
|
||||||
|
|
||||||
|
$attachmentFileName.text(currentNote.attributes.original_file_name);
|
||||||
|
$attachmentFileSize.text(currentNote.attributes.file_size + " bytes");
|
||||||
|
$attachmentFileType.text(currentNote.detail.mime);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
setContent(currentNote.detail.content);
|
await setContent(currentNote.detail.content);
|
||||||
}
|
}
|
||||||
|
|
||||||
noteChangeDisabled = false;
|
noteChangeDisabled = false;
|
||||||
@@ -191,7 +233,7 @@ const noteEditor = (function() {
|
|||||||
noteTree.setNoteTreeBackgroundBasedOnProtectedStatus(noteId);
|
noteTree.setNoteTreeBackgroundBasedOnProtectedStatus(noteId);
|
||||||
|
|
||||||
// after loading new note make sure editor is scrolled to the top
|
// after loading new note make sure editor is scrolled to the top
|
||||||
noteDetailWrapperEl.scrollTop(0);
|
$noteDetailWrapper.scrollTop(0);
|
||||||
|
|
||||||
loadAttributeList();
|
loadAttributeList();
|
||||||
}
|
}
|
||||||
@@ -201,17 +243,17 @@ const noteEditor = (function() {
|
|||||||
|
|
||||||
const attributes = await server.get('notes/' + noteId + '/attributes');
|
const attributes = await server.get('notes/' + noteId + '/attributes');
|
||||||
|
|
||||||
attributeListInnerEl.html('');
|
$attributeListInner.html('');
|
||||||
|
|
||||||
if (attributes.length > 0) {
|
if (attributes.length > 0) {
|
||||||
for (const attr of attributes) {
|
for (const attr of attributes) {
|
||||||
attributeListInnerEl.append(formatAttribute(attr) + " ");
|
$attributeListInner.append(formatAttribute(attr) + " ");
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeListEl.show();
|
$attributeList.show();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
attributeListEl.hide();
|
$attributeList.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,12 +269,12 @@ const noteEditor = (function() {
|
|||||||
const note = getCurrentNote();
|
const note = getCurrentNote();
|
||||||
|
|
||||||
if (note.detail.type === 'text') {
|
if (note.detail.type === 'text') {
|
||||||
noteDetailEl.focus();
|
$noteDetail.focus();
|
||||||
}
|
}
|
||||||
else if (note.detail.type === 'code') {
|
else if (note.detail.type === 'code') {
|
||||||
codeEditor.focus();
|
codeEditor.focus();
|
||||||
}
|
}
|
||||||
else if (note.detail.type === 'render') {
|
else if (note.detail.type === 'render' || note.detail.type === 'file') {
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -257,45 +299,49 @@ const noteEditor = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$attachmentDownload.click(() => {
|
||||||
|
if (isElectron()) {
|
||||||
|
const remote = require('electron').remote;
|
||||||
|
|
||||||
|
remote.getCurrentWebContents().downloadURL(getAttachmentUrl());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.location.href = getAttachmentUrl();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$attachmentOpen.click(() => {
|
||||||
|
if (isElectron()) {
|
||||||
|
const open = require("open");
|
||||||
|
|
||||||
|
open(getAttachmentUrl());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.location.href = getAttachmentUrl();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function getAttachmentUrl() {
|
||||||
|
// electron needs absolute URL so we extract current host, port, protocol
|
||||||
|
const url = new URL(window.location.href);
|
||||||
|
const host = url.protocol + "//" + url.hostname + ":" + url.port;
|
||||||
|
|
||||||
|
const downloadUrl = "/api/attachments/download/" + getCurrentNoteId();
|
||||||
|
|
||||||
|
return host + downloadUrl;
|
||||||
|
}
|
||||||
|
|
||||||
$(document).ready(() => {
|
$(document).ready(() => {
|
||||||
noteTitleEl.on('input', () => {
|
$noteTitle.on('input', () => {
|
||||||
noteChanged();
|
noteChanged();
|
||||||
|
|
||||||
const title = noteTitleEl.val();
|
const title = $noteTitle.val();
|
||||||
|
|
||||||
noteTree.setNoteTitle(getCurrentNoteId(), title);
|
noteTree.setNoteTitle(getCurrentNoteId(), title);
|
||||||
});
|
});
|
||||||
|
|
||||||
BalloonEditor
|
|
||||||
.create(document.querySelector('#note-detail'), {
|
|
||||||
})
|
|
||||||
.then(edit => {
|
|
||||||
editor = edit;
|
|
||||||
|
|
||||||
editor.document.on('change', noteChanged);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error(error);
|
|
||||||
});
|
|
||||||
|
|
||||||
CodeMirror.keyMap.default["Shift-Tab"] = "indentLess";
|
|
||||||
CodeMirror.keyMap.default["Tab"] = "indentMore";
|
|
||||||
|
|
||||||
CodeMirror.modeURL = 'libraries/codemirror/mode/%N/%N.js';
|
|
||||||
|
|
||||||
codeEditor = CodeMirror($("#note-detail-code")[0], {
|
|
||||||
value: "",
|
|
||||||
viewportMargin: Infinity,
|
|
||||||
indentUnit: 4,
|
|
||||||
matchBrackets: true,
|
|
||||||
matchTags: { bothTags: true },
|
|
||||||
highlightSelectionMatches: { showToken: /\w/, annotateScrollbar: false }
|
|
||||||
});
|
|
||||||
|
|
||||||
codeEditor.on('change', noteChanged);
|
|
||||||
|
|
||||||
// so that tab jumps from note title (which has tabindex 1)
|
// so that tab jumps from note title (which has tabindex 1)
|
||||||
noteDetailEl.attr("tabindex", 2);
|
$noteDetail.attr("tabindex", 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
$(document).bind('keydown', "ctrl+return", executeCurrentNote);
|
$(document).bind('keydown', "ctrl+return", executeCurrentNote);
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const noteTree = (function() {
|
const noteTree = (function() {
|
||||||
const treeEl = $("#tree");
|
const $tree = $("#tree");
|
||||||
const parentListEl = $("#parent-list");
|
const $parentList = $("#parent-list");
|
||||||
const parentListListEl = $("#parent-list-inner");
|
const $parentListList = $("#parent-list-inner");
|
||||||
|
|
||||||
let startNotePath = null;
|
let startNotePath = null;
|
||||||
let notesTreeMap = {};
|
let notesTreeMap = {};
|
||||||
@@ -52,7 +52,7 @@ const noteTree = (function() {
|
|||||||
|
|
||||||
// note that if you want to access data like noteId or isProtected, you need to go into "data" property
|
// note that if you want to access data like noteId or isProtected, you need to go into "data" property
|
||||||
function getCurrentNode() {
|
function getCurrentNode() {
|
||||||
return treeEl.fancytree("getActiveNode");
|
return $tree.fancytree("getActiveNode");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentNotePath() {
|
function getCurrentNotePath() {
|
||||||
@@ -314,11 +314,11 @@ const noteTree = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (parents.length <= 1) {
|
if (parents.length <= 1) {
|
||||||
parentListEl.hide();
|
$parentList.hide();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parentListEl.show();
|
$parentList.show();
|
||||||
parentListListEl.empty();
|
$parentListList.empty();
|
||||||
|
|
||||||
for (const parentNoteId of parents) {
|
for (const parentNoteId of parents) {
|
||||||
const parentNotePath = getSomeNotePath(parentNoteId);
|
const parentNotePath = getSomeNotePath(parentNoteId);
|
||||||
@@ -335,7 +335,7 @@ const noteTree = (function() {
|
|||||||
item = link.createNoteLink(notePath, title);
|
item = link.createNoteLink(notePath, title);
|
||||||
}
|
}
|
||||||
|
|
||||||
parentListListEl.append($("<li/>").append(item));
|
$parentListList.append($("<li/>").append(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -543,7 +543,7 @@ const noteTree = (function() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
treeEl.fancytree({
|
$tree.fancytree({
|
||||||
autoScroll: true,
|
autoScroll: true,
|
||||||
keyboard: false, // we takover keyboard handling in the hotkeys plugin
|
keyboard: false, // we takover keyboard handling in the hotkeys plugin
|
||||||
extensions: ["hotkeys", "filter", "dnd", "clones"],
|
extensions: ["hotkeys", "filter", "dnd", "clones"],
|
||||||
@@ -624,11 +624,11 @@ const noteTree = (function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
treeEl.contextmenu(contextMenu.contextMenuSettings);
|
$tree.contextmenu(contextMenu.contextMenuSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTree() {
|
function getTree() {
|
||||||
return treeEl.fancytree('getTree');
|
return $tree.fancytree('getTree');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function reload() {
|
async function reload() {
|
||||||
@@ -663,7 +663,7 @@ const noteTree = (function() {
|
|||||||
|
|
||||||
function collapseTree(node = null) {
|
function collapseTree(node = null) {
|
||||||
if (!node) {
|
if (!node) {
|
||||||
node = treeEl.fancytree("getRootNode");
|
node = $tree.fancytree("getRootNode");
|
||||||
}
|
}
|
||||||
|
|
||||||
node.setExpanded(false);
|
node.setExpanded(false);
|
||||||
@@ -744,7 +744,7 @@ const noteTree = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function createNewTopLevelNote() {
|
async function createNewTopLevelNote() {
|
||||||
const rootNode = treeEl.fancytree("getRootNode");
|
const rootNode = $tree.fancytree("getRootNode");
|
||||||
|
|
||||||
await createNote(rootNode, "root", "into");
|
await createNote(rootNode, "root", "into");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const noteType = (function() {
|
const noteType = (function() {
|
||||||
const executeScriptButton = $("#execute-script-button");
|
const $executeScriptButton = $("#execute-script-button");
|
||||||
const noteTypeModel = new NoteTypeModel();
|
const noteTypeModel = new NoteTypeModel();
|
||||||
|
|
||||||
function NoteTypeModel() {
|
function NoteTypeModel() {
|
||||||
@@ -65,11 +65,18 @@ const noteType = (function() {
|
|||||||
else if (type === 'render') {
|
else if (type === 'render') {
|
||||||
return 'Render HTML note';
|
return 'Render HTML note';
|
||||||
}
|
}
|
||||||
|
else if (type === 'file') {
|
||||||
|
return 'Attachment';
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
throwError('Unrecognized type: ' + type);
|
throwError('Unrecognized type: ' + type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.isDisabled = function() {
|
||||||
|
return self.type() === "file";
|
||||||
|
};
|
||||||
|
|
||||||
async function save() {
|
async function save() {
|
||||||
const note = noteEditor.getCurrentNote();
|
const note = noteEditor.getCurrentNote();
|
||||||
|
|
||||||
@@ -114,7 +121,7 @@ const noteType = (function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
this.updateExecuteScriptButtonVisibility = function() {
|
this.updateExecuteScriptButtonVisibility = function() {
|
||||||
executeScriptButton.toggle(self.mime() === 'application/javascript');
|
$executeScriptButton.toggle(self.mime() === 'application/javascript');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const protected_session = (function() {
|
const protected_session = (function() {
|
||||||
const dialogEl = $("#protected-session-password-dialog");
|
const $dialog = $("#protected-session-password-dialog");
|
||||||
const passwordFormEl = $("#protected-session-password-form");
|
const $passwordForm = $("#protected-session-password-form");
|
||||||
const passwordEl = $("#protected-session-password");
|
const $password = $("#protected-session-password");
|
||||||
const noteDetailWrapperEl = $("#note-detail-wrapper");
|
const $noteDetailWrapper = $("#note-detail-wrapper");
|
||||||
|
|
||||||
let protectedSessionDeferred = null;
|
let protectedSessionDeferred = null;
|
||||||
let lastProtectedSessionOperationDate = null;
|
let lastProtectedSessionOperationDate = null;
|
||||||
@@ -25,9 +25,9 @@ const protected_session = (function() {
|
|||||||
if (requireProtectedSession && !isProtectedSessionAvailable()) {
|
if (requireProtectedSession && !isProtectedSessionAvailable()) {
|
||||||
protectedSessionDeferred = dfd;
|
protectedSessionDeferred = dfd;
|
||||||
|
|
||||||
noteDetailWrapperEl.hide();
|
$noteDetailWrapper.hide();
|
||||||
|
|
||||||
dialogEl.dialog({
|
$dialog.dialog({
|
||||||
modal: modal,
|
modal: modal,
|
||||||
width: 400,
|
width: 400,
|
||||||
open: () => {
|
open: () => {
|
||||||
@@ -46,8 +46,8 @@ const protected_session = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function setupProtectedSession() {
|
async function setupProtectedSession() {
|
||||||
const password = passwordEl.val();
|
const password = $password.val();
|
||||||
passwordEl.val("");
|
$password.val("");
|
||||||
|
|
||||||
const response = await enterProtectedSession(password);
|
const response = await enterProtectedSession(password);
|
||||||
|
|
||||||
@@ -58,15 +58,15 @@ const protected_session = (function() {
|
|||||||
|
|
||||||
protectedSessionId = response.protectedSessionId;
|
protectedSessionId = response.protectedSessionId;
|
||||||
|
|
||||||
dialogEl.dialog("close");
|
$dialog.dialog("close");
|
||||||
|
|
||||||
noteEditor.reload();
|
noteEditor.reload();
|
||||||
noteTree.reload();
|
noteTree.reload();
|
||||||
|
|
||||||
if (protectedSessionDeferred !== null) {
|
if (protectedSessionDeferred !== null) {
|
||||||
ensureDialogIsClosed(dialogEl, passwordEl);
|
ensureDialogIsClosed($dialog, $password);
|
||||||
|
|
||||||
noteDetailWrapperEl.show();
|
$noteDetailWrapper.show();
|
||||||
|
|
||||||
protectedSessionDeferred.resolve();
|
protectedSessionDeferred.resolve();
|
||||||
|
|
||||||
@@ -77,11 +77,11 @@ const protected_session = (function() {
|
|||||||
function ensureDialogIsClosed() {
|
function ensureDialogIsClosed() {
|
||||||
// this may fal if the dialog has not been previously opened
|
// this may fal if the dialog has not been previously opened
|
||||||
try {
|
try {
|
||||||
dialogEl.dialog('close');
|
$dialog.dialog('close');
|
||||||
}
|
}
|
||||||
catch (e) {}
|
catch (e) {}
|
||||||
|
|
||||||
passwordEl.val('');
|
$password.val('');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function enterProtectedSession(password) {
|
async function enterProtectedSession(password) {
|
||||||
@@ -155,7 +155,7 @@ const protected_session = (function() {
|
|||||||
noteEditor.reload();
|
noteEditor.reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
passwordFormEl.submit(() => {
|
$passwordForm.submit(() => {
|
||||||
setupProtectedSession();
|
setupProtectedSession();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const searchTree = (function() {
|
const searchTree = (function() {
|
||||||
const treeEl = $("#tree");
|
const $tree = $("#tree");
|
||||||
const searchInputEl = $("input[name='search-text']");
|
const $searchInput = $("input[name='search-text']");
|
||||||
const resetSearchButton = $("button#reset-search-button");
|
const $resetSearchButton = $("button#reset-search-button");
|
||||||
const searchBoxEl = $("#search-box");
|
const $searchBox = $("#search-box");
|
||||||
|
|
||||||
resetSearchButton.click(resetSearch);
|
$resetSearchButton.click(resetSearch);
|
||||||
|
|
||||||
function toggleSearch() {
|
function toggleSearch() {
|
||||||
if (searchBoxEl.is(":hidden")) {
|
if ($searchBox.is(":hidden")) {
|
||||||
searchBoxEl.show();
|
$searchBox.show();
|
||||||
searchInputEl.focus();
|
$searchInput.focus();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
resetSearch();
|
resetSearch();
|
||||||
|
|
||||||
searchBoxEl.hide();
|
$searchBox.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetSearch() {
|
function resetSearch() {
|
||||||
searchInputEl.val("");
|
$searchInput.val("");
|
||||||
|
|
||||||
getTree().clearFilter();
|
getTree().clearFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTree() {
|
function getTree() {
|
||||||
return treeEl.fancytree('getTree');
|
return $tree.fancytree('getTree');
|
||||||
}
|
}
|
||||||
|
|
||||||
searchInputEl.keyup(async e => {
|
$searchInput.keyup(async e => {
|
||||||
const searchText = searchInputEl.val();
|
const searchText = $searchInput.val();
|
||||||
|
|
||||||
if (e && e.which === $.ui.keyCode.ESCAPE || $.trim(searchText) === "") {
|
if (e && e.which === $.ui.keyCode.ESCAPE || $.trim(searchText) === "") {
|
||||||
resetSearchButton.click();
|
$resetSearchButton.click();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,12 +31,23 @@ const server = (function() {
|
|||||||
return await call('DELETE', url);
|
return await call('DELETE', url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function prepareParams(params) {
|
||||||
|
return params.map(p => {
|
||||||
|
if (typeof p === "function") {
|
||||||
|
return "!@#Function: " + p.toString();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function exec(params, script) {
|
async function exec(params, script) {
|
||||||
if (typeof script === "function") {
|
if (typeof script === "function") {
|
||||||
script = script.toString();
|
script = script.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
const ret = await post('script/exec', { script: script, params: params });
|
const ret = await post('script/exec', { script: script, params: prepareParams(params) });
|
||||||
|
|
||||||
return ret.executionResult;
|
return ret.executionResult;
|
||||||
}
|
}
|
||||||
@@ -105,6 +116,7 @@ const server = (function() {
|
|||||||
put,
|
put,
|
||||||
remove,
|
remove,
|
||||||
exec,
|
exec,
|
||||||
|
ajax,
|
||||||
// don't remove, used from CKEditor image upload!
|
// don't remove, used from CKEditor image upload!
|
||||||
getHeaders
|
getHeaders
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const treeUtils = (function() {
|
const treeUtils = (function() {
|
||||||
const treeEl = $("#tree");
|
const $tree = $("#tree");
|
||||||
|
|
||||||
function getParentProtectedStatus(node) {
|
function getParentProtectedStatus(node) {
|
||||||
return isTopLevelNode(node) ? 0 : node.getParent().data.isProtected;
|
return isTopLevelNode(node) ? 0 : node.getParent().data.isProtected;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNodeByKey(key) {
|
function getNodeByKey(key) {
|
||||||
return treeEl.fancytree('getNodeByKey', key);
|
return $tree.fancytree('getNodeByKey', key);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNoteIdFromNotePath(notePath) {
|
function getNoteIdFromNotePath(notePath) {
|
||||||
|
|||||||
@@ -116,8 +116,7 @@ async function stopWatch(what, func) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function executeScript(script) {
|
function executeScript(script) {
|
||||||
// last \r\n is necessary if script contains line comment on its last line
|
eval(script);
|
||||||
eval("(async function() {" + script + "\r\n})()");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatValueWithWhitespace(val) {
|
function formatValueWithWhitespace(val) {
|
||||||
@@ -132,4 +131,57 @@ function formatAttribute(attr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return str;
|
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"
|
||||||
|
],
|
||||||
|
css: [
|
||||||
|
"libraries/codemirror/codemirror.css"
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function requireScript(url) {
|
||||||
|
const scripts = Array
|
||||||
|
.from(document.querySelectorAll('script'))
|
||||||
|
.map(scr => scr.src);
|
||||||
|
|
||||||
|
if (!scripts.includes(url)) {
|
||||||
|
return $.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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -268,4 +268,9 @@ div.ui-tooltip {
|
|||||||
#attribute-list button {
|
#attribute-list button {
|
||||||
padding: 2px;
|
padding: 2px;
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#attachment-table th, #attachment-table td {
|
||||||
|
padding: 10px;
|
||||||
|
font-size: large;
|
||||||
}
|
}
|
||||||
61
src/routes/api/attachments.js
Normal file
61
src/routes/api/attachments.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
"use strict";
|
||||||
|
|
||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const sql = require('../../services/sql');
|
||||||
|
const auth = require('../../services/auth');
|
||||||
|
const notes = require('../../services/notes');
|
||||||
|
const attributes = require('../../services/attributes');
|
||||||
|
const multer = require('multer')();
|
||||||
|
const wrap = require('express-promise-wrap').wrap;
|
||||||
|
|
||||||
|
router.post('/upload/:parentNoteId', auth.checkApiAuthOrElectron, multer.single('upload'), wrap(async (req, res, next) => {
|
||||||
|
const sourceId = req.headers.source_id;
|
||||||
|
const parentNoteId = req.params.parentNoteId;
|
||||||
|
const file = req.file;
|
||||||
|
const originalName = file.originalname;
|
||||||
|
const size = file.size;
|
||||||
|
|
||||||
|
const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [parentNoteId]);
|
||||||
|
|
||||||
|
if (!note) {
|
||||||
|
return res.status(404).send(`Note ${parentNoteId} doesn't exist.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
await sql.doInTransaction(async () => {
|
||||||
|
const noteId = (await notes.createNewNote(parentNoteId, {
|
||||||
|
title: originalName,
|
||||||
|
content: file.buffer,
|
||||||
|
target: 'into',
|
||||||
|
isProtected: false,
|
||||||
|
type: 'file',
|
||||||
|
mime: file.mimetype
|
||||||
|
}, req, sourceId)).noteId;
|
||||||
|
|
||||||
|
await attributes.createAttribute(noteId, "original_file_name", originalName, sourceId);
|
||||||
|
await attributes.createAttribute(noteId, "file_size", size, sourceId);
|
||||||
|
|
||||||
|
res.send({
|
||||||
|
noteId: noteId
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
router.get('/download/:noteId', auth.checkApiAuthOrElectron, wrap(async (req, res, next) => {
|
||||||
|
const noteId = req.params.noteId;
|
||||||
|
const note = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]);
|
||||||
|
|
||||||
|
if (!note) {
|
||||||
|
return res.status(404).send(`Note ${parentNoteId} doesn't exist.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const attributeMap = await attributes.getNoteAttributeMap(noteId);
|
||||||
|
const fileName = attributeMap.original_file_name ? attributeMap.original_file_name : note.title;
|
||||||
|
|
||||||
|
res.setHeader('Content-Disposition', 'attachment; filename=' + fileName);
|
||||||
|
res.setHeader('Content-Type', note.mime);
|
||||||
|
|
||||||
|
res.send(note.content);
|
||||||
|
}));
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -5,6 +5,7 @@ const router = express.Router();
|
|||||||
const auth = require('../../services/auth');
|
const auth = require('../../services/auth');
|
||||||
const sql = require('../../services/sql');
|
const sql = require('../../services/sql');
|
||||||
const notes = require('../../services/notes');
|
const notes = require('../../services/notes');
|
||||||
|
const attributes = require('../../services/attributes');
|
||||||
const log = require('../../services/log');
|
const log = require('../../services/log');
|
||||||
const utils = require('../../services/utils');
|
const utils = require('../../services/utils');
|
||||||
const protected_session = require('../../services/protected_session');
|
const protected_session = require('../../services/protected_session');
|
||||||
@@ -25,8 +26,19 @@ router.get('/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => {
|
|||||||
|
|
||||||
protected_session.decryptNote(req, detail);
|
protected_session.decryptNote(req, detail);
|
||||||
|
|
||||||
|
let attributeMap = null;
|
||||||
|
|
||||||
|
if (detail.type === 'file') {
|
||||||
|
// no need to transfer attachment payload for this request
|
||||||
|
detail.content = null;
|
||||||
|
|
||||||
|
// attributes contain important attachment metadata - filename and size
|
||||||
|
attributeMap = await attributes.getNoteAttributeMap(noteId);
|
||||||
|
}
|
||||||
|
|
||||||
res.send({
|
res.send({
|
||||||
detail: detail
|
detail: detail,
|
||||||
|
attributes: attributeMap
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -31,26 +31,28 @@ router.get('/startup', auth.checkApiAuth, wrap(async (req, res, next) => {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
router.get('/subtree/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => {
|
router.get('/subtree/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||||
|
const repository = new Repository(req);
|
||||||
const noteId = req.params.noteId;
|
const noteId = req.params.noteId;
|
||||||
|
|
||||||
const repository = new Repository(req);
|
res.send(await getNoteWithSubtreeScript(noteId, repository));
|
||||||
|
|
||||||
const noteScript = (await repository.getNote(noteId)).content;
|
|
||||||
|
|
||||||
const subTreeScripts = await getSubTreeScripts(noteId, [noteId], repository);
|
|
||||||
|
|
||||||
res.send(subTreeScripts + noteScript);
|
|
||||||
}));
|
}));
|
||||||
|
|
||||||
async function getNoteWithSubtreeScript(noteId, repository) {
|
async function getNoteWithSubtreeScript(noteId, repository) {
|
||||||
const noteScript = (await repository.getNote(noteId)).content;
|
const note = await repository.getNote(noteId);
|
||||||
|
|
||||||
const subTreeScripts = await getSubTreeScripts(noteId, [noteId], repository);
|
let noteScript = note.content;
|
||||||
|
|
||||||
|
if (note.isJavaScript()) {
|
||||||
|
// last \r\n is necessary if script contains line comment on its last line
|
||||||
|
noteScript = "(async function() {" + noteScript + "\r\n})()";
|
||||||
|
}
|
||||||
|
|
||||||
|
const subTreeScripts = await getSubTreeScripts(noteId, [noteId], repository, note.isJavaScript());
|
||||||
|
|
||||||
return subTreeScripts + noteScript;
|
return subTreeScripts + noteScript;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSubTreeScripts(parentId, includedNoteIds, repository) {
|
async function getSubTreeScripts(parentId, includedNoteIds, repository, isJavaScript) {
|
||||||
const children = await repository.getEntities(`
|
const children = await repository.getEntities(`
|
||||||
SELECT notes.*
|
SELECT notes.*
|
||||||
FROM notes JOIN note_tree USING(noteId)
|
FROM notes JOIN note_tree USING(noteId)
|
||||||
@@ -69,7 +71,7 @@ async function getSubTreeScripts(parentId, includedNoteIds, repository) {
|
|||||||
|
|
||||||
script += await getSubTreeScripts(child.noteId, includedNoteIds, repository);
|
script += await getSubTreeScripts(child.noteId, includedNoteIds, repository);
|
||||||
|
|
||||||
if (child.mime === 'application/javascript') {
|
if (!isJavaScript && child.mime === 'application/javascript') {
|
||||||
child.content = '<script>' + child.content + '</script>';
|
child.content = '<script>' + child.content + '</script>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -79,9 +79,12 @@ router.get('/changed', auth.checkApiAuth, wrap(async (req, res, next) => {
|
|||||||
|
|
||||||
router.get('/notes/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => {
|
router.get('/notes/:noteId', auth.checkApiAuth, wrap(async (req, res, next) => {
|
||||||
const noteId = req.params.noteId;
|
const noteId = req.params.noteId;
|
||||||
|
const entity = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId]);
|
||||||
|
|
||||||
|
sync.serializeNoteContentBuffer(entity);
|
||||||
|
|
||||||
res.send({
|
res.send({
|
||||||
entity: await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [noteId])
|
entity: entity
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ const imageRoute = require('./api/image');
|
|||||||
const attributesRoute = require('./api/attributes');
|
const attributesRoute = require('./api/attributes');
|
||||||
const scriptRoute = require('./api/script');
|
const scriptRoute = require('./api/script');
|
||||||
const senderRoute = require('./api/sender');
|
const senderRoute = require('./api/sender');
|
||||||
|
const attachmentsRoute = require('./api/attachments');
|
||||||
|
|
||||||
function register(app) {
|
function register(app) {
|
||||||
app.use('/', indexRoute);
|
app.use('/', indexRoute);
|
||||||
@@ -61,6 +62,7 @@ function register(app) {
|
|||||||
app.use('/api/images', imageRoute);
|
app.use('/api/images', imageRoute);
|
||||||
app.use('/api/script', scriptRoute);
|
app.use('/api/script', scriptRoute);
|
||||||
app.use('/api/sender', senderRoute);
|
app.use('/api/sender', senderRoute);
|
||||||
|
app.use('/api/attachments', attachmentsRoute);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<form id="weight-form" style="display: flex; width: 500px; justify-content: space-around; align-items: flex-end;">
|
<form id="weight-form" style="display: flex; width: 700px; justify-content: space-around; align-items: flex-end;">
|
||||||
<div>
|
<div>
|
||||||
<label for="weight-date">Date</label>
|
<label for="weight-date">Date</label>
|
||||||
<input type="text" id="weight-date" class="form-control" style="width: 150px; text-align: center;" />
|
<input type="text" id="weight-date" class="form-control" style="width: 150px; text-align: center;" />
|
||||||
@@ -7,6 +7,10 @@
|
|||||||
<label for="weight">Weight</label>
|
<label for="weight">Weight</label>
|
||||||
<input type="number" id="weight" value="80.0" step="0.1" class="form-control" style="text-align: center; width: 100px;" />
|
<input type="number" id="weight" value="80.0" step="0.1" class="form-control" style="text-align: center; width: 100px;" />
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="comment">Comment</label>
|
||||||
|
<input type="text" id="comment" class="form-control" style="width: 200px;" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<button type="submit" class="btn btn-primary">Add</button>
|
<button type="submit" class="btn btn-primary">Add</button>
|
||||||
</form>
|
</form>
|
||||||
@@ -16,84 +20,127 @@
|
|||||||
<canvas id="canvas"></canvas>
|
<canvas id="canvas"></canvas>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
(async function() {
|
(async function() {
|
||||||
const dateEl = $("#weight-date");
|
const $form = $("#weight-form");
|
||||||
const weightEl = $("#weight");
|
const $date = $("#weight-date");
|
||||||
|
const $weight = $("#weight");
|
||||||
|
const $comment = $("#comment");
|
||||||
|
let chart;
|
||||||
|
|
||||||
dateEl.datepicker();
|
$date.datepicker();
|
||||||
dateEl.datepicker('option', 'dateFormat', 'yy-mm-dd');
|
$date.datepicker('option', 'dateFormat', 'yy-mm-dd');
|
||||||
dateEl.datepicker('setDate', new Date());
|
$date.datepicker('setDate', new Date());
|
||||||
|
|
||||||
async function saveWeight() {
|
async function saveWeight() {
|
||||||
await server.exec([dateEl.val(), weightEl.val()], async (date, weight) => {
|
await server.exec([$date.val(), parseFloat($weight.val()), $comment.val()], async (date, weight, comment) => {
|
||||||
const dataNote = await this.getNoteWithAttribute('date_data', date);
|
const dataNote = await this.getNoteWithAttribute('date_data', date);
|
||||||
|
|
||||||
if (dataNote) {
|
if (dataNote) {
|
||||||
dataNote.jsonContent.weight = weight;
|
dataNote.jsonContent.weight = weight;
|
||||||
|
|
||||||
await this.updateEntity(dataNote);
|
if (comment) {
|
||||||
}
|
dataNote.jsonContent.weight_comment = comment;
|
||||||
else {
|
|
||||||
const parentNoteId = await this.getDateNoteId(date);
|
|
||||||
const jsonContent = { weight: weight };
|
|
||||||
|
|
||||||
await this.createNote(parentNoteId, 'data', jsonContent, {
|
|
||||||
json: true,
|
|
||||||
attributes: {
|
|
||||||
date_data: date,
|
|
||||||
hide_in_autocomplete: null
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
showMessage("Weight has been saved");
|
await this.updateEntity(dataNote);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const parentNoteId = await this.getDateNoteId(date);
|
||||||
|
const jsonContent = { weight: weight };
|
||||||
|
|
||||||
|
if (comment) {
|
||||||
|
jsonContent.weight_comment = comment;
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.createNote(parentNoteId, 'data', jsonContent, {
|
||||||
|
json: true,
|
||||||
|
attributes: {
|
||||||
|
date_data: date,
|
||||||
|
hide_in_autocomplete: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
showMessage("Weight has been saved");
|
||||||
|
|
||||||
|
chart.data = await getData();
|
||||||
|
chart.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function drawChart() {
|
||||||
|
const data = await getData();
|
||||||
|
|
||||||
|
const ctx = $("#canvas")[0].getContext("2d");
|
||||||
|
|
||||||
|
chart = new Chart(ctx, {
|
||||||
|
type: 'line',
|
||||||
|
data: data,
|
||||||
|
options: {
|
||||||
|
tooltips: {
|
||||||
|
enabled: true,
|
||||||
|
mode: 'single',
|
||||||
|
callbacks: {
|
||||||
|
label: function (tooltipItem, data) {
|
||||||
|
const multistringText = [tooltipItem.yLabel];
|
||||||
|
const comment = data.comments[tooltipItem['index']];
|
||||||
|
|
||||||
|
if (comment) {
|
||||||
|
multistringText.push(comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistringText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getData() {
|
||||||
|
const data = await server.exec([], async () => {
|
||||||
|
const notes = await this.getNotesWithAttribute('date_data');
|
||||||
|
const data = [];
|
||||||
|
|
||||||
|
for (const note of notes) {
|
||||||
|
const dateAttr = await note.getAttribute('date_data');
|
||||||
|
|
||||||
|
data.push({
|
||||||
|
date: dateAttr.value,
|
||||||
|
weight: note.jsonContent.weight,
|
||||||
|
comment: note.jsonContent.weight_comment
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
data.sort((a, b) => a.date < b.date ? -1 : +1);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
});
|
||||||
|
|
||||||
|
const datasets = [{
|
||||||
|
label: "Weight",
|
||||||
|
backgroundColor: 'red',
|
||||||
|
borderColor: 'red',
|
||||||
|
data: data.map(row => row.weight),
|
||||||
|
fill: false
|
||||||
|
}];
|
||||||
|
|
||||||
|
const labels = data.map(row => row.date);
|
||||||
|
const comments = data.map(row => row.comment);
|
||||||
|
|
||||||
|
return {
|
||||||
|
labels: labels,
|
||||||
|
datasets: datasets,
|
||||||
|
comments: comments
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
$form.submit(event => {
|
||||||
|
saveWeight();
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
drawChart();
|
drawChart();
|
||||||
}
|
})();
|
||||||
|
|
||||||
async function drawChart() {
|
|
||||||
const data = await server.exec([], async () => {
|
|
||||||
const notes = await this.getNotesWithAttribute('date_data');
|
|
||||||
const data = [];
|
|
||||||
|
|
||||||
for (const note of notes) {
|
|
||||||
const dateAttr = await note.getAttribute('date_data');
|
|
||||||
|
|
||||||
data.push({
|
|
||||||
date: dateAttr.value,
|
|
||||||
weight: note.jsonContent.weight
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
data.sort((a, b) => a.date < b.date ? -1 : +1);
|
|
||||||
|
|
||||||
return data;
|
|
||||||
});
|
|
||||||
|
|
||||||
const ctx = $("#canvas")[0].getContext("2d");
|
|
||||||
|
|
||||||
new Chart(ctx, {
|
|
||||||
type: 'line',
|
|
||||||
data: {
|
|
||||||
labels: data.map(row => row.date),
|
|
||||||
datasets: [{
|
|
||||||
label: "Weight",
|
|
||||||
backgroundColor: 'red',
|
|
||||||
borderColor: 'red',
|
|
||||||
data: data.map(row => row.weight),
|
|
||||||
fill: false
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
$("#weight-form").submit(event => {
|
|
||||||
saveWeight();
|
|
||||||
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
drawChart();
|
|
||||||
})();
|
|
||||||
</script>
|
</script>
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
const build = require('./build');
|
const build = require('./build');
|
||||||
const packageJson = require('../../package');
|
const packageJson = require('../../package');
|
||||||
|
|
||||||
const APP_DB_VERSION = 76;
|
const APP_DB_VERSION = 77;
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
app_version: packageJson.version,
|
app_version: packageJson.version,
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ const BUILTIN_ATTRIBUTES = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function getNoteAttributeMap(noteId) {
|
async function getNoteAttributeMap(noteId) {
|
||||||
return await sql.getMap(`SELECT name, value FROM attributes WHERE noteId = ?`, [noteId]);
|
return await sql.getMap(`SELECT name, value FROM attributes WHERE noteId = ? AND isDeleted = 0`, [noteId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getNoteIdWithAttribute(name, value) {
|
async function getNoteIdWithAttribute(name, value) {
|
||||||
@@ -52,7 +52,11 @@ async function getNoteIdsWithAttribute(name) {
|
|||||||
WHERE notes.isDeleted = 0 AND attributes.isDeleted = 0 AND attributes.name = ? AND attributes.isDeleted = 0`, [name]);
|
WHERE notes.isDeleted = 0 AND attributes.isDeleted = 0 AND attributes.name = ? AND attributes.isDeleted = 0`, [name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createAttribute(noteId, name, value = null, sourceId = null) {
|
async function createAttribute(noteId, name, value = "", sourceId = null) {
|
||||||
|
if (value === null || value === undefined) {
|
||||||
|
value = "";
|
||||||
|
}
|
||||||
|
|
||||||
const now = utils.nowDate();
|
const now = utils.nowDate();
|
||||||
const attributeId = utils.newAttributeId();
|
const attributeId = utils.newAttributeId();
|
||||||
|
|
||||||
|
|||||||
@@ -214,7 +214,7 @@ async function runAllChecks() {
|
|||||||
FROM
|
FROM
|
||||||
notes
|
notes
|
||||||
WHERE
|
WHERE
|
||||||
type != 'text' AND type != 'code' AND type != 'render'`,
|
type != 'text' AND type != 'code' AND type != 'render' AND type != 'file'`,
|
||||||
"Note has invalid type", errorList);
|
"Note has invalid type", errorList);
|
||||||
|
|
||||||
await runSyncRowChecks("notes", "noteId", errorList);
|
await runSyncRowChecks("notes", "noteId", errorList);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ function info(message) {
|
|||||||
|
|
||||||
function error(message) {
|
function error(message) {
|
||||||
// we're using .info() instead of .error() because simple-node-logger emits weird error for showError()
|
// we're using .info() instead of .error() because simple-node-logger emits weird error for showError()
|
||||||
info(message);
|
info("ERROR: " + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
const requestBlacklist = [ "/libraries", "/javascripts", "/images", "/stylesheets" ];
|
const requestBlacklist = [ "/libraries", "/javascripts", "/images", "/stylesheets" ];
|
||||||
|
|||||||
@@ -19,7 +19,14 @@ async function executeScript(dataKey, script, params) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getParams(params) {
|
function getParams(params) {
|
||||||
return params.map(p => JSON.stringify(p)).join(",");
|
return params.map(p => {
|
||||||
|
if (typeof p === "string" && p.startsWith("!@#Function: ")) {
|
||||||
|
return p.substr(13);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return JSON.stringify(p);
|
||||||
|
}
|
||||||
|
}).join(",");
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -204,6 +204,8 @@ async function pushEntity(sync, syncContext) {
|
|||||||
|
|
||||||
if (sync.entityName === 'notes') {
|
if (sync.entityName === 'notes') {
|
||||||
entity = await sql.getRow('SELECT * FROM notes WHERE noteId = ?', [sync.entityId]);
|
entity = await sql.getRow('SELECT * FROM notes WHERE noteId = ?', [sync.entityId]);
|
||||||
|
|
||||||
|
serializeNoteContentBuffer(entity);
|
||||||
}
|
}
|
||||||
else if (sync.entityName === 'note_tree') {
|
else if (sync.entityName === 'note_tree') {
|
||||||
entity = await sql.getRow('SELECT * FROM note_tree WHERE noteTreeId = ?', [sync.entityId]);
|
entity = await sql.getRow('SELECT * FROM note_tree WHERE noteTreeId = ?', [sync.entityId]);
|
||||||
@@ -258,6 +260,12 @@ async function pushEntity(sync, syncContext) {
|
|||||||
await syncRequest(syncContext, 'PUT', '/api/sync/' + sync.entityName, payload);
|
await syncRequest(syncContext, 'PUT', '/api/sync/' + sync.entityName, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function serializeNoteContentBuffer(note) {
|
||||||
|
if (note.type === 'file') {
|
||||||
|
note.content = note.content.toString("binary");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function checkContentHash(syncContext) {
|
async function checkContentHash(syncContext) {
|
||||||
const resp = await syncRequest(syncContext, 'GET', '/api/sync/check');
|
const resp = await syncRequest(syncContext, 'GET', '/api/sync/check');
|
||||||
|
|
||||||
@@ -350,5 +358,6 @@ sql.dbReady.then(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
sync
|
sync,
|
||||||
|
serializeNoteContentBuffer
|
||||||
};
|
};
|
||||||
@@ -1,10 +1,17 @@
|
|||||||
const sql = require('./sql');
|
const sql = require('./sql');
|
||||||
const log = require('./log');
|
const log = require('./log');
|
||||||
const eventLog = require('./event_log');
|
const eventLog = require('./event_log');
|
||||||
const notes = require('./notes');
|
|
||||||
const sync_table = require('./sync_table');
|
const sync_table = require('./sync_table');
|
||||||
|
|
||||||
|
function deserializeNoteContentBuffer(note) {
|
||||||
|
if (note.type === 'file') {
|
||||||
|
note.content = new Buffer(note.content, 'binary');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function updateNote(entity, sourceId) {
|
async function updateNote(entity, sourceId) {
|
||||||
|
deserializeNoteContentBuffer(entity);
|
||||||
|
|
||||||
const origNote = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [entity.noteId]);
|
const origNote = await sql.getRow("SELECT * FROM notes WHERE noteId = ?", [entity.noteId]);
|
||||||
|
|
||||||
if (!origNote || origNote.dateModified <= entity.dateModified) {
|
if (!origNote || origNote.dateModified <= entity.dateModified) {
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
onclick="noteEditor.executeCurrentNote()">Execute <kbd>Ctrl+Enter</kbd></button>
|
onclick="noteEditor.executeCurrentNote()">Execute <kbd>Ctrl+Enter</kbd></button>
|
||||||
|
|
||||||
<div class="dropdown" id="note-type">
|
<div class="dropdown" id="note-type">
|
||||||
<button id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-sm">
|
<button data-bind="disable: isDisabled()" id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-sm">
|
||||||
Type: <span data-bind="text: typeString()"></span>
|
Type: <span data-bind="text: typeString()"></span>
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
@@ -130,6 +130,7 @@
|
|||||||
<li><a onclick="noteHistory.showCurrentNoteHistory();"><kbd>Alt+H</kbd> History</a></li>
|
<li><a onclick="noteHistory.showCurrentNoteHistory();"><kbd>Alt+H</kbd> History</a></li>
|
||||||
<li><a onclick="attributesDialog.showDialog();"><kbd>Alt+A</kbd> Attributes</a></li>
|
<li><a onclick="attributesDialog.showDialog();"><kbd>Alt+A</kbd> Attributes</a></li>
|
||||||
<li><a onclick="noteSource.showDialog();"><kbd>Ctrl+U</kbd> HTML source</a></li>
|
<li><a onclick="noteSource.showDialog();"><kbd>Ctrl+U</kbd> HTML source</a></li>
|
||||||
|
<li><a onclick="uploadAttachment();">Upload attachment</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -141,6 +142,32 @@
|
|||||||
<div id="note-detail-code"></div>
|
<div id="note-detail-code"></div>
|
||||||
|
|
||||||
<div id="note-detail-render"></div>
|
<div id="note-detail-render"></div>
|
||||||
|
|
||||||
|
<div id="note-detail-attachment">
|
||||||
|
<table id="attachment-table">
|
||||||
|
<tr>
|
||||||
|
<th>File name:</th>
|
||||||
|
<td id="attachment-filename"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>File type:</th>
|
||||||
|
<td id="attachment-filetype"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>File size:</th>
|
||||||
|
<td id="attachment-filesize"></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<button id="attachment-download" class="btn btn-primary" type="button">Download</button>
|
||||||
|
|
||||||
|
<button id="attachment-open" class="btn btn-primary" type="button">Open</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<input type="file" id="file-upload" style="display: none" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="attribute-list">
|
<div id="attribute-list">
|
||||||
@@ -449,8 +476,6 @@
|
|||||||
<link href="libraries/fancytree/skin-win8/ui.fancytree.css" rel="stylesheet">
|
<link href="libraries/fancytree/skin-win8/ui.fancytree.css" rel="stylesheet">
|
||||||
<script src="libraries/fancytree/jquery.fancytree-all.min.js"></script>
|
<script src="libraries/fancytree/jquery.fancytree-all.min.js"></script>
|
||||||
|
|
||||||
<script src="libraries/ckeditor/ckeditor.js"></script>
|
|
||||||
|
|
||||||
<script src="libraries/jquery.hotkeys.js"></script>
|
<script src="libraries/jquery.hotkeys.js"></script>
|
||||||
<script src="libraries/jquery.fancytree.hotkeys.js"></script>
|
<script src="libraries/jquery.fancytree.hotkeys.js"></script>
|
||||||
|
|
||||||
@@ -458,15 +483,6 @@
|
|||||||
|
|
||||||
<script src="libraries/knockout.min.js"></script>
|
<script src="libraries/knockout.min.js"></script>
|
||||||
|
|
||||||
<script src="libraries/codemirror/codemirror.js"></script>
|
|
||||||
<link rel="stylesheet" href="libraries/codemirror/codemirror.css">
|
|
||||||
<script src="libraries/codemirror/addon/mode/loadmode.js"></script>
|
|
||||||
<script src="libraries/codemirror/addon/fold/xml-fold.js"></script>
|
|
||||||
<script src="libraries/codemirror/addon/edit/matchbrackets.js"></script>
|
|
||||||
<script src="libraries/codemirror/addon/edit/matchtags.js"></script>
|
|
||||||
<script src="libraries/codemirror/addon/search/match-highlighter.js"></script>
|
|
||||||
<script src="libraries/codemirror/mode/meta.js"></script>
|
|
||||||
|
|
||||||
<link href="stylesheets/style.css" rel="stylesheet">
|
<link href="stylesheets/style.css" rel="stylesheet">
|
||||||
|
|
||||||
<script src="javascripts/utils.js"></script>
|
<script src="javascripts/utils.js"></script>
|
||||||
|
|||||||
Reference in New Issue
Block a user