Compare commits

...

40 Commits

Author SHA1 Message Date
zadam
13e9f9f9e7 release 0.33.7 2019-07-11 20:55:56 +02:00
zadam
a76dcb44ae improvements in the exported file extensions 2019-07-11 20:54:57 +02:00
zadam
b9373806cf fix doubling of extension 2019-07-11 20:40:40 +02:00
zadam
9de2927304 image import/export related fixes 2019-07-10 23:01:30 +02:00
zadam
c3e1126489 backported image fixes 2019-07-10 20:38:27 +02:00
zadam
3413c9ed64 backport notePath handling fixes from master 2019-07-10 20:35:01 +02:00
zadam
ddf381f92d fixed duplicated notes after creating into a folder which wasn't yet loaded 2019-07-06 13:14:33 +02:00
zadam
2b44f3bc76 fixed websocket reconnection 2019-07-06 12:03:51 +02:00
zadam
bf3360572a nest code editor instance to avoid visibility issues 2019-07-03 20:37:59 +02:00
zadam
e5036318af fix enter on title to the code editor 2019-07-03 20:29:55 +02:00
zadam
6d2394a9da release 0.33.6 2019-07-02 22:26:05 +02:00
zadam
196264b8c2 use bootstrap modal to confirm note deletion which fixes #582 2019-07-02 21:54:37 +02:00
zadam
afe24866f0 some debug logging for duplicated nodes 2019-07-02 20:35:06 +02:00
zadam
d18a20cc06 fix focus issue from title to the text content with tab/enter 2019-07-02 20:28:57 +02:00
zadam
9c91b0459e release 0.33.5 2019-06-30 21:47:04 +02:00
zadam
af21dd4463 fix mobile text editor display 2019-06-30 20:14:57 +02:00
zadam
1ea0d283de fix text instance sometimes remaining displayed when switching to e.g. image 2019-06-30 19:41:26 +02:00
zadam
6e3d8472e1 avoid duplicate key error 2019-06-28 21:50:15 +02:00
zadam
2a9f36a027 fix activating parent note after delete 2019-06-27 22:58:04 +02:00
zadam
cf3726289c attempt to fix the duplicate issue 2019-06-27 21:24:25 +02:00
zadam
c8e4a5c9e7 release 0.33.4 2019-06-26 21:20:30 +02:00
zadam
a3951f1cce make sure autocomplete is closed when navigating to note 2019-06-26 21:08:54 +02:00
zadam
7c77ae758b fix frontend reload again 2019-06-26 20:49:17 +02:00
zadam
20d3d61cec release 0.33.3 2019-06-24 20:47:50 +02:00
zadam
1b831f94a9 fix orphan note autocomplete, closes #569 2019-06-24 20:45:35 +02:00
zadam
3f241553aa fix pngquant for linux-x64 2019-06-24 20:27:28 +02:00
zadam
8624c83108 use 127.0.0.1 instead of localhost, #577 2019-06-24 20:26:28 +02:00
zadam
d49cae9cea fix update of window title during note renaming 2019-06-24 20:12:04 +02:00
zadam
504b2e2c4a Merge pull request #574 from maurerit/master
Build failed without python for arm
2019-06-21 09:10:17 +02:00
Matt Maurer
2c5292222f Build failed without python for arm 2019-06-20 23:45:31 +00:00
zadam
989da8877b added link map 2019-06-20 10:20:44 +02:00
zadam
70591eadd5 release 0.33.2-beta 2019-06-20 09:39:11 +02:00
zadam
fead3cd7ad fix note export/import/branch prefix to use right-clicked note as opposed to current active 2019-06-20 09:37:18 +02:00
zadam
a7cf3cdf05 fix unloading protected session after the timeout, fixes #571 2019-06-19 22:23:55 +02:00
zadam
5372f71faa hide menu bar 2019-06-19 20:45:19 +02:00
zadam
3b76939f17 distinction between unfocused active and hovered node - unfocused active has dashed border 2019-06-17 22:30:26 +02:00
zadam
c827d38f39 when single note is selected and it's the same that was right clicked for context menu, then we treat it as no-selection action 2019-06-17 22:25:22 +02:00
zadam
1e7586fae4 context menu items are now disabled when there are selected notes and the item does not support actions on multiple items 2019-06-17 20:34:00 +02:00
zadam
ee89111bfb fix clipboard operation for single nodes 2019-06-16 18:07:22 +02:00
zadam
288b3077b2 context menu items are now disabled when there are selected notes and the item does not support actions on multiple items 2019-06-16 12:06:06 +02:00
38 changed files with 331 additions and 263 deletions

View File

@@ -18,6 +18,7 @@ RUN set -x \
make \
nasm \
libpng-dev \
python \
&& npm install --production \
&& apk del .build-dependencies

View File

@@ -24,7 +24,7 @@ Trilium Notes is a hierarchical note taking application with focus on building l
## Builds
Trilium is provided as either desktop application (Linux, Windows, Mac) or web application hosted on your server (Linux).
Trilium is provided as either desktop application (Linux and Windows) or web application hosted on your server (Linux). Mac OS desktop build is available, but it is [unsupported](https://github.com/zadam/trilium/wiki/FAQ#mac-os-support).
* If you want to use Trilium on the desktop, download binary release for your platform from [latest release](https://github.com/zadam/trilium/releases/latest), unzip the package and run ```trilium``` executable.
* If you want to install Trilium on server, follow [this page](https://github.com/zadam/trilium/wiki/Server-installation).

View File

@@ -7,6 +7,9 @@ rm -r node_modules/sqlite3/lib/binding/*
cp -r bin/deps/linux-x64/sqlite/* node_modules/sqlite3/lib/binding/
# rebuild binaries for image operations (pngquant ...)
npm rebuild
./node_modules/.bin/electron-packager . --asar --out=dist --executable-name=trilium --platform=linux --arch=x64 --overwrite
mv "./dist/Trilium Notes-linux-x64" $BUILD_DIR

View File

@@ -58,8 +58,8 @@ async function createMainWindow() {
mainWindowState.manage(win);
win.setMenu(null);
win.loadURL('http://localhost:' + await port);
win.setMenuBarVisibility(false);
win.loadURL('http://127.0.0.1:' + await port);
win.on('closed', onClosed);
win.webContents.on('new-window', (e, url) => {
@@ -74,7 +74,7 @@ async function createMainWindow() {
const parsedUrl = url.parse(targetUrl);
// we still need to allow internal redirects from setup and migration pages
if (parsedUrl.hostname !== 'localhost' || (parsedUrl.path && parsedUrl.path !== '/')) {
if (!['localhost', '127.0.0.1'].includes(parsedUrl.hostname) || (parsedUrl.path && parsedUrl.path !== '/')) {
ev.preventDefault();
}
});

File diff suppressed because one or more lines are too long

217
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "trilium",
"version": "0.33.0-beta",
"version": "0.33.6",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -589,32 +589,32 @@
"integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg=="
},
"app-builder-bin": {
"version": "2.6.6",
"resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-2.6.6.tgz",
"integrity": "sha512-G0Ee6xkbxV+fvM/7xXWIgSDjWAD4E/d/aNbxerq/TVsCyBIau/0VPmrEqBMyZv0NbTwLDW5aF/yHG+0ZEY77kA==",
"version": "2.6.16",
"resolved": "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-2.6.16.tgz",
"integrity": "sha512-TSq2/AwXbFI+jK4SPRRASZEpZ32HsrugxuCzHshnZ3Wj5LDVIAMU3EGXfaciXWx7TV047G69RlA4/Y8OiHBn3w==",
"dev": true
},
"app-builder-lib": {
"version": "20.43.0",
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-20.43.0.tgz",
"integrity": "sha512-8OhRPGbTFsgBn07mcG1x0FApqsLLQkNMrdl2sBPo/haI/E1QqhN4DU5x7nKbbFwnsG2XvqvBBZwnMV3FXgDi9Q==",
"version": "20.44.2",
"resolved": "https://registry.npmjs.org/app-builder-lib/-/app-builder-lib-20.44.2.tgz",
"integrity": "sha512-84AEt+k/edrwHwFtaXx8SGAC9ZdMJabx5xf2VGM8L8sFYbBPJppl4G6TieHqpPhDURbPXqL710HKEA/lyiEIRQ==",
"dev": true,
"requires": {
"7zip-bin": "~4.1.0",
"app-builder-bin": "2.6.6",
"app-builder-bin": "2.6.16",
"async-exit-hook": "^2.0.1",
"bluebird-lst": "^1.0.9",
"builder-util": "10.0.2",
"builder-util-runtime": "8.2.4",
"builder-util": "10.1.0",
"builder-util-runtime": "8.2.5",
"chromium-pickle-js": "^0.2.0",
"debug": "^4.1.1",
"ejs": "^2.6.1",
"ejs": "^2.6.2",
"electron-osx-sign": "0.4.11",
"electron-publish": "20.43.0",
"electron-publish": "20.44.2",
"fs-extra-p": "^8.0.2",
"hosted-git-info": "^2.7.1",
"is-ci": "^2.0.0",
"isbinaryfile": "^4.0.0",
"isbinaryfile": "^4.0.1",
"js-yaml": "^3.13.1",
"lazy-val": "^1.0.4",
"minimatch": "^3.0.4",
@@ -623,7 +623,7 @@
"read-config-file": "3.2.2",
"sanitize-filename": "^1.6.1",
"semver": "^6.1.1",
"temp-file": "^3.3.2"
"temp-file": "^3.3.3"
},
"dependencies": {
"ci-info": {
@@ -678,9 +678,9 @@
}
},
"resolve": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz",
"integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==",
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz",
"integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==",
"dev": true,
"requires": {
"path-parse": "^1.0.6"
@@ -713,7 +713,7 @@
"dependencies": {
"file-type": {
"version": "3.9.0",
"resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek="
}
}
@@ -1022,7 +1022,7 @@
},
"uuid": {
"version": "2.0.3",
"resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
"integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
}
}
@@ -1056,7 +1056,7 @@
"dependencies": {
"semver": {
"version": "4.3.6",
"resolved": "http://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
"integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto="
}
}
@@ -1076,7 +1076,7 @@
},
"bl": {
"version": "1.2.2",
"resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
"requires": {
"readable-stream": "^2.3.5",
@@ -1375,27 +1375,27 @@
"dependencies": {
"file-type": {
"version": "3.9.0",
"resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek="
},
"uuid": {
"version": "2.0.3",
"resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
"integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
}
}
},
"builder-util": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-10.0.2.tgz",
"integrity": "sha512-Dt11O/MTdCsaCjAdnkVVcDSSkQEkvPWAs18sNQBc6l6wt5RvzcI4nfgpLxwbUi/DkCpHCltUgIj94TLQXQv1bw==",
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/builder-util/-/builder-util-10.1.0.tgz",
"integrity": "sha512-M+XnPGbVKSssgxgejtcrCPr7BcJfTyZZYf9yJ8r3o3kDJfBcF0ShaxyuOk956PnAUuanRGtfhZb4cD6dx+x1jA==",
"dev": true,
"requires": {
"7zip-bin": "~4.1.0",
"@types/debug": "^4.1.4",
"app-builder-bin": "2.6.6",
"app-builder-bin": "2.6.16",
"bluebird-lst": "^1.0.9",
"builder-util-runtime": "^8.2.4",
"builder-util-runtime": "^8.2.5",
"chalk": "^2.4.2",
"debug": "^4.1.1",
"fs-extra-p": "^8.0.2",
@@ -1403,7 +1403,7 @@
"js-yaml": "^3.13.1",
"source-map-support": "^0.5.12",
"stat-mode": "^0.3.0",
"temp-file": "^3.3.2"
"temp-file": "^3.3.3"
},
"dependencies": {
"ansi-styles": {
@@ -1475,9 +1475,9 @@
}
},
"builder-util-runtime": {
"version": "8.2.4",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.2.4.tgz",
"integrity": "sha512-iwRnmFnGs63+p6uJem2N/d9Q0SKj5c0TP8PTesKnWsWvo1saKKM/0yiT137w+3uz+r/Cmf8VH/8nt75uW8jeUw==",
"version": "8.2.5",
"resolved": "https://registry.npmjs.org/builder-util-runtime/-/builder-util-runtime-8.2.5.tgz",
"integrity": "sha512-YILT+YUlxrE3yNB6mDC1tF+Q24mr1LSYdjP5U861jbBeDZfvy1/VPDzW3boMVrDtzYnDnvkYrzLJnoh6TXA75w==",
"dev": true,
"requires": {
"bluebird-lst": "^1.0.9",
@@ -1625,7 +1625,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"requires": {
"ansi-styles": "^2.2.1",
@@ -1895,7 +1895,7 @@
},
"commander": {
"version": "2.8.1",
"resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
"integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
"requires": {
"graceful-readlink": ">= 1.0.0"
@@ -2621,14 +2621,14 @@
}
},
"dmg-builder": {
"version": "6.6.4",
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-6.6.4.tgz",
"integrity": "sha512-neJXwnFaJ4wisP++Yyi9H0kEUsvxyY7TBBEK2fu8V8i1VoMQKljY/6Dgf2HktLVHzXSWP71TQwKKWSIWI/3aeQ==",
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/dmg-builder/-/dmg-builder-6.7.0.tgz",
"integrity": "sha512-YluV5KM2sbqKZ0SeL+K7Q0E37EAeV64UmdUtnV4CZqe7TYaVa5j2K5zpfoMZyg+sekxAN8utfmrvaLf9V6SNeA==",
"dev": true,
"requires": {
"app-builder-lib": "~20.43.0",
"app-builder-lib": "~20.44.2",
"bluebird-lst": "^1.0.9",
"builder-util": "~10.0.2",
"builder-util": "~10.1.0",
"fs-extra-p": "^8.0.2",
"iconv-lite": "^0.4.24",
"js-yaml": "^3.13.1",
@@ -2815,14 +2815,14 @@
"integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
},
"ejs": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.1.tgz",
"integrity": "sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ=="
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/ejs/-/ejs-2.6.2.tgz",
"integrity": "sha512-PcW2a0tyTuPHz3tWyYqtK6r1fZ3gp+3Sop8Ph+ZYN81Ob5rwmbHEzaqs10N3BEsaGTkh/ooniXK+WwszGlc2+Q=="
},
"electron": {
"version": "6.0.0-beta.8",
"resolved": "https://registry.npmjs.org/electron/-/electron-6.0.0-beta.8.tgz",
"integrity": "sha512-TqgsK90V9Mkal24uw9/fGJiRob9J7WnSjlshDQjtmDYYD4xfDqk6U9+FRg638nst44J22BK8ew3HyaguuVqEWw==",
"version": "6.0.0-beta.13",
"resolved": "https://registry.npmjs.org/electron/-/electron-6.0.0-beta.13.tgz",
"integrity": "sha512-q1pX18l4N6PH0iCoHXPmgqDNEX2slvMYZcxWXHlUFQodtvXq7bnsFfr6uvifMT5oSdfsCZtXXPK3/iK6PdODNQ==",
"dev": true,
"requires": {
"@types/node": "^10.12.18",
@@ -2831,17 +2831,17 @@
}
},
"electron-builder": {
"version": "20.43.0",
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-20.43.0.tgz",
"integrity": "sha512-8trMnW3K2BWtPGQJqCWZ5QMwZajMucmzlTCHrzhufQWuQbaPhanmho6tWFm2ftyuYku3T4TB4kD7UCX/YQDGyg==",
"version": "20.44.2",
"resolved": "https://registry.npmjs.org/electron-builder/-/electron-builder-20.44.2.tgz",
"integrity": "sha512-4n7s8gfmMuNr3IbVLXo/XzcdaWcOFxu+VeC0FUjl90lU8H8pvuQ/LZS+yD7k0zVw98p4+GvMg0nIwjdF+BbwTA==",
"dev": true,
"requires": {
"app-builder-lib": "20.43.0",
"app-builder-lib": "20.44.2",
"bluebird-lst": "^1.0.9",
"builder-util": "10.0.2",
"builder-util-runtime": "8.2.4",
"builder-util": "10.1.0",
"builder-util-runtime": "8.2.5",
"chalk": "^2.4.2",
"dmg-builder": "6.6.4",
"dmg-builder": "6.7.0",
"fs-extra-p": "^8.0.2",
"is-ci": "^2.0.0",
"lazy-val": "^1.0.4",
@@ -3055,15 +3055,15 @@
"dev": true
},
"package-json": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/package-json/-/package-json-6.3.0.tgz",
"integrity": "sha512-XO7WS3EEXd48vmW633Y97Mh9xuENFiOevI9G+ExfTG/k6xuY9cBd3fxkAoDMSEsNZXasaVJIJ1rD/n7GMf18bA==",
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/package-json/-/package-json-6.4.0.tgz",
"integrity": "sha512-bd1T8OBG7hcvMd9c/udgv6u5v9wISP3Oyl9Cm7Weop8EFwrtcQDnS2sb6zhwqus2WslSr5wSTIPiTTpxxmPm7Q==",
"dev": true,
"requires": {
"got": "^9.6.0",
"registry-auth-token": "^3.4.0",
"registry-url": "^5.0.0",
"semver": "^5.6.0"
"semver": "^6.1.1"
}
},
"prepend-http": {
@@ -3091,12 +3091,6 @@
"rc": "^1.2.8"
}
},
"semver": {
"version": "5.7.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
"dev": true
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
@@ -3583,18 +3577,18 @@
}
},
"electron-publish": {
"version": "20.43.0",
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-20.43.0.tgz",
"integrity": "sha512-+oaTdbMmh1xceKPZWORYyGkNmxIhu7rkE1qEEn0NeG3KHEAePHg9FZGemR4aV3tQmtOwti2Vj+x8snAUxsnHHQ==",
"version": "20.44.2",
"resolved": "https://registry.npmjs.org/electron-publish/-/electron-publish-20.44.2.tgz",
"integrity": "sha512-GRzmMFdVG63zKip2wY+fa5Vmw6bHz1OaGemz3Ebfzm60CfaPOw8o3iWa49JuxYYPobi2BbZrbr76a0flECmAzg==",
"dev": true,
"requires": {
"bluebird-lst": "^1.0.9",
"builder-util": "~10.0.2",
"builder-util-runtime": "^8.2.4",
"builder-util": "~10.1.0",
"builder-util-runtime": "^8.2.5",
"chalk": "^2.4.2",
"fs-extra-p": "^8.0.2",
"lazy-val": "^1.0.4",
"mime": "^2.4.3"
"mime": "^2.4.4"
},
"dependencies": {
"ansi-styles": {
@@ -5832,7 +5826,7 @@
},
"got": {
"version": "5.7.1",
"resolved": "http://registry.npmjs.org/got/-/got-5.7.1.tgz",
"resolved": "https://registry.npmjs.org/got/-/got-5.7.1.tgz",
"integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=",
"requires": {
"create-error-class": "^3.0.1",
@@ -6619,7 +6613,7 @@
},
"into-stream": {
"version": "3.1.0",
"resolved": "http://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz",
"resolved": "https://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz",
"integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=",
"requires": {
"from2": "^2.1.1",
@@ -8053,7 +8047,7 @@
},
"get-stream": {
"version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
},
"got": {
@@ -8089,7 +8083,7 @@
},
"p-cancelable": {
"version": "0.4.1",
"resolved": "http://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz",
"resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz",
"integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ=="
},
"p-event": {
@@ -8236,7 +8230,7 @@
"dependencies": {
"file-type": {
"version": "3.9.0",
"resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek="
}
}
@@ -8261,7 +8255,7 @@
"dependencies": {
"get-stream": {
"version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
},
"pify": {
@@ -8318,7 +8312,7 @@
},
"get-stream": {
"version": "2.3.1",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
"integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
"requires": {
"object-assign": "^4.0.1",
@@ -8348,7 +8342,7 @@
"dependencies": {
"get-stream": {
"version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
}
}
@@ -8378,7 +8372,7 @@
},
"pify": {
"version": "2.3.0",
"resolved": "http://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
},
"prepend-http": {
@@ -8484,7 +8478,7 @@
},
"readable-stream": {
"version": "1.1.14",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"requires": {
"core-util-is": "~1.0.0",
@@ -8576,9 +8570,9 @@
"integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q=="
},
"node-abi": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.8.0.tgz",
"integrity": "sha512-1/aa2clS0pue0HjckL62CsbhWWU35HARvBDXcJtYKbYR7LnIutmpxmXbuDMV9kEviD2lP/wACOgWmmwljghHyQ==",
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.9.0.tgz",
"integrity": "sha512-jmEOvv0eanWjhX8dX1pmjb7oJl1U1oR4FOh0b2GnvALwSYoOdU7sj+kLDSAyjo4pfC9aj/IxkloxdLJQhSSQBA==",
"requires": {
"semver": "^5.4.1"
},
@@ -8910,7 +8904,7 @@
},
"onetime": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
"integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k="
},
"open": {
@@ -9097,7 +9091,7 @@
},
"p-is-promise": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz",
"integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4="
},
"p-limit": {
@@ -9600,7 +9594,7 @@
},
"get-stream": {
"version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
}
}
@@ -9884,7 +9878,7 @@
"dependencies": {
"file-type": {
"version": "3.9.0",
"resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"resolved": "https://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz",
"integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek="
}
}
@@ -9909,7 +9903,7 @@
"dependencies": {
"get-stream": {
"version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
},
"pify": {
@@ -9947,7 +9941,7 @@
},
"get-stream": {
"version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
}
}
@@ -9999,7 +9993,7 @@
},
"get-stream": {
"version": "2.3.1",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz",
"integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=",
"requires": {
"object-assign": "^4.0.1",
@@ -10029,7 +10023,7 @@
"dependencies": {
"get-stream": {
"version": "3.0.0",
"resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
"integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
}
}
@@ -10286,7 +10280,7 @@
},
"query-string": {
"version": "5.1.1",
"resolved": "http://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz",
"integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==",
"requires": {
"decode-uri-component": "^0.2.0",
@@ -11627,7 +11621,7 @@
},
"strip-dirs": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-1.1.1.tgz",
"integrity": "sha1-lgu9EoeETzl1pFWKoQOoJV4kVqA=",
"requires": {
"chalk": "^1.0.0",
@@ -11917,37 +11911,14 @@
"integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0="
},
"temp-file": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.2.tgz",
"integrity": "sha512-FGKccAW0Mux9hC/2bdUIe4bJRv4OyVo4RpVcuplFird1V/YoplIFbnPZjfzbJSf/qNvRZIRB9/4n/RkI0GziuQ==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/temp-file/-/temp-file-3.3.3.tgz",
"integrity": "sha512-ErWJ0vfZwkozaH7dn/5QtYdrGwy6fWID0GG3PEzNb9Vmt6urL4mQ3lKz7NWVi1/kmZsWQzgjTL7/P4mwGx5jqg==",
"dev": true,
"requires": {
"async-exit-hook": "^2.0.1",
"bluebird-lst": "^1.0.6",
"fs-extra-p": "^7.0.0"
},
"dependencies": {
"fs-extra": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"fs-extra-p": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fs-extra-p/-/fs-extra-p-7.0.1.tgz",
"integrity": "sha512-yhd2OV0HnHt2oitlp+X9hl2ReX4X/7kQeL7/72qzPHTZj5eUPGzAKOvEglU02Fa1OeG2rSy/aKB4WGVaLiF8tw==",
"dev": true,
"requires": {
"bluebird-lst": "^1.0.7",
"fs-extra": "^7.0.1"
}
}
"bluebird-lst": "^1.0.9",
"fs-extra-p": "^8.0.2"
}
},
"tempfile": {
@@ -12007,7 +11978,7 @@
},
"readable-stream": {
"version": "1.0.34",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
"integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
"requires": {
"core-util-is": "~1.0.0",
@@ -12877,9 +12848,9 @@
}
},
"ws": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.0.0.tgz",
"integrity": "sha512-cknCal4k0EAOrh1SHHPPWWh4qm93g1IuGGGwBjWkXmCG7LsDtL8w9w+YVfaF+KSVwiHQKDIMsSLBVftKf9d1pg==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.0.1.tgz",
"integrity": "sha512-ILHfMbuqLJvnSgYXLgy4kMntroJpe8hT41dOVWM8bxRuw6TK4mgMp9VJUNsZTEc5Bh+Mbs0DJT4M0N+wBG9l9A==",
"requires": {
"async-limiter": "^1.0.0"
}

View File

@@ -2,7 +2,7 @@
"name": "trilium",
"productName": "Trilium Notes",
"description": "Trilium Notes",
"version": "0.33.1-beta",
"version": "0.33.7",
"license": "AGPL-3.0-only",
"main": "electron.js",
"bin": {
@@ -30,7 +30,7 @@
"csurf": "1.10.0",
"dayjs": "1.8.14",
"debug": "4.1.1",
"ejs": "2.6.1",
"ejs": "2.6.2",
"electron-debug": "3.0.0",
"electron-dl": "1.14.0",
"electron-find": "1.0.6",
@@ -53,7 +53,7 @@
"mime-types": "2.1.24",
"moment": "2.24.0",
"multer": "1.4.1",
"node-abi": "2.8.0",
"node-abi": "2.9.0",
"open": "6.3.0",
"pngjs": "3.4.0",
"rand-token": "0.4.0",
@@ -70,13 +70,13 @@
"tar-stream": "2.1.0",
"turndown": "5.0.3",
"unescape": "1.0.1",
"ws": "7.0.0",
"ws": "7.0.1",
"xml2js": "0.4.19"
},
"devDependencies": {
"devtron": "1.4.0",
"electron": "6.0.0-beta.8",
"electron-builder": "20.43.0",
"electron": "6.0.0-beta.13",
"electron-builder": "20.44.2",
"electron-compile": "6.4.4",
"electron-installer-debian": "2.0.0",
"electron-packager": "13.1.1",

View File

@@ -142,10 +142,10 @@ $noteTabContainer.on("click", ".export-note-button", function () {
return;
}
exportDialog.showDialog('single');
exportDialog.showDialog(treeService.getActiveNode(), 'single');
});
$noteTabContainer.on("click", ".import-files-button", importDialog.showDialog);
$noteTabContainer.on("click", ".import-files-button", () => importDialog.showDialog(treeService.getActiveNode()));
$('[data-toggle="tooltip"]').tooltip({
html: true

View File

@@ -12,21 +12,19 @@ const $noteTitle = $('#branch-prefix-note-title');
let branchId;
async function showDialog() {
async function showDialog(node) {
utils.closeActiveDialog();
glob.activeDialog = $dialog;
$dialog.modal();
const currentNode = treeService.getActiveNode();
branchId = currentNode.data.branchId;
branchId = node.data.branchId;
const branch = await treeCache.getBranch(branchId);
$treePrefixInput.val(branch.prefix);
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
const noteTitle = await treeUtils.getNoteTitle(node.data.noteId);
$noteTitle.text(" - " + noteTitle);
}

View File

@@ -7,8 +7,11 @@ const $custom = $("#confirm-dialog-custom");
const DELETE_NOTE_BUTTON_ID = "confirm-dialog-delete-note";
let resolve;
let $originallyFocused; // element focused before the dialog was opened so we can return to it afterwards
function confirm(message) {
$originallyFocused = $(':focus');
$custom.hide();
glob.activeDialog = $dialog;
@@ -55,6 +58,11 @@ $dialog.on("hidden.bs.modal", () => {
if (resolve) {
resolve(false);
}
if ($originallyFocused) {
$originallyFocused.focus();
$originallyFocused = null;
}
});
function doResolve(ret) {

View File

@@ -1,4 +1,3 @@
import treeService from '../services/tree.js';
import treeUtils from "../services/tree_utils.js";
import utils from "../services/utils.js";
import messagingService from "../services/messaging.js";
@@ -6,7 +5,7 @@ import infoService from "../services/info.js";
const $dialog = $("#export-dialog");
const $form = $("#export-form");
const $noteTitle = $dialog.find(".note-title");
const $noteTitle = $dialog.find(".export-note-title");
const $subtreeFormats = $("#export-subtree-formats");
const $singleFormats = $("#export-single-formats");
const $subtreeType = $("#export-type-subtree");
@@ -17,8 +16,9 @@ const $exportButton = $("#export-button");
const $opmlVersions = $("#opml-versions");
let exportId = '';
let branchId = null;
async function showDialog(defaultType) {
async function showDialog(node, defaultType) {
utils.closeActiveDialog();
// each opening of the dialog resets the exportId so we don't associate it with previous exports anymore
@@ -46,8 +46,9 @@ async function showDialog(defaultType) {
$dialog.modal();
const currentNode = treeService.getActiveNode();
const noteTitle = await treeUtils.getNoteTitle(currentNode.data.noteId);
branchId = node.data.branchId;
const noteTitle = await treeUtils.getNoteTitle(node.data.noteId);
$noteTitle.html(noteTitle);
}
@@ -70,9 +71,7 @@ $form.submit(() => {
const exportVersion = exportFormat === 'opml' ? $dialog.find("input[name='opml-version']:checked").val() : "1.0";
const currentNode = treeService.getActiveNode();
exportBranch(currentNode.data.branchId, exportType, exportFormat, exportVersion);
exportBranch(branchId, exportType, exportFormat, exportVersion);
return false;
});

View File

@@ -19,8 +19,9 @@ const $codeImportedAsCodeCheckbox = $("#code-imported-as-code-checkbox");
const $explodeArchivesCheckbox = $("#explode-archives-checkbox");
let importId;
let importIntoNoteId = null;
async function showDialog() {
async function showDialog(node) {
utils.closeActiveDialog();
// each opening of the dialog resets the importId so we don't associate it with previous imports anymore
@@ -37,19 +38,18 @@ async function showDialog() {
glob.activeDialog = $dialog;
const currentNode = treeService.getActiveNode();
$noteTitle.text(await treeUtils.getNoteTitle(currentNode.data.noteId));
importIntoNoteId = node.data.noteId;
$noteTitle.text(await treeUtils.getNoteTitle(importIntoNoteId));
$dialog.modal();
}
$form.submit(() => {
const currentNode = treeService.getActiveNode();
// disabling so that import is not triggered again.
$importButton.attr("disabled", "disabled");
importIntoNote(currentNode.data.noteId);
importIntoNote(importIntoNoteId);
return false;
});

View File

@@ -5,8 +5,11 @@ const $infoContent = $("#info-dialog-content");
const $okButton = $("#info-dialog-ok-button");
let resolve;
let $originallyFocused; // element focused before the dialog was opened so we can return to it afterwards
function info(message) {
$originallyFocused = $(':focus');
utils.closeActiveDialog();
glob.activeDialog = $dialog;
@@ -24,6 +27,11 @@ $dialog.on("hidden.bs.modal", () => {
if (resolve) {
resolve();
}
if ($originallyFocused) {
$originallyFocused.focus();
$originallyFocused = null;
}
});
$okButton.click(() => $dialog.modal("hide"));

View File

@@ -6,6 +6,7 @@ import treeCache from "./tree_cache.js";
import treeUtils from "./tree_utils.js";
import hoistedNoteService from "./hoisted_note.js";
import noteDetailService from "./note_detail.js";
import confirmDialog from "../dialogs/confirm.js";
async function moveBeforeNode(nodesToMove, beforeNode) {
nodesToMove = await filterRootNote(nodesToMove);
@@ -82,7 +83,7 @@ async function moveToNode(nodesToMove, toNode) {
async function deleteNodes(nodes) {
nodes = await 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 || !await confirmDialog.confirm('Are you sure you want to delete select note(s) and all the sub-notes?')) {
return false;
}
@@ -102,7 +103,7 @@ async function deleteNodes(nodes) {
next = nodes[0].getPrevSibling();
}
if (!next && !hoistedNoteService.isTopLevelNode(nodes[0])) {
if (!next && !await hoistedNoteService.isTopLevelNode(nodes[0])) {
next = nodes[0].getParent();
}

View File

@@ -67,12 +67,9 @@ function connectWebSocket() {
// use wss for secure messaging
const ws = new WebSocket(protocol + "://" + location.host);
ws.onopen = event => console.debug(utils.now(), "Connected to server with WebSocket");
ws.onopen = () => console.debug(utils.now(), "Connected to server with WebSocket");
ws.onmessage = handleMessage;
ws.onclose = function(){
// Try to reconnect in 5 seconds
setTimeout(() => connectWebSocket(), 5000);
};
// we're not handling ws.onclose here because reconnection is done in sendPing()
return ws;
}
@@ -88,10 +85,17 @@ setTimeout(() => {
console.log("Lost connection to server");
}
ws.send(JSON.stringify({
type: 'ping',
lastSyncId: lastSyncId
}));
if (ws.readyState === ws.OPEN) {
ws.send(JSON.stringify({
type: 'ping',
lastSyncId: lastSyncId
}));
}
else if (ws.readyState === ws.CLOSED || ws.readyState === ws.CLOSING) {
console.log("WS closed or closing, trying to reconnect");
ws = connectWebSocket();
}
}, 1000);
}, 0);

View File

@@ -401,11 +401,14 @@ tabRow.addListener('activeTabChange', async ({ detail }) => {
tabRow.addListener('tabRemove', async ({ detail }) => {
const tabId = detail.tabEl.getAttribute('data-tab-id');
const tabContentToDelete = tabContexts.find(nc => nc.tabId === tabId);
const tabContextToDelete = tabContexts.find(nc => nc.tabId === tabId);
if (tabContentToDelete) {
await tabContentToDelete.saveNoteIfChanged();
tabContentToDelete.$tabContent.remove();
if (tabContextToDelete) {
// sometimes there are orphan autocompletes after closing the tab
tabContextToDelete.closeAutocomplete();
await tabContextToDelete.saveNoteIfChanged();
tabContextToDelete.$tabContent.remove();
}
tabContexts = tabContexts.filter(nc => nc.tabId !== tabId);

View File

@@ -14,6 +14,7 @@ class NoteDetailCode {
this.ctx = ctx;
this.codeEditor = null;
this.$component = ctx.$tabContent.find('.note-detail-code');
this.$editorEl = this.$component.find('.note-detail-code-editor');
this.$executeScriptButton = ctx.$tabContent.find(".execute-script-button");
utils.bindElShortcut(ctx.$tabContent, "ctrl+return", () => this.executeCurrentNote());
@@ -34,7 +35,7 @@ class NoteDetailCode {
CodeMirror.modeURL = 'libraries/codemirror/mode/%N/%N.js';
this.codeEditor = CodeMirror(this.$component[0], {
this.codeEditor = CodeMirror(this.$editorEl[0], {
value: "",
viewportMargin: Infinity,
indentUnit: 4,

View File

@@ -1,5 +1,4 @@
import utils from "./utils.js";
import noteDetailService from "./note_detail.js";
import infoService from "./info.js";
import server from "./server.js";

View File

@@ -8,6 +8,7 @@ class NoteDetailText {
constructor(ctx) {
this.ctx = ctx;
this.$component = ctx.$tabContent.find('.note-detail-text');
this.$editorEl = this.$component.find('.note-detail-text-editor');
this.textEditor = null;
this.$component.on("dblclick", "img", e => {
@@ -39,7 +40,7 @@ class NoteDetailText {
// textEditor might have been initialized during previous await so checking again
// looks like double initialization can freeze CKEditor pretty badly
if (!this.textEditor) {
this.textEditor = await BalloonEditor.create(this.$component[0], {
this.textEditor = await BalloonEditor.create(this.$editorEl[0], {
placeholder: "Type the content of your note here ..."
});
@@ -73,7 +74,7 @@ class NoteDetailText {
}
focus() {
this.$component.focus();
this.$editorEl.focus();
}
getEditor() {

View File

@@ -43,6 +43,7 @@ async function setupProtectedSession(password) {
}
protectedSessionHolder.setProtectedSessionId(response.protectedSessionId);
protectedSessionHolder.touchProtectedSession();
await treeService.reload();

View File

@@ -37,6 +37,8 @@ function isProtectedSessionAvailable() {
function touchProtectedSession() {
if (isProtectedSessionAvailable()) {
lastProtectedSessionOperationDate = new Date();
setProtectedSessionId(utils.getCookie(PROTECTED_SESSION_ID_KEY));
}
}

View File

@@ -67,17 +67,27 @@ class TabContext {
this.components = {};
this.$noteTitle.on('input', () => {
if (!this.note) {
return;
}
this.noteChanged();
const title = this.$noteTitle.val();
this.note.title = this.$noteTitle.val();
this.tabRow.updateTab(this.$tab[0], {title});
treeService.setNoteTitle(this.noteId, title);
this.tabRow.updateTab(this.$tab[0], {title: this.note.title});
treeService.setNoteTitle(this.noteId, this.note.title);
this.setTitleBar();
});
if (utils.isDesktop()) {
// keyboard plugin is not loaded in mobile
this.$noteTitle.bind('keydown', 'return', () => this.getComponent().focus());
this.$noteTitle.bind('keydown', 'return', () => {
this.getComponent().focus();
return false; // to not propagate the enter into the editor (causes issues with codemirror)
});
}
this.$protectButton = this.$tabContent.find(".protect-button");
@@ -86,7 +96,7 @@ class TabContext {
this.$unprotectButton = this.$tabContent.find(".unprotect-button");
this.$unprotectButton.click(protectedSessionService.unprotectNoteAndSendToServer);
console.log(`Created note tab ${this.tabId}`);
console.debug(`Created note tab ${this.tabId}`);
}
setNote(note, notePath) {
@@ -103,6 +113,8 @@ class TabContext {
this.setTitleBar();
this.closeAutocomplete(); // esp. on windows autocomplete is not getting closed automatically
setTimeout(async () => {
// we include the note into recent list only if the user stayed on the note at least 5 seconds
if (notePath && notePath === this.notePath) {
@@ -119,7 +131,7 @@ class TabContext {
this.showPaths();
console.log(`Switched tab ${this.tabId} to ${this.noteId}`);
console.debug(`Switched tab ${this.tabId} to ${this.noteId}`);
}
show() {
@@ -328,6 +340,12 @@ class TabContext {
}
}
}
closeAutocomplete() {
if (utils.isDesktop()) {
this.$tabContent.find('.aa-input').autocomplete('close');
}
}
}
export default TabContext;

View File

@@ -196,6 +196,8 @@ async function resolveNotePath(notePath) {
async function getRunPath(notePath) {
utils.assertArguments(notePath);
notePath = notePath.split("-")[0];
const path = notePath.split("/").reverse();
if (!path.includes("root")) {
@@ -303,6 +305,15 @@ function getSelectedNodes(stopOnParents = false) {
return getTree().getSelectedNodes(stopOnParents);
}
function getSelectedOrActiveNodes(node) {
let notes = getSelectedNodes(true);
if (notes.length === 0) {
notes.push(node);
}
return notes;
}
function clearSelectedNodes() {
for (const selectedNode of getSelectedNodes()) {
selectedNode.setSelected(false);
@@ -621,7 +632,8 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
extraClasses: await treeBuilder.getExtraClasses(noteEntity),
icon: await treeBuilder.getIcon(noteEntity),
folder: extraOptions.type === 'search',
lazy: true
lazy: true,
key: utils.randomString(12) // this should prevent some "duplicate key" errors
};
if (target === 'after') {
@@ -629,10 +641,14 @@ async function createNote(node, parentNoteId, target, extraOptions = {}) {
}
else if (target === 'into') {
if (!node.getChildren() && node.isFolder()) {
// folder is not loaded - load will bring up the note since it was already put into cache
await node.load(true);
await node.setExpanded();
}
node.addChildren(newNode);
else {
node.addChildren(newNode);
}
await node.getLastChild().setActive(true);
@@ -728,10 +744,12 @@ utils.bindShortcut('ctrl+o', async () => {
async function createNoteInto() {
const node = getActiveNode();
await createNote(node, node.data.noteId, 'into', {
isProtected: node.data.isProtected,
saveSelection: true
});
if (node) {
await createNote(node, node.data.noteId, 'into', {
isProtected: node.data.isProtected,
saveSelection: true
});
}
}
async function checkFolderStatus(node) {
@@ -805,6 +823,7 @@ export default {
createNote,
createNoteInto,
getSelectedNodes,
getSelectedOrActiveNodes,
clearSelectedNodes,
sortAlphabetically,
showTree,

View File

@@ -83,7 +83,8 @@ async function prepareNode(branch) {
icon: await getIcon(note),
refKey: note.noteId,
expanded: branch.isExpanded || hoistedNoteId === note.noteId,
lazy: true
lazy: true,
key: utils.randomString(12) // this should prevent some "duplicate key" errors
};
if (note.hasChildren() || note.type === 'search') {

View File

@@ -34,45 +34,52 @@ class TreeContextMenu {
const isNotRoot = note.noteId !== 'root';
const isHoisted = note.noteId === await hoistedNoteService.getHoistedNoteId();
// some actions don't support multi-note so they are disabled when notes are selected
// the only exception is when the only selected note is the one that was right-clicked, then
// it's clear what the user meant to do.
const selNodes = treeService.getSelectedNodes();
const noSelectedNotes = selNodes.length === 0
|| (selNodes.length === 1 && selNodes[0] === this.node);
const insertNoteAfterEnabled = isNotRoot && !isHoisted && parentNote.type !== 'search';
const insertChildNoteEnabled = note.type !== 'search';
return [
{ title: "Open in new tab", cmd: "openInTab", uiIcon: "empty" },
{ title: "Open in new tab", cmd: "openInTab", uiIcon: "empty", enabled: noSelectedNotes },
{ title: "Insert note after <kbd>Ctrl+O</kbd>", cmd: "insertNoteAfter", uiIcon: "plus",
items: insertNoteAfterEnabled ? this.getNoteTypeItems("insertNoteAfter") : null,
enabled: insertNoteAfterEnabled },
enabled: insertNoteAfterEnabled && noSelectedNotes },
{ title: "Insert child note <kbd>Ctrl+P</kbd>", cmd: "insertChildNote", uiIcon: "plus",
items: insertChildNoteEnabled ? this.getNoteTypeItems("insertChildNote") : null,
enabled: insertChildNoteEnabled },
enabled: insertChildNoteEnabled && noSelectedNotes },
{ title: "Delete <kbd>Delete</kbd>", cmd: "delete", uiIcon: "trash",
enabled: isNotRoot && !isHoisted && parentNote.type !== 'search' },
{ title: "----" },
isHoisted ? null : { title: "Hoist note <kbd>Ctrl-H</kbd>", cmd: "hoist", uiIcon: "empty" },
isHoisted ? null : { title: "Hoist note <kbd>Ctrl-H</kbd>", cmd: "hoist", uiIcon: "empty", enabled: noSelectedNotes },
!isHoisted || !isNotRoot ? null : { title: "Unhoist note <kbd>Ctrl-H</kbd>", cmd: "unhoist", uiIcon: "arrow-up" },
{ title: "Edit branch prefix <kbd>F2</kbd>", cmd: "editBranchPrefix", uiIcon: "empty",
enabled: isNotRoot && parentNote.type !== 'search'},
enabled: isNotRoot && parentNote.type !== 'search' && noSelectedNotes},
{ title: "----" },
{ title: "Protect subtree", cmd: "protectSubtree", uiIcon: "shield-check" },
{ title: "Unprotect subtree", cmd: "unprotectSubtree", uiIcon: "shield-close" },
{ title: "Protect subtree", cmd: "protectSubtree", uiIcon: "shield-check", enabled: noSelectedNotes },
{ title: "Unprotect subtree", cmd: "unprotectSubtree", uiIcon: "shield-close", enabled: noSelectedNotes },
{ title: "----" },
{ title: "Copy / clone <kbd>Ctrl+C</kbd>", cmd: "copy", uiIcon: "files",
enabled: isNotRoot },
{ title: "Cut <kbd>Ctrl+X</kbd>", cmd: "cut", uiIcon: "scissors",
enabled: isNotRoot },
{ title: "Paste into <kbd>Ctrl+V</kbd>", cmd: "pasteInto", uiIcon: "clipboard",
enabled: !clipboard.isEmpty() && note.type !== 'search' },
enabled: !clipboard.isEmpty() && note.type !== 'search' && noSelectedNotes },
{ title: "Paste after", cmd: "pasteAfter", uiIcon: "clipboard",
enabled: !clipboard.isEmpty() && isNotRoot && parentNote.type !== 'search' },
enabled: !clipboard.isEmpty() && isNotRoot && parentNote.type !== 'search' && noSelectedNotes },
{ title: "----" },
{ title: "Export", cmd: "export", uiIcon: "empty",
enabled: note.type !== 'search' },
enabled: note.type !== 'search' && noSelectedNotes },
{ title: "Import into note", cmd: "importIntoNote", uiIcon: "empty",
enabled: note.type !== 'search' },
enabled: note.type !== 'search' && noSelectedNotes },
{ title: "----" },
{ title: "Collapse subtree <kbd>Alt+-</kbd>", cmd: "collapseSubtree", uiIcon: "align-justify" },
{ title: "Force note sync", cmd: "forceNoteSync", uiIcon: "refresh" },
{ title: "Sort alphabetically <kbd>Alt+S</kbd>", cmd: "sortAlphabetically", uiIcon: "empty" }
{ title: "Collapse subtree <kbd>Alt+-</kbd>", cmd: "collapseSubtree", uiIcon: "align-justify", enabled: noSelectedNotes },
{ title: "Force note sync", cmd: "forceNoteSync", uiIcon: "refresh", enabled: noSelectedNotes },
{ title: "Sort alphabetically <kbd>Alt+S</kbd>", cmd: "sortAlphabetically", uiIcon: "empty", enabled: noSelectedNotes }
].filter(row => row !== null);
}
@@ -110,10 +117,10 @@ class TreeContextMenu {
protectedSessionService.protectSubtree(this.node.data.noteId, false);
}
else if (cmd === "copy") {
clipboard.copy(treeService.getSelectedNodes());
clipboard.copy(treeService.getSelectedOrActiveNodes(this.node));
}
else if (cmd === "cut") {
clipboard.cut(treeService.getSelectedNodes());
clipboard.cut(treeService.getSelectedOrActiveNodes(this.node));
}
else if (cmd === "pasteAfter") {
clipboard.pasteAfter(this.node);
@@ -122,19 +129,13 @@ class TreeContextMenu {
clipboard.pasteInto(this.node);
}
else if (cmd === "delete") {
let notesToDelete = treeService.getSelectedNodes(true);
if (notesToDelete.length === 0) {
notesToDelete.push(this.node);
}
treeChangesService.deleteNodes(notesToDelete);
treeChangesService.deleteNodes(treeService.getSelectedOrActiveNodes(this.node));
}
else if (cmd === "export") {
exportDialog.showDialog("subtree");
exportDialog.showDialog(this.node,"subtree");
}
else if (cmd === "importIntoNote") {
importDialog.showDialog();
importDialog.showDialog(this.node);
}
else if (cmd === "collapseSubtree") {
treeService.collapseTree(this.node);

View File

@@ -7,13 +7,7 @@ import clipboard from "./clipboard.js";
const keyBindings = {
"del": node => {
let notesToDelete = treeService.getSelectedNodes(true);
if (notesToDelete.length === 0) {
notesToDelete.push(node);
}
treeChangesService.deleteNodes(notesToDelete);
treeChangesService.deleteNodes(treeService.getSelectedOrActiveNodes(node));
},
"ctrl+up": node => {
const beforeNode = node.getPrevSibling();
@@ -110,13 +104,13 @@ const keyBindings = {
return false;
},
"ctrl+c": () => {
clipboard.copy(treeService.getSelectedNodes());
"ctrl+c": node => {
clipboard.copy(treeService.getSelectedOrActiveNodes(node));
return false;
},
"ctrl+x": () => {
clipboard.cut(treeService.getSelectedNodes());
"ctrl+x": node => {
clipboard.cut(treeService.getSelectedOrActiveNodes(node));
return false;
},

View File

@@ -19,7 +19,10 @@ function getNoteIdFromNotePath(notePath) {
const path = notePath.split("/");
return path[path.length - 1];
const lastSegment = path[path.length - 1];
// path could have also tabId suffix
return lastSegment.split("-")[0];
}
async function getNotePath(node) {

View File

@@ -135,13 +135,16 @@ ul.fancytree-container {
.note-detail-text h6 { font-size: 1.1em; }
.note-detail-text {
overflow: auto;
font-family: var(--detail-text-font-family);
}
.note-detail-text-editor {
padding-top: 10px;
border: 0 !important;
box-shadow: none !important;
/* This is because with empty content height of editor is 0 and it's impossible to click into it */
min-height: 200px;
padding-top: 10px;
overflow: auto;
font-family: var(--detail-text-font-family);
}
.note-detail-text p:first-child, .note-detail-text::before {
@@ -194,6 +197,10 @@ span.fancytree-active .fancytree-title {
border-radius: 5px;
}
span.fancytree-active:not(.fancytree-focused) .fancytree-title {
border-style: dashed !important;
}
span.fancytree-focused .fancytree-title, span.fancytree-focused.fancytree-selected .fancytree-title {
color: var(--active-item-text-color) !important;
background-color: var(--active-item-background-color) !important;
@@ -350,10 +357,13 @@ div.ui-tooltip {
}
.note-detail-code {
min-height: 200px;
overflow: auto;
}
.note-detail-code-editor {
min-height: 200px;
}
.note-detail-render {
min-height: 200px;
}

View File

@@ -1,9 +1,9 @@
"use strict";
const imageType = require('image-type');
const imageService = require('../../services/image');
const utils = require('../../services/utils');
const dateNoteService = require('../../services/date_notes');
const sql = require('../../services/sql');
const noteService = require('../../services/notes');
const passwordEncryptionService = require('../../services/password_encryption');
const optionService = require('../../services/options');
@@ -36,9 +36,11 @@ async function uploadImage(req) {
return [400, "Unknown image type: " + file.mimetype];
}
const originalName = "Sender image." + imageType(file.buffer).ext;
const parentNote = await dateNoteService.getDateNote(req.headers['x-local-date']);
const {noteId} = await imageService.saveImage(file.buffer, "Sender image", parentNote.noteId, true);
const {noteId} = await imageService.saveImage(file.buffer, originalName, parentNote.noteId, true);
return {
noteId: noteId

View File

@@ -1 +1 @@
module.exports = { buildDate:"2019-06-16T11:13:37+02:00", buildRevision: "93f1d461044c7e027a739fad0ebd2582a71edc34" };
module.exports = { buildDate:"2019-07-11T20:55:56+02:00", buildRevision: "a76dcb44ae1c1cef58b9a66041b183893745a944" };

View File

@@ -32,11 +32,11 @@ async function exportToTar(exportContext, branch, format, res) {
do {
index = existingFileNames[lcFileName]++;
newName = lcFileName + "_" + index;
newName = index + "_" + lcFileName;
}
while (newName in existingFileNames);
return fileName + "_" + index;
return index + "_" + fileName;
}
else {
existingFileNames[lcFileName] = 1;
@@ -46,24 +46,32 @@ async function exportToTar(exportContext, branch, format, res) {
}
function getDataFileName(note, baseFileName, existingFileNames) {
let extension;
const existingExtension = path.extname(baseFileName).toLowerCase();
let newExtension;
// following two are handled specifically since we always want to have these extensions no matter the automatic detection
// and/or existing detected extensions in the note name
if (note.type === 'text' && format === 'markdown') {
extension = 'md';
newExtension = 'md';
}
else if (note.type === 'text' && format === 'html') {
newExtension = 'html';
}
else if (note.mime === 'application/x-javascript' || note.mime === 'text/javascript') {
extension = 'js';
newExtension = 'js';
}
else if (existingExtension.length > 0) { // if the page already has an extension, then we'll just keep it
newExtension = null;
}
else {
extension = mimeTypes.extension(note.mime) || "dat";
newExtension = mimeTypes.extension(note.mime) || "dat";
}
let fileName = baseFileName;
const existingExtension = path.extname(fileName).toLowerCase();
// if the note is already named with extension (e.g. "jquery.js"), then it's silly to append exact same extension again
if (existingExtension !== extension) {
fileName += "." + extension;
if (newExtension && existingExtension !== "." + newExtension.toLowerCase()) {
fileName += "." + newExtension;
}
return getUniqueFilename(existingFileNames, fileName);

View File

@@ -13,14 +13,20 @@ const imageType = require('image-type');
const sanitizeFilename = require('sanitize-filename');
async function saveImage(buffer, originalName, parentNoteId, shrinkImageSwitch) {
const origImageFormat = imageType(buffer);
if (origImageFormat.ext === "webp") {
// JIMP does not support webp at the moment: https://github.com/oliver-moran/jimp/issues/144
shrinkImageSwitch = false;
}
const finalImageBuffer = shrinkImageSwitch ? await shrinkImage(buffer, originalName) : buffer;
const imageFormat = imageType(finalImageBuffer);
const parentNote = await repository.getNote(parentNoteId);
const fileNameWithoutExtension = originalName.replace(/\.[^/.]+$/, "");
const fileName = sanitizeFilename(fileNameWithoutExtension + "." + imageFormat.ext);
const fileName = sanitizeFilename(originalName);
const {note} = await noteService.createNote(parentNoteId, fileName, finalImageBuffer, {
target: 'into',
@@ -48,7 +54,7 @@ async function shrinkImage(buffer, originalName) {
try {
finalImageBuffer = await optimize(resizedImage);
} catch (e) {
log.error("Failed to optimize image '" + originalName + "\nStack: " + e.stack);
log.error("Failed to optimize image '" + originalName + "'\nStack: " + e.stack);
finalImageBuffer = resizedImage;
}
@@ -93,7 +99,7 @@ async function optimize(buffer) {
quality: 50
}),
imageminPngQuant({
quality: "0-70"
quality: [0, 0.7]
}),
imageminGifLossy({
lossy: 80,

View File

@@ -74,11 +74,7 @@ function getMime(fileName) {
const ext = path.extname(fileName).toLowerCase();
console.log("EXT", ext);
if (ext in EXTENSION_TO_MIME) {
console.log(EXTENSION_TO_MIME[ext]);
return EXTENSION_TO_MIME[ext];
}
@@ -110,7 +106,7 @@ async function importSingleFile(importContext, file, parentNote) {
}
async function importImage(file, parentNote, importContext) {
const {note} = await imageService.saveImage(file.buffer, getFileNameWithoutExtension(file.originalname), parentNote.noteId, importContext.shrinkImages);
const {note} = await imageService.saveImage(file.buffer, file.originalname, parentNote.noteId, importContext.shrinkImages);
importContext.increaseProgressCount();

View File

@@ -2,7 +2,7 @@
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">Export note</h5>
<h5 class="modal-title">Export note "<span class="export-note-title"></span>"</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>

View File

@@ -36,9 +36,13 @@
</div>
</div>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" style="margin-left: 0;">
<span aria-hidden="true">&times;</span>
</button>
<div style="display: inline-block;">
<button type="button" class="close" data-dismiss="modal" aria-label="Close" style="margin-left: 0;">
<span aria-hidden="true">&times;</span>
</button>
<button class="help-button" type="button" data-help-page="Link-map" title="Help on Link map">?</button>
</div>
</div>
<div class="modal-body" style="outline: none; overflow: hidden;">
<div id="link-map-container"></div>

View File

@@ -72,7 +72,7 @@
document.cookie = name + "=" + (value || "") + expires + "; path=/";
}
</script>
<link href="libraries/bootstrap/css/bootstrap.min.css" rel="stylesheet">
</body>
<link href="libraries/bootstrap/css/bootstrap.min.css" rel="stylesheet">
</body>
</html>

View File

@@ -49,7 +49,9 @@
</div>
<div class="note-detail-component-wrapper">
<div class="note-detail-text note-detail-component" tabindex="10000"></div>
<div class="note-detail-text note-detail-component" tabindex="10000">
<div class="note-detail-text-editor"></div>
</div>
<div class="note-detail-code note-detail-component"></div>

View File

@@ -11,9 +11,13 @@
<table class="note-detail-promoted-attributes"></table>
<div class="note-detail-component-wrapper">
<div class="note-detail-text note-detail-component" tabindex="10000"></div>
<div class="note-detail-text note-detail-component">
<div class="note-detail-text-editor" tabindex="10000"></div>
</div>
<div class="note-detail-code note-detail-component"></div>
<div class="note-detail-code note-detail-component">
<div class="note-detail-code-editor"></div>
</div>
<% include details/empty.ejs %>