Compare commits

...

5 Commits

Author SHA1 Message Date
zadam
38e7649ac3 release 0.37.4 2019-11-22 22:38:03 +01:00
zadam
7a2c7edd7e allow multiple instances of @in operator, closes #716 2019-11-22 21:17:46 +01:00
zadam
cfb850acb2 download fixes for the sub-domain web deployment 2019-11-22 20:35:17 +01:00
zadam
a16aaf7a81 fix setup on non-root paths #404 2019-11-22 20:24:49 +01:00
zadam
522f71cb91 fix tree clipboard 2019-11-20 19:24:23 +01:00
14 changed files with 76 additions and 50 deletions

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{ {
"name": "trilium", "name": "trilium",
"version": "0.37.2", "version": "0.37.3",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {

View File

@@ -2,7 +2,7 @@
"name": "trilium", "name": "trilium",
"productName": "Trilium Notes", "productName": "Trilium Notes",
"description": "Trilium Notes", "description": "Trilium Notes",
"version": "0.37.3", "version": "0.37.4",
"license": "AGPL-3.0-only", "license": "AGPL-3.0-only",
"main": "electron.js", "main": "electron.js",
"bin": { "bin": {

View File

@@ -74,7 +74,7 @@ $form.on('submit', () => {
function exportBranch(branchId, type, format, version) { function exportBranch(branchId, type, format, version) {
taskId = utils.randomString(10); taskId = utils.randomString(10);
const url = utils.getHost() + `/api/notes/${branchId}/export/${type}/${format}/${version}/${taskId}`; const url = utils.getUrlForDownload(`api/notes/${branchId}/export/${type}/${format}/${version}/${taskId}`);
utils.download(url); utils.download(url);
} }

View File

@@ -102,7 +102,9 @@ async function setContentPane() {
const $downloadButton = $('<button class="btn btn-sm btn-primary" type="button">Download</button>'); const $downloadButton = $('<button class="btn btn-sm btn-primary" type="button">Download</button>');
$downloadButton.on('click', () => { $downloadButton.on('click', () => {
utils.download(utils.getHost() + `/api/notes/${revisionItem.noteId}/revisions/${revisionItem.noteRevisionId}/download`); const url = utils.getUrlForDownload(`api/notes/${revisionItem.noteId}/revisions/${revisionItem.noteRevisionId}/download`);
utils.download(url);
}); });
$titleButtons.append($downloadButton); $titleButtons.append($downloadButton);

View File

@@ -4,83 +4,97 @@ import cloningService from "./cloning.js";
import toastService from "./toast.js"; import toastService from "./toast.js";
import hoistedNoteService from "./hoisted_note.js"; import hoistedNoteService from "./hoisted_note.js";
let clipboardIds = []; /*
* Clipboard contains node keys which are not stable. If a (part of the) tree is reloaded,
* node keys in the clipboard might not exist anymore. Code here should then be ready to deal
* with this.
*/
let clipboardNodeKeys = [];
let clipboardMode = null; let clipboardMode = null;
async function pasteAfter(node) { async function pasteAfter(afterNode) {
if (isClipboardEmpty()) {
return;
}
if (clipboardMode === 'cut') { if (clipboardMode === 'cut') {
const nodes = clipboardIds.map(nodeKey => treeUtils.getNodeByKey(nodeKey)); const nodes = clipboardNodeKeys.map(nodeKey => treeUtils.getNodeByKey(nodeKey));
await treeChangesService.moveAfterNode(nodes, node); await treeChangesService.moveAfterNode(nodes, afterNode);
clipboardIds = []; clipboardNodeKeys = [];
clipboardMode = null; clipboardMode = null;
} }
else if (clipboardMode === 'copy') { else if (clipboardMode === 'copy') {
for (const noteId of clipboardIds) { for (const nodeKey of clipboardNodeKeys) {
await cloningService.cloneNoteAfter(noteId, node.data.branchId); const clipNode = treeUtils.getNodeByKey(nodeKey);
await cloningService.cloneNoteAfter(clipNode.data.noteId, afterNode.data.branchId);
} }
// copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places // copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places
} }
else if (clipboardIds.length === 0) {
// just do nothing
}
else { else {
toastService.throwError("Unrecognized clipboard mode=" + clipboardMode); toastService.throwError("Unrecognized clipboard mode=" + clipboardMode);
} }
} }
async function pasteInto(node) { async function pasteInto(parentNode) {
if (isClipboardEmpty()) {
return;
}
if (clipboardMode === 'cut') { if (clipboardMode === 'cut') {
const nodes = clipboardIds.map(nodeKey => treeUtils.getNodeByKey(nodeKey)); const nodes = clipboardNodeKeys.map(nodeKey => treeUtils.getNodeByKey(nodeKey));
await treeChangesService.moveToNode(nodes, node); await treeChangesService.moveToNode(nodes, parentNode);
await node.setExpanded(true); await parentNode.setExpanded(true);
clipboardIds = []; clipboardNodeKeys = [];
clipboardMode = null; clipboardMode = null;
} }
else if (clipboardMode === 'copy') { else if (clipboardMode === 'copy') {
for (const noteId of clipboardIds) { for (const nodeKey of clipboardNodeKeys) {
await cloningService.cloneNoteTo(noteId, node.data.noteId); const clipNode = treeUtils.getNodeByKey(nodeKey);
await cloningService.cloneNoteTo(clipNode.data.noteId, parentNode.data.noteId);
} }
await node.setExpanded(true); await parentNode.setExpanded(true);
// copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places // copy will keep clipboardIds and clipboardMode so it's possible to paste into multiple places
} }
else if (clipboardIds.length === 0) {
// just do nothing
}
else { else {
toastService.throwError("Unrecognized clipboard mode=" + mode); toastService.throwError("Unrecognized clipboard mode=" + mode);
} }
} }
function copy(nodes) { function copy(nodes) {
clipboardIds = nodes.map(node => node.data.noteId); clipboardNodeKeys = nodes.map(node => node.key);
clipboardMode = 'copy'; clipboardMode = 'copy';
toastService.showMessage("Note(s) have been copied into clipboard."); toastService.showMessage("Note(s) have been copied into clipboard.");
} }
function cut(nodes) { function cut(nodes) {
clipboardIds = nodes clipboardNodeKeys = nodes
.filter(node => node.data.noteId !== hoistedNoteService.getHoistedNoteNoPromise()) .filter(node => node.data.noteId !== hoistedNoteService.getHoistedNoteNoPromise())
.filter(node => node.getParent().data.noteType !== 'search') .filter(node => node.getParent().data.noteType !== 'search')
.map(node => node.data.noteId); .map(node => node.key);
if (clipboardIds.length > 0) { if (clipboardNodeKeys.length > 0) {
clipboardMode = 'cut'; clipboardMode = 'cut';
toastService.showMessage("Note(s) have been cut into clipboard."); toastService.showMessage("Note(s) have been cut into clipboard.");
} }
} }
function isEmpty() { function isClipboardEmpty() {
return clipboardIds.length === 0; clipboardNodeKeys = clipboardNodeKeys.filter(key => !!treeUtils.getNodeByKey(key));
return clipboardNodeKeys.length === 0;
} }
export default { export default {
@@ -88,5 +102,5 @@ export default {
pasteInto, pasteInto,
cut, cut,
copy, copy,
isEmpty isClipboardEmpty
} }

View File

@@ -185,8 +185,7 @@ class NoteDetailBook {
} }
else if (type === 'file') { else if (type === 'file') {
function getFileUrl() { function getFileUrl() {
// electron needs absolute URL so we extract current host, port, protocol return utils.getUrlForDownload("api/notes/" + note.noteId + "/download");
return utils.getHost() + "/api/notes/" + note.noteId + "/download";
} }
const $downloadButton = $('<button class="file-download btn btn-primary" type="button">Download</button>'); const $downloadButton = $('<button class="file-download btn btn-primary" type="button">Download</button>');

View File

@@ -87,8 +87,7 @@ class NoteDetailFile {
} }
getFileUrl() { getFileUrl() {
// electron needs absolute URL so we extract current host, port, protocol return utils.getUrlForDownload("api/notes/" + this.ctx.note.noteId + "/download");
return utils.getHost() + "/api/notes/" + this.ctx.note.noteId + "/download";
} }
show() {} show() {}

View File

@@ -98,8 +98,7 @@ class NoteDetailImage {
} }
getFileUrl() { getFileUrl() {
// electron needs absolute URL so we extract current host, port, protocol return utils.getUrlForDownload(`api/notes/${this.ctx.note.noteId}/download`);
return utils.getHost() + `/api/notes/${this.ctx.note.noteId}/download`;
} }
show() {} show() {}

View File

@@ -75,9 +75,9 @@ class TreeContextMenu {
{ title: "Move to ... <kbd>Ctrl+Shift+X</kbd>", cmd: "moveTo", uiIcon: "empty", { title: "Move to ... <kbd>Ctrl+Shift+X</kbd>", cmd: "moveTo", uiIcon: "empty",
enabled: isNotRoot && !isHoisted && parentNotSearch }, enabled: isNotRoot && !isHoisted && parentNotSearch },
{ title: "Paste into <kbd>Ctrl+V</kbd>", cmd: "pasteInto", uiIcon: "paste", { title: "Paste into <kbd>Ctrl+V</kbd>", cmd: "pasteInto", uiIcon: "paste",
enabled: !clipboard.isEmpty() && notSearch && noSelectedNotes }, enabled: !clipboard.isClipboardEmpty() && notSearch && noSelectedNotes },
{ title: "Paste after", cmd: "pasteAfter", uiIcon: "paste", { title: "Paste after", cmd: "pasteAfter", uiIcon: "paste",
enabled: !clipboard.isEmpty() && isNotRoot && parentNotSearch && noSelectedNotes }, enabled: !clipboard.isClipboardEmpty() && isNotRoot && !isHoisted && parentNotSearch && noSelectedNotes },
{ title: "Duplicate note here", cmd: "duplicateNote", uiIcon: "empty", { title: "Duplicate note here", cmd: "duplicateNote", uiIcon: "empty",
enabled: noSelectedNotes && parentNotSearch && (!note.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) }, enabled: noSelectedNotes && parentNotSearch && (!note.isProtected || protectedSessionHolder.isProtectedSessionAvailable()) },
{ title: "----" }, { title: "----" },

View File

@@ -214,6 +214,20 @@ async function clearBrowserCache() {
} }
} }
/**
* @param url - should be without initial slash!!!
*/
function getUrlForDownload(url) {
if (isElectron()) {
// electron needs absolute URL so we extract current host, port, protocol
return getHost() + '/' + url;
}
else {
// web server can be deployed on subdomain so we need to use relative path
return url;
}
}
export default { export default {
reloadApp, reloadApp,
parseDate, parseDate,
@@ -230,7 +244,6 @@ export default {
escapeHtml, escapeHtml,
stopWatch, stopWatch,
formatLabel, formatLabel,
getHost,
download, download,
toObject, toObject,
randomString, randomString,
@@ -245,5 +258,6 @@ export default {
getMimeTypeClass, getMimeTypeClass,
closeActiveDialog, closeActiveDialog,
isHtmlEmpty, isHtmlEmpty,
clearBrowserCache clearBrowserCache,
getUrlForDownload
}; };

View File

@@ -76,12 +76,12 @@ function SetupModel() {
} }
// not using server.js because it loads too many dependencies // not using server.js because it loads too many dependencies
$.post('/api/setup/new-document', { $.post('api/setup/new-document', {
username: username, username: username,
password: password1, password: password1,
theme: theme theme: theme
}).then(() => { }).then(() => {
window.location.replace("/"); window.location.replace("./");
}); });
} }
else if (this.setupType() === 'sync-from-server') { else if (this.setupType() === 'sync-from-server') {
@@ -128,10 +128,10 @@ function SetupModel() {
} }
async function checkOutstandingSyncs() { async function checkOutstandingSyncs() {
const { stats, initialized } = await $.get('/api/sync/stats'); const { stats, initialized } = await $.get('api/sync/stats');
if (initialized) { if (initialized) {
window.location.replace("/"); window.location.replace("./");
} }
const totalOutstandingSyncs = stats.outstandingPushes + stats.outstandingPulls; const totalOutstandingSyncs = stats.outstandingPushes + stats.outstandingPulls;

View File

@@ -1 +1 @@
module.exports = { buildDate:"2019-11-19T23:05:54+01:00", buildRevision: "07043fb177afb9d754428a410b3019d53d7b6fa0" }; module.exports = { buildDate:"2019-11-22T22:38:03+01:00", buildRevision: "7a2c7edd7e9b975bf64f732629e711379baecf48" };

View File

@@ -35,9 +35,9 @@ async function searchForNoteIds(searchString) {
} }
} }
const isInFilter = filters.find(filter => filter.name.toLowerCase() === 'in'); const isInFilters = filters.filter(filter => filter.name.toLowerCase() === 'in');
if (isInFilter) { for (const isInFilter of isInFilters) {
if (isInFilter.operator === '=') { if (isInFilter.operator === '=') {
noteIds = noteIds.filter(noteId => noteCacheService.isInAncestor(noteId, isInFilter.value)); noteIds = noteIds.filter(noteId => noteCacheService.isInAncestor(noteId, isInFilter.value));
} }

View File

@@ -138,7 +138,6 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
const baseApiUrl = 'api/';
const glob = { const glob = {
sourceId: '' sourceId: ''
}; };