mirror of
https://github.com/zadam/trilium.git
synced 2025-10-29 09:16:45 +01:00
Compare commits
9 Commits
v0.51.1-be
...
v0.51.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26e1ff4e16 | ||
|
|
b3763eed61 | ||
|
|
f9c01851ef | ||
|
|
6b61b0604a | ||
|
|
f705c432fd | ||
|
|
70edd9a210 | ||
|
|
0a45b58784 | ||
|
|
dbd312c88d | ||
|
|
11578b1bc3 |
BIN
db/demo.zip
BIN
db/demo.zip
Binary file not shown.
@@ -2,7 +2,7 @@
|
|||||||
"name": "trilium",
|
"name": "trilium",
|
||||||
"productName": "Trilium Notes",
|
"productName": "Trilium Notes",
|
||||||
"description": "Trilium Notes",
|
"description": "Trilium Notes",
|
||||||
"version": "0.51.1-beta",
|
"version": "0.51.2",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"main": "electron.js",
|
"main": "electron.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ export default class ButtonWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.$widget
|
this.$widget
|
||||||
.attr("title", this.settings.title)
|
|
||||||
.addClass(this.settings.icon);
|
.addClass(this.settings.icon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import ButtonWidget from "./button_widget.js";
|
import ButtonWidget from "./button_widget.js";
|
||||||
import appContext from "../../services/app_context.js";
|
import appContext from "../../services/app_context.js";
|
||||||
|
import attributeService from "../../services/attributes.js";
|
||||||
|
import protectedSessionHolder from "../../services/protected_session_holder.js";
|
||||||
|
|
||||||
export default class EditButton extends ButtonWidget {
|
export default class EditButton extends ButtonWidget {
|
||||||
isEnabled() {
|
isEnabled() {
|
||||||
@@ -22,9 +24,29 @@ export default class EditButton extends ButtonWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async refreshWithNote(note) {
|
async refreshWithNote(note) {
|
||||||
// can't do this in isEnabled() since isReadOnly is async
|
if (note.isProtected && !protectedSessionHolder.isProtectedSessionAvailable()) {
|
||||||
this.toggleInt(await this.noteContext.isReadOnly());
|
this.toggleInt(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// prevent flickering by assuming hidden before async operation
|
||||||
|
this.toggleInt(false);
|
||||||
|
|
||||||
|
// can't do this in isEnabled() since isReadOnly is async
|
||||||
|
this.toggleInt(await this.noteContext.isReadOnly());
|
||||||
|
}
|
||||||
|
|
||||||
await super.refreshWithNote(note);
|
await super.refreshWithNote(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
entitiesReloadedEvent({loadResults}) {
|
||||||
|
if (loadResults.getAttributes().find(
|
||||||
|
attr => attr.type === 'label'
|
||||||
|
&& attr.name.toLowerCase().includes("readonly")
|
||||||
|
&& attributeService.isAffecting(attr, this.note)
|
||||||
|
)) {
|
||||||
|
this.noteContext.readOnlyTemporarilyDisabled = false;
|
||||||
|
|
||||||
|
this.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ export default class EditableTextTypeWidget extends AbstractTextTypeWidget {
|
|||||||
await this.initialized;
|
await this.initialized;
|
||||||
|
|
||||||
this.textEditor.model.change(writer => {
|
this.textEditor.model.change(writer => {
|
||||||
const insertPosition = this.textEditor.model.document.selection.getFirstPosition();
|
const insertPosition = this.textEditor.model.document.selection.getLastPosition();
|
||||||
writer.insertText(text, insertPosition);
|
writer.insertText(text, insertPosition);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
import NoteContextAwareWidget from "../note_context_aware_widget.js";
|
||||||
|
import appContext from "../../services/app_context.js";
|
||||||
|
|
||||||
export default class TypeWidget extends NoteContextAwareWidget {
|
export default class TypeWidget extends NoteContextAwareWidget {
|
||||||
// for overriding
|
// for overriding
|
||||||
@@ -34,7 +35,7 @@ export default class TypeWidget extends NoteContextAwareWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isActive() {
|
isActive() {
|
||||||
return this.$widget.is(":visible");
|
return this.$widget.is(":visible") && this.noteContext?.ntxId === appContext.tabManager.activeNtxId;
|
||||||
}
|
}
|
||||||
|
|
||||||
getContent() {}
|
getContent() {}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
module.exports = { buildDate:"2022-04-22T00:07:59+02:00", buildRevision: "3b58b83f8bb93c04263081f60d75f211320ed065" };
|
module.exports = { buildDate:"2022-05-01T23:18:35+02:00", buildRevision: "b3763eed610fa3f2aabbcbdbd21efca704a5dd08" };
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const utils = require("../../utils");
|
|||||||
|
|
||||||
// FIXME: create common subclass with NoteContentUnprotectedFulltextExp to avoid duplication
|
// FIXME: create common subclass with NoteContentUnprotectedFulltextExp to avoid duplication
|
||||||
class NoteContentProtectedFulltextExp extends Expression {
|
class NoteContentProtectedFulltextExp extends Expression {
|
||||||
constructor(operator, tokens, raw) {
|
constructor(operator, {tokens, raw, flatText}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (operator !== '*=*') {
|
if (operator !== '*=*') {
|
||||||
@@ -19,6 +19,7 @@ class NoteContentProtectedFulltextExp extends Expression {
|
|||||||
|
|
||||||
this.tokens = tokens;
|
this.tokens = tokens;
|
||||||
this.raw = !!raw;
|
this.raw = !!raw;
|
||||||
|
this.flatText = !!flatText;
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(inputNoteSet) {
|
execute(inputNoteSet) {
|
||||||
@@ -33,7 +34,7 @@ class NoteContentProtectedFulltextExp extends Expression {
|
|||||||
for (let {noteId, type, mime, content} of sql.iterateRows(`
|
for (let {noteId, type, mime, content} of sql.iterateRows(`
|
||||||
SELECT noteId, type, mime, content
|
SELECT noteId, type, mime, content
|
||||||
FROM notes JOIN note_contents USING (noteId)
|
FROM notes JOIN note_contents USING (noteId)
|
||||||
WHERE type IN ('text', 'code') AND isDeleted = 0 AND isProtected = 1`)) {
|
WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0 AND isProtected = 1`)) {
|
||||||
|
|
||||||
if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) {
|
if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -49,7 +50,17 @@ class NoteContentProtectedFulltextExp extends Expression {
|
|||||||
|
|
||||||
content = this.preprocessContent(content, type, mime);
|
content = this.preprocessContent(content, type, mime);
|
||||||
|
|
||||||
if (!this.tokens.find(token => !content.includes(token))) {
|
const nonMatchingToken = this.tokens.find(token =>
|
||||||
|
!content.includes(token) &&
|
||||||
|
(
|
||||||
|
// in case of default fulltext search we should consider both title, attrs and content
|
||||||
|
// so e.g. "hello world" should match when "hello" is in title and "world" in content
|
||||||
|
!this.flatText
|
||||||
|
|| !becca.notes[noteId].getFlatText().includes(token)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!nonMatchingToken) {
|
||||||
resultNoteSet.add(becca.notes[noteId]);
|
resultNoteSet.add(becca.notes[noteId]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const utils = require("../../utils");
|
|||||||
|
|
||||||
// FIXME: create common subclass with NoteContentProtectedFulltextExp to avoid duplication
|
// FIXME: create common subclass with NoteContentProtectedFulltextExp to avoid duplication
|
||||||
class NoteContentUnprotectedFulltextExp extends Expression {
|
class NoteContentUnprotectedFulltextExp extends Expression {
|
||||||
constructor(operator, tokens, raw) {
|
constructor(operator, {tokens, raw, flatText}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
if (operator !== '*=*') {
|
if (operator !== '*=*') {
|
||||||
@@ -17,6 +17,7 @@ class NoteContentUnprotectedFulltextExp extends Expression {
|
|||||||
|
|
||||||
this.tokens = tokens;
|
this.tokens = tokens;
|
||||||
this.raw = !!raw;
|
this.raw = !!raw;
|
||||||
|
this.flatText = !!flatText;
|
||||||
}
|
}
|
||||||
|
|
||||||
execute(inputNoteSet) {
|
execute(inputNoteSet) {
|
||||||
@@ -27,7 +28,7 @@ class NoteContentUnprotectedFulltextExp extends Expression {
|
|||||||
for (let {noteId, type, mime, content} of sql.iterateRows(`
|
for (let {noteId, type, mime, content} of sql.iterateRows(`
|
||||||
SELECT noteId, type, mime, content
|
SELECT noteId, type, mime, content
|
||||||
FROM notes JOIN note_contents USING (noteId)
|
FROM notes JOIN note_contents USING (noteId)
|
||||||
WHERE type IN ('text', 'code') AND isDeleted = 0 AND isProtected = 0`)) {
|
WHERE type IN ('text', 'code', 'mermaid') AND isDeleted = 0 AND isProtected = 0`)) {
|
||||||
|
|
||||||
if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) {
|
if (!inputNoteSet.hasNoteId(noteId) || !(noteId in becca.notes)) {
|
||||||
continue;
|
continue;
|
||||||
@@ -35,7 +36,17 @@ class NoteContentUnprotectedFulltextExp extends Expression {
|
|||||||
|
|
||||||
content = this.preprocessContent(content, type, mime);
|
content = this.preprocessContent(content, type, mime);
|
||||||
|
|
||||||
if (!this.tokens.find(token => !content.includes(token))) {
|
const nonMatchingToken = this.tokens.find(token =>
|
||||||
|
!content.includes(token) &&
|
||||||
|
(
|
||||||
|
// in case of default fulltext search we should consider both title, attrs and content
|
||||||
|
// so e.g. "hello world" should match when "hello" is in title and "world" in content
|
||||||
|
!this.flatText
|
||||||
|
|| !becca.notes[noteId].getFlatText().includes(token)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!nonMatchingToken) {
|
||||||
resultNoteSet.add(becca.notes[noteId]);
|
resultNoteSet.add(becca.notes[noteId]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ function getFulltext(tokens, searchContext) {
|
|||||||
if (!searchContext.fastSearch) {
|
if (!searchContext.fastSearch) {
|
||||||
return new OrExp([
|
return new OrExp([
|
||||||
new NoteFlatTextExp(tokens),
|
new NoteFlatTextExp(tokens),
|
||||||
new NoteContentProtectedFulltextExp('*=*', tokens),
|
new NoteContentProtectedFulltextExp('*=*', {tokens, flatText: true}),
|
||||||
new NoteContentUnprotectedFulltextExp('*=*', tokens)
|
new NoteContentUnprotectedFulltextExp('*=*', {tokens, flatText: true})
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -141,8 +141,8 @@ function getExpression(tokens, searchContext, level = 0) {
|
|||||||
i++;
|
i++;
|
||||||
|
|
||||||
return new OrExp([
|
return new OrExp([
|
||||||
new NoteContentUnprotectedFulltextExp(operator, [tokens[i].token], raw),
|
new NoteContentUnprotectedFulltextExp(operator, {tokens: [tokens[i].token], raw }),
|
||||||
new NoteContentProtectedFulltextExp(operator, [tokens[i].token], raw)
|
new NoteContentProtectedFulltextExp(operator, {tokens: [tokens[i].token], raw })
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,8 +196,8 @@ function getExpression(tokens, searchContext, level = 0) {
|
|||||||
|
|
||||||
return new OrExp([
|
return new OrExp([
|
||||||
new PropertyComparisonExp(searchContext, 'title', '*=*', tokens[i].token),
|
new PropertyComparisonExp(searchContext, 'title', '*=*', tokens[i].token),
|
||||||
new NoteContentProtectedFulltextExp('*=*', [tokens[i].token]),
|
new NoteContentProtectedFulltextExp('*=*', {tokens: [tokens[i].token]}),
|
||||||
new NoteContentUnprotectedFulltextExp('*=*', [tokens[i].token])
|
new NoteContentUnprotectedFulltextExp('*=*', {tokens: [tokens[i].token]})
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,16 +62,18 @@ function register(router) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/share/:shareId', (req, res, next) => {
|
router.get('/share/:shareId', (req, res, next) => {
|
||||||
const {shareId} = req.params;
|
|
||||||
|
|
||||||
shacaLoader.ensureLoad();
|
shacaLoader.ensureLoad();
|
||||||
|
|
||||||
|
const {shareId} = req.params;
|
||||||
|
|
||||||
const note = shaca.aliasToNote[shareId] || shaca.notes[shareId];
|
const note = shaca.aliasToNote[shareId] || shaca.notes[shareId];
|
||||||
|
|
||||||
renderNote(note, res);
|
renderNote(note, res);
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get('/share/api/notes/:noteId', (req, res, next) => {
|
router.get('/share/api/notes/:noteId', (req, res, next) => {
|
||||||
|
shacaLoader.ensureLoad();
|
||||||
|
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const note = shaca.getNote(noteId);
|
const note = shaca.getNote(noteId);
|
||||||
|
|
||||||
@@ -85,6 +87,8 @@ function register(router) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/share/api/notes/:noteId/download', (req, res, next) => {
|
router.get('/share/api/notes/:noteId/download', (req, res, next) => {
|
||||||
|
shacaLoader.ensureLoad();
|
||||||
|
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const note = shaca.getNote(noteId);
|
const note = shaca.getNote(noteId);
|
||||||
|
|
||||||
@@ -107,6 +111,8 @@ function register(router) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.get('/share/api/images/:noteId/:filename', (req, res, next) => {
|
router.get('/share/api/images/:noteId/:filename', (req, res, next) => {
|
||||||
|
shacaLoader.ensureLoad();
|
||||||
|
|
||||||
const image = shaca.getNote(req.params.noteId);
|
const image = shaca.getNote(req.params.noteId);
|
||||||
|
|
||||||
if (!image) {
|
if (!image) {
|
||||||
@@ -118,13 +124,15 @@ function register(router) {
|
|||||||
|
|
||||||
addNoIndexHeader(image, res);
|
addNoIndexHeader(image, res);
|
||||||
|
|
||||||
res.set('Content-Type', image.mime);
|
res.setHeader('Content-Type', image.mime);
|
||||||
|
|
||||||
res.send(image.getContent());
|
res.send(image.getContent());
|
||||||
});
|
});
|
||||||
|
|
||||||
// used for PDF viewing
|
// used for PDF viewing
|
||||||
router.get('/share/api/notes/:noteId/view', (req, res, next) => {
|
router.get('/share/api/notes/:noteId/view', (req, res, next) => {
|
||||||
|
shacaLoader.ensureLoad();
|
||||||
|
|
||||||
const {noteId} = req.params;
|
const {noteId} = req.params;
|
||||||
const note = shaca.getNote(noteId);
|
const note = shaca.getNote(noteId);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user