Compare commits

...

8 Commits

12 changed files with 24407 additions and 12814 deletions

2
package-lock.json generated
View File

@@ -1,6 +1,6 @@
{
"name": "trilium",
"version": "0.26.1",
"version": "0.27.0-beta",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

View File

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

View File

@@ -85,8 +85,11 @@ async function showAttributes() {
$promotedAttributesContainer.empty().append($tbody);
}
else if (note.type !== 'relation-map') {
if (attributes.length > 0) {
for (const attribute of attributes) {
// display only "own" notes
const ownedAttributes = attributes.filter(attr => attr.noteId === note.noteId);
if (ownedAttributes.length > 0) {
for (const attribute of ownedAttributes) {
if (attribute.type === 'label') {
$attributeListInner.append(utils.formatLabel(attribute) + " ");
}
@@ -132,7 +135,9 @@ async function createPromotedAttributeRow(definitionAttr, valueAttr) {
const $inputCell = $("<td>").append($("<div>").addClass("input-group").append($input));
const $actionCell = $("<td>");
const $multiplicityCell = $("<td>").addClass("multiplicity");
const $multiplicityCell = $("<td>")
.addClass("multiplicity")
.attr("nowrap", true);
$tr
.append($labelCell)

View File

@@ -7,6 +7,7 @@ import treeCache from './tree_cache.js';
import noteDetailService from './note_detail.js';
import noteTypeService from './note_type.js';
import noteTooltipService from './note_tooltip.js';
import protectedSessionService from'./protected_session.js';
/**
* This is the main frontend API interface for scripts. It's published in the local "api" object.
@@ -42,7 +43,7 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
this.activateNewNote = async notePath => {
await treeService.reload();
await treeService.activateNote(notePath, true);
await treeService.activateNote(notePath, noteDetailService.focusOnTitle);
};
/**
@@ -244,7 +245,12 @@ function FrontendScriptApi(startNote, currentNote, originEntity = null) {
* @method
* @param {object} $el - jquery object on which to setup the tooltip
*/
this.setupElementTooltip = noteTooltipService.setupElementTooltip
this.setupElementTooltip = noteTooltipService.setupElementTooltip;
/**
* @method
*/
this.protectCurrentNote = protectedSessionService.protectNoteAndSendToServer;
}
export default FrontendScriptApi;

View File

@@ -37,6 +37,8 @@ let noteChangeDisabled = false;
let isNoteChanged = false;
let detailLoadedListeners = [];
const components = {
'code': noteDetailCode,
'text': noteDetailText,
@@ -147,12 +149,6 @@ function setNoteBackgroundIfProtected(note) {
$unprotectButton.prop("disabled", !protectedSessionHolder.isProtectedSessionAvailable());
}
let isNewNoteCreated = false;
function newNoteCreated() {
isNewNoteCreated = true;
}
async function handleProtectedSession() {
const newSessionCreated = await protectedSessionService.ensureProtectedSession(currentNote.isProtected, false);
@@ -191,12 +187,6 @@ async function loadNoteDetail(noteId) {
attributeService.invalidateAttributes();
}
if (isNewNoteCreated) {
isNewNoteCreated = false;
$noteTitle.focus().select();
}
$noteIdDisplay.html(noteId);
setNoteBackgroundIfProtected(currentNote);
@@ -240,11 +230,13 @@ async function loadNoteDetail(noteId) {
// after loading new note make sure editor is scrolled to the top
getComponent(currentNote.type).scrollToTop();
if (utils.isDesktop()) {
fireDetailLoaded();
$scriptArea.empty();
await bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteView');
if (utils.isDesktop()) {
await attributeService.showAttributes();
await showChildrenOverview();
@@ -291,6 +283,30 @@ function focusOnTitle() {
$noteTitle.focus();
}
/**
* Since detail loading may take some time and user might just browse through the notes using UP-DOWN keys,
* we intentionally decouple activation of the note in the tree and full load of the note so just avaiting on
* fancytree's activate() won't wait for the full load.
*
* This causes an issue where in some cases you want to do some action after detail is loaded. For this reason
* we provide the listeners here which will be triggered after the detail is loaded and if the loaded note
* is the one registered in the listener.
*/
function addDetailLoadedListener(noteId, callback) {
detailLoadedListeners.push({ noteId, callback });
}
function fireDetailLoaded() {
for (const {noteId, callback} of detailLoadedListeners) {
if (noteId === currentNote.noteId) {
callback();
}
}
// all the listeners are one time only
detailLoadedListeners = [];
}
messagingService.subscribeToSyncMessages(syncData => {
if (syncData.some(sync => sync.entityName === 'notes' && sync.entityId === getCurrentNoteId())) {
infoService.showMessage('Reloading note because of background changes');
@@ -325,11 +341,11 @@ export default {
getCurrentNote,
getCurrentNoteType,
getCurrentNoteId,
newNoteCreated,
focusOnTitle,
saveNote,
saveNoteIfChanged,
noteChanged,
getCurrentNoteContent,
onNoteChange
onNoteChange,
addDetailLoadedListener
};

View File

@@ -184,5 +184,6 @@ export default {
protectSubtree,
ensureDialogIsClosed,
enterProtectedSession,
leaveProtectedSession
leaveProtectedSession,
protectNoteAndSendToServer
};

View File

@@ -83,6 +83,10 @@ async function setNodeTitleWithPrefix(node) {
node.setTitle(utils.escapeHtml(title));
}
function getNode(childNoteId, parentNoteId) {
return getNodesByNoteId(childNoteId).find(node => !parentNoteId || node.data.parentNoteId === parentNoteId);
}
async function expandToNote(notePath, expandOpts) {
utils.assertArguments(notePath);
@@ -94,7 +98,18 @@ async function expandToNote(notePath, expandOpts) {
for (const childNoteId of runPath) {
// for first node (!parentNoteId) it doesn't matter which node is found
const node = getNodesByNoteId(childNoteId).find(node => !parentNoteId || node.data.parentNoteId === parentNoteId);
let node = getNode(childNoteId, parentNoteId);
if (!node && parentNoteId) {
const parents = getNodesByNoteId(parentNoteId);
for (const parent of parents) {
// force load parents. This is useful when fancytree doesn't contain recently created notes yet.
await parent.load(true);
}
node = getNode(childNoteId, parentNoteId);
}
if (!node) {
console.error(`Can't find node for noteId=${childNoteId} with parentNoteId=${parentNoteId}`);
@@ -111,7 +126,7 @@ async function expandToNote(notePath, expandOpts) {
}
}
async function activateNote(notePath, newNote) {
async function activateNote(notePath, noteLoadedListener) {
utils.assertArguments(notePath);
const hoistedNoteId = await hoistedNoteService.getHoistedNoteId();
@@ -131,8 +146,8 @@ async function activateNote(notePath, newNote) {
const node = await expandToNote(notePath);
if (newNote) {
noteDetailService.newNoteCreated();
if (noteLoadedListener) {
noteDetailService.addDetailLoadedListener(node.data.noteId, noteLoadedListener);
}
// we use noFocus because when we reload the tree because of background changes
@@ -547,7 +562,7 @@ async function createNote(node, parentNoteId, target, isProtected, saveSelection
await noteDetailService.saveNoteIfChanged();
noteDetailService.newNoteCreated();
noteDetailService.addDetailLoadedListener(note.noteId, noteDetailService.focusOnTitle);
const noteEntity = new NoteShort(treeCache, note);
const branchEntity = new Branch(treeCache, branch);

File diff suppressed because one or more lines are too long

View File

@@ -53,6 +53,7 @@
padding: 10px 0 10px 0;
margin: 0 10px 0 16px;
border: 1px solid #ccc;
border-radius: 5px;
}
#context-menu-container {

View File

@@ -70,6 +70,7 @@ body {
height: 100%;
display: flex;
flex-direction: column;
min-height: 200px;
}
.note-detail-component {
@@ -311,6 +312,12 @@ div.ui-tooltip {
.cm-matchhighlight {background-color: #eeeeee}
#attribute-list {
overflow: auto;
/* limiting the size since actual note content is more important */
max-height: 30%;
}
#label-list, #relation-list, #attribute-list {
color: #777777;
padding: 5px;
@@ -434,8 +441,13 @@ html.theme-dark body {
}
#note-detail-promoted-attributes {
max-width: 70%;
margin: auto;
/* setting the display to block since "table" doesn't support scrolling */
display: block;
flex-basis: content;
flex-shrink: 1;
flex-grow: 100;
overflow: auto;
}
#note-detail-promoted-attributes td, #note-detail-promoted-attributes th {

View File

@@ -1 +1 @@
module.exports = { buildDate:"2018-12-30T22:38:11+01:00", buildRevision: "32220476aa6795bab036b7dd9057ea3357d7dd51" };
module.exports = { buildDate:"2019-01-01T20:54:23+01:00", buildRevision: "1771ddb78783352970ef64906af8c8fe117183d0" };

View File

@@ -153,7 +153,8 @@ async function createNote(parentNoteId, title, content = "", extraOptions = {})
noteId: note.noteId,
type: attr.type,
name: attr.name,
value: attr.value
value: attr.value,
isInheritable: !!attr.isInheritable
});
}
@@ -357,10 +358,12 @@ async function deleteNote(branch) {
const notDeletedBranches = await note.getBranches();
if (notDeletedBranches.length === 0) {
note.isDeleted = true;
// we don't reset content here, that's postponed and done later to give the user
// a chance to correct a mistake
await note.save();
// maybe a bit counter-intuitively, protected notes can be deleted also outside of protected session
// this is because protected notes offer only confidentiality which makes some things simpler - e.g. deletion UI
// to allow this, we just set the isDeleted flag, otherwise saving would fail because of attempt to encrypt
// content with non-existent protected session key
// we don't reset content here, that's postponed and done later to give the user a chance to correct a mistake
await sql.execute("UPDATE notes SET isDeleted = 1 WHERE noteId = ?", [note.noteId]);
for (const noteRevision of await note.getRevisions()) {
await noteRevision.save();