Merge remote-tracking branch 'origin/stable'

# Conflicts:
#	db/demo.zip
#	src/services/notes.js
#	src/services/request.js
This commit is contained in:
zadam 2020-08-10 23:45:17 +02:00
commit 8d0df6ddb9
15 changed files with 210 additions and 172 deletions

View File

@ -1,10 +1,18 @@
/* !!!!!! TRILIUM CUSTOM CHANGES !!!!!! */
.ck-widget__type-around { /* gets rid of triangles: https://github.com/zadam/trilium/issues/1129 */
display: none;
}
/* /*
* CKEditor 5 (v19.1.1) content styles. * CKEditor 5 (v21.0.0) content styles.
* Generated on Fri, 19 Jun 2020 01:26:44 GMT. * Generated on Wed, 29 Jul 2020 12:14:43 GMT.
* For more information, check out https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/content-styles.html * For more information, check out https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/content-styles.html
*/ */
:root { :root {
--ck-color-mention-background: hsla(341, 100%, 30%, 0.1);
--ck-color-mention-text: hsl(341, 100%, 30%);
--ck-highlight-marker-blue: hsl(201, 97%, 72%); --ck-highlight-marker-blue: hsl(201, 97%, 72%);
--ck-highlight-marker-green: hsl(120, 93%, 68%); --ck-highlight-marker-green: hsl(120, 93%, 68%);
--ck-highlight-marker-pink: hsl(345, 96%, 73%); --ck-highlight-marker-pink: hsl(345, 96%, 73%);
@ -15,6 +23,81 @@
--ck-todo-list-checkmark-size: 16px; --ck-todo-list-checkmark-size: 16px;
} }
/* ckeditor5-image/theme/image.css */
.ck-content .image {
display: table;
clear: both;
text-align: center;
margin: 1em auto;
}
/* ckeditor5-image/theme/image.css */
.ck-content .image img {
display: block;
margin: 0 auto;
max-width: 100%;
min-width: 50px;
}
/* ckeditor5-image/theme/imagecaption.css */
.ck-content .image > figcaption {
display: table-caption;
caption-side: bottom;
word-break: break-word;
color: hsl(0, 0%, 20%);
background-color: hsl(0, 0%, 97%);
padding: .6em;
font-size: .75em;
outline-offset: -1px;
}
/* ckeditor5-image/theme/imageresize.css */
.ck-content .image.image_resized {
max-width: 100%;
display: block;
box-sizing: border-box;
}
/* ckeditor5-image/theme/imageresize.css */
.ck-content .image.image_resized img {
width: 100%;
}
/* ckeditor5-image/theme/imageresize.css */
.ck-content .image.image_resized > figcaption {
display: block;
}
/* ckeditor5-image/theme/imagestyle.css */
.ck-content .image-style-side {
float: right;
margin-left: var(--ck-image-style-spacing);
max-width: 50%;
}
/* ckeditor5-image/theme/imagestyle.css */
.ck-content .image-style-align-left {
float: left;
margin-right: var(--ck-image-style-spacing);
}
/* ckeditor5-image/theme/imagestyle.css */
.ck-content .image-style-align-center {
margin-left: auto;
margin-right: auto;
}
/* ckeditor5-image/theme/imagestyle.css */
.ck-content .image-style-align-right {
float: right;
margin-left: var(--ck-image-style-spacing);
}
/* ckeditor5-block-quote/theme/blockquote.css */
.ck-content blockquote {
overflow: hidden;
padding-right: 1.5em;
padding-left: 1.5em;
margin-left: 0;
margin-right: 0;
font-style: italic;
border-left: solid 5px hsl(0, 0%, 80%);
}
/* ckeditor5-block-quote/theme/blockquote.css */
.ck-content[dir="rtl"] blockquote {
border-left: 0;
border-right: solid 5px hsl(0, 0%, 80%);
}
/* ckeditor5-list/theme/todolist.css */ /* ckeditor5-list/theme/todolist.css */
.ck-content .todo-list { .ck-content .todo-list {
list-style: none; list-style: none;
@ -82,12 +165,54 @@
.ck-content .todo-list .todo-list__label .todo-list__label__description { .ck-content .todo-list .todo-list__label .todo-list__label__description {
vertical-align: middle; vertical-align: middle;
} }
/* ckeditor5-media-embed/theme/mediaembed.css */ /* ckeditor5-horizontal-line/theme/horizontalline.css */
.ck-content .media { .ck-content hr {
clear: both; margin: 15px 0;
margin: 1em 0; height: 4px;
display: block; background: hsl(0, 0%, 87%);
min-width: 15em; border: 0;
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .marker-yellow {
background-color: var(--ck-highlight-marker-yellow);
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .marker-green {
background-color: var(--ck-highlight-marker-green);
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .marker-pink {
background-color: var(--ck-highlight-marker-pink);
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .marker-blue {
background-color: var(--ck-highlight-marker-blue);
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .pen-red {
color: var(--ck-highlight-pen-red);
background-color: transparent;
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .pen-green {
color: var(--ck-highlight-pen-green);
background-color: transparent;
}
/* ckeditor5-font/theme/fontsize.css */
.ck-content .text-tiny {
font-size: .7em;
}
/* ckeditor5-font/theme/fontsize.css */
.ck-content .text-small {
font-size: .85em;
}
/* ckeditor5-font/theme/fontsize.css */
.ck-content .text-big {
font-size: 1.4em;
}
/* ckeditor5-font/theme/fontsize.css */
.ck-content .text-huge {
font-size: 1.8em;
} }
/* ckeditor5-basic-styles/theme/code.css */ /* ckeditor5-basic-styles/theme/code.css */
.ck-content code { .ck-content code {
@ -95,21 +220,6 @@
padding: .15em; padding: .15em;
border-radius: 2px; border-radius: 2px;
} }
/* ckeditor5-block-quote/theme/blockquote.css */
.ck-content blockquote {
overflow: hidden;
padding-right: 1.5em;
padding-left: 1.5em;
margin-left: 0;
margin-right: 0;
font-style: italic;
border-left: solid 5px hsl(0, 0%, 80%);
}
/* ckeditor5-block-quote/theme/blockquote.css */
.ck-content[dir="rtl"] blockquote {
border-left: 0;
border-right: solid 5px hsl(0, 0%, 80%);
}
/* ckeditor5-table/theme/table.css */ /* ckeditor5-table/theme/table.css */
.ck-content .table { .ck-content .table {
margin: 1em auto; margin: 1em auto;
@ -143,98 +253,6 @@
.ck-content[dir="ltr"] .table th { .ck-content[dir="ltr"] .table th {
text-align: left; text-align: left;
} }
/* ckeditor5-image/theme/imageresize.css */
.ck-content .image.image_resized {
max-width: 100%;
display: block;
box-sizing: border-box;
}
/* ckeditor5-image/theme/imageresize.css */
.ck-content .image.image_resized img {
width: 100%;
}
/* ckeditor5-image/theme/imageresize.css */
.ck-content .image.image_resized > figcaption {
display: block;
}
/* ckeditor5-image/theme/image.css */
.ck-content .image {
display: table;
clear: both;
text-align: center;
margin: 1em auto;
}
/* ckeditor5-image/theme/image.css */
.ck-content .image img {
display: block;
margin: 0 auto;
max-width: 100%;
min-width: 50px;
}
/* ckeditor5-image/theme/imagecaption.css */
.ck-content .image > figcaption {
display: table-caption;
caption-side: bottom;
word-break: break-word;
color: hsl(0, 0%, 20%);
background-color: hsl(0, 0%, 97%);
padding: .6em;
font-size: .75em;
outline-offset: -1px;
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .marker-yellow {
background-color: var(--ck-highlight-marker-yellow);
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .marker-green {
background-color: var(--ck-highlight-marker-green);
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .marker-pink {
background-color: var(--ck-highlight-marker-pink);
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .marker-blue {
background-color: var(--ck-highlight-marker-blue);
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .pen-red {
color: var(--ck-highlight-pen-red);
background-color: transparent;
}
/* ckeditor5-highlight/theme/highlight.css */
.ck-content .pen-green {
color: var(--ck-highlight-pen-green);
background-color: transparent;
}
/* ckeditor5-image/theme/imagestyle.css */
.ck-content .image-style-side,
.ck-content .image-style-align-left,
.ck-content .image-style-align-center,
.ck-content .image-style-align-right {
max-width: 50%;
}
/* ckeditor5-image/theme/imagestyle.css */
.ck-content .image-style-side {
float: right;
margin-left: var(--ck-image-style-spacing);
}
/* ckeditor5-image/theme/imagestyle.css */
.ck-content .image-style-align-left {
float: left;
margin-right: var(--ck-image-style-spacing);
}
/* ckeditor5-image/theme/imagestyle.css */
.ck-content .image-style-align-center {
margin-left: auto;
margin-right: auto;
}
/* ckeditor5-image/theme/imagestyle.css */
.ck-content .image-style-align-right {
float: right;
margin-left: var(--ck-image-style-spacing);
}
/* ckeditor5-page-break/theme/pagebreak.css */ /* ckeditor5-page-break/theme/pagebreak.css */
.ck-content .page-break { .ck-content .page-break {
position: relative; position: relative;
@ -271,21 +289,12 @@
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
} }
/* ckeditor5-font/theme/fontsize.css */ /* ckeditor5-media-embed/theme/mediaembed.css */
.ck-content .text-tiny { .ck-content .media {
font-size: .7em; clear: both;
} margin: 1em 0;
/* ckeditor5-font/theme/fontsize.css */ display: block;
.ck-content .text-small { min-width: 15em;
font-size: .85em;
}
/* ckeditor5-font/theme/fontsize.css */
.ck-content .text-big {
font-size: 1.4em;
}
/* ckeditor5-font/theme/fontsize.css */
.ck-content .text-huge {
font-size: 1.8em;
} }
/* ckeditor5-code-block/theme/codeblock.css */ /* ckeditor5-code-block/theme/codeblock.css */
.ck-content pre { .ck-content pre {
@ -307,12 +316,10 @@
padding: 0; padding: 0;
border-radius: 0; border-radius: 0;
} }
/* ckeditor5-horizontal-line/theme/horizontalline.css */ /* ckeditor5-mention/theme/mention.css */
.ck-content hr { .ck-content .mention {
margin: 15px 0; background: var(--ck-color-mention-background);
height: 4px; color: var(--ck-color-mention-text);
background: hsl(0, 0%, 87%);
border: 0;
} }
@media print { @media print {
/* ckeditor5-page-break/theme/pagebreak.css */ /* ckeditor5-page-break/theme/pagebreak.css */
@ -324,9 +331,3 @@
display: none; display: none;
} }
} }
/* !!!!!! TRILIUM CUSTOM CHANGES !!!!!! */
.ck-widget__type-around { /* gets rid of triangles: https://github.com/zadam/trilium/issues/1129 */
display: none;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -81,6 +81,8 @@ function setupGlobs() {
$("body").on("click", "a.external", function () { $("body").on("click", "a.external", function () {
window.open($(this).attr("href"), '_blank'); window.open($(this).attr("href"), '_blank');
return false;
}); });
} }

View File

@ -24,7 +24,7 @@ async function getRenderedContent(note) {
.attr("src", `api/images/${note.noteId}/${note.title}`) .attr("src", `api/images/${note.noteId}/${note.title}`)
.css("max-width", "100%"); .css("max-width", "100%");
} }
else if (type === 'file') { else if (type === 'file' || type === 'pdf') {
function getFileUrl() { function getFileUrl() {
return utils.getUrlForDownload("api/notes/" + note.noteId + "/download"); return utils.getUrlForDownload("api/notes/" + note.noteId + "/download");
} }
@ -47,19 +47,21 @@ async function getRenderedContent(note) {
// open doesn't work for protected notes since it works through browser which isn't in protected session // open doesn't work for protected notes since it works through browser which isn't in protected session
$openButton.toggle(!note.isProtected); $openButton.toggle(!note.isProtected);
$rendered = $('<div>'); $rendered = $('<div style="display: flex; flex-direction: column; height: 100%;">');
if (note.mime === 'application/pdf' && utils.isElectron()) { if (type === 'pdf') {
const $pdfPreview = $('<iframe class="pdf-preview" style="width: 100%; height: 100%; flex-grow: 100;"></iframe>'); const $pdfPreview = $('<iframe class="pdf-preview" style="width: 100%; flex-grow: 100;"></iframe>');
$pdfPreview.attr("src", utils.getUrlForDownload("api/notes/" + note.noteId + "/open")); $pdfPreview.attr("src", utils.getUrlForDownload("api/notes/" + note.noteId + "/open"));
$rendered.append($pdfPreview); $rendered.append($pdfPreview);
} }
$rendered $rendered.append(
.append($downloadButton) $("<div>")
.append(' &nbsp; ') .append($downloadButton)
.append($openButton); .append(' &nbsp; ')
.append($openButton)
);
} }
else if (type === 'render') { else if (type === 'render') {
$rendered = $('<div>'); $rendered = $('<div>');
@ -90,6 +92,10 @@ async function getRenderedContent(note) {
function getRenderingType(note) { function getRenderingType(note) {
let type = note.type; let type = note.type;
if (type === 'file' && note.mime === 'application/pdf' && utils.isElectron()) {
type = 'pdf';
}
if (note.isProtected) { if (note.isProtected) {
if (protectedSessionHolder.isProtectedSessionAvailable()) { if (protectedSessionHolder.isProtectedSessionAvailable()) {
protectedSessionHolder.touchProtectedSession(); protectedSessionHolder.touchProtectedSession();
@ -104,4 +110,4 @@ function getRenderingType(note) {
export default { export default {
getRenderedContent getRenderedContent
}; };

View File

@ -288,6 +288,13 @@ class TreeCache {
async getNoteComplement(noteId) { async getNoteComplement(noteId) {
if (!this.noteComplementPromises[noteId]) { if (!this.noteComplementPromises[noteId]) {
this.noteComplementPromises[noteId] = server.get('notes/' + noteId).then(row => new NoteComplement(row)); this.noteComplementPromises[noteId] = server.get('notes/' + noteId).then(row => new NoteComplement(row));
// we don't want to keep large payloads forever in memory so we clean that up quite quickly
// this cache is more meant to share the data between different components within one business transaction (e.g. loading of the note into the tab context and all the components)
// this is also a work around for missing invalidation after change
this.noteComplementPromises[noteId].then(
() => setTimeout(() => this.noteComplementPromises[noteId] = null, 1000)
);
} }
return await this.noteComplementPromises[noteId]; return await this.noteComplementPromises[noteId];

View File

@ -329,4 +329,9 @@ export default class NoteDetailWidget extends TabAwareWidget {
saveSelection: true saveSelection: true
}); });
} }
// used by cutToNote in CKEditor build
async saveNoteDetailNowCommand() {
await this.spacedUpdate.updateNowIfNecessary();
}
} }

View File

@ -305,6 +305,10 @@ export default class NoteTreeWidget extends TabAwareWidget {
keyboard: false, // we takover keyboard handling in the hotkeys plugin keyboard: false, // we takover keyboard handling in the hotkeys plugin
extensions: utils.isMobile() ? ["dnd5", "clones"] : ["hotkeys", "dnd5", "clones"], extensions: utils.isMobile() ? ["dnd5", "clones"] : ["hotkeys", "dnd5", "clones"],
source: treeData, source: treeData,
scrollOfs: {
top: 200,
bottom: 200
},
scrollParent: this.$tree, scrollParent: this.$tree,
minExpandLevel: 2, // root can't be collapsed minExpandLevel: 2, // root can't be collapsed
click: (event, data) => { click: (event, data) => {

View File

@ -36,10 +36,10 @@ export default class AbstractTextTypeWidget extends TypeWidget {
.append($link) .append($link)
); );
const {renderedContent} = await noteContentRenderer.getRenderedContent(note); const {renderedContent, type} = await noteContentRenderer.getRenderedContent(note);
$el.append( $el.append(
$('<div class="include-note-content">') $(`<div class="include-note-content type-${type}">`)
.append(renderedContent) .append(renderedContent)
); );
} }

View File

@ -135,7 +135,7 @@ export default class FileTypeWidget extends TypeWidget {
this.$pdfPreview.attr('src', '').empty().hide(); this.$pdfPreview.attr('src', '').empty().hide();
if (noteComplement.content) { if (noteComplement.content) {
this.$previewContent.show(); this.$previewContent.show().scrollTop(0);
this.$previewContent.text(noteComplement.content); this.$previewContent.text(noteComplement.content);
} }
else if (note.mime === 'application/pdf' && utils.isElectron()) { else if (note.mime === 'application/pdf' && utils.isElectron()) {

View File

@ -687,11 +687,23 @@ a.external:not(.no-arrow):after, a[href^="http://"]:not(.no-arrow):after, a[href
overflow: auto; overflow: auto;
} }
.include-note.box-size-small .include-note-content.type-pdf {
height: 10em; /* PDF is rendered in iframe and must be sized absolutely */
}
.include-note.box-size-medium .include-note-content { .include-note.box-size-medium .include-note-content {
max-height: 20em; max-height: 20em;
overflow: auto; overflow: auto;
} }
.include-note.box-size-medium .include-note-content.type-pdf {
height: 20em; /* PDF is rendered in iframe and must be sized absolutely */
}
.include-note.box-size-full .include-note-content.type-pdf {
height: 50em; /* PDF is rendered in iframe and it's not possible to put full height so at least a large height */
}
.alert-warning { .alert-warning {
color: var(--main-text-color) !important; color: var(--main-text-color) !important;
background-color: var(--accented-background-color) !important; background-color: var(--accented-background-color) !important;

View File

@ -17,8 +17,9 @@ function getNote(req) {
if (note.isStringNote()) { if (note.isStringNote()) {
note.content = note.getContent(); note.content = note.getContent();
if (note.type === 'file') { if (note.type === 'file' && note.content.length > 10000) {
note.content = note.content.substr(0, 10000); note.content = note.content.substr(0, 10000)
+ `\r\n\r\n... and ${note.content.length - 10000} more characters.`;
} }
} }

View File

@ -279,18 +279,15 @@ const downloadImagePromises = {};
function replaceUrl(content, url, imageNote) { function replaceUrl(content, url, imageNote) {
const quotedUrl = utils.quoteRegex(url); const quotedUrl = utils.quoteRegex(url);
return content.replace(new RegExp(`\\s+src=[\"']${quotedUrl}[\"']`, "g"), ` src="api/images/${imageNote.noteId}/${imageNote.title}"`); return content.replace(new RegExp(`\\s+src=[\"']${quotedUrl}[\"']`, "ig"), ` src="api/images/${imageNote.noteId}/${imageNote.title}"`);
} }
function downloadImages(noteId, content) { function downloadImages(noteId, content) {
const re = /<img[^>]*?\ssrc=['"]([^'">]+)['"]/ig; const imageRe = /<img[^>]*?\ssrc=['"]([^'">]+)['"]/ig;
let match; let imageMatch;
const origContent = content;
while (match = re.exec(origContent)) {
const url = match[1];
while (imageMatch = imageRe.exec(content)) {
const url = imageMatch[1];
const inlineImageMatch = /^data:image\/[a-z]+;base64,/.exec(url); const inlineImageMatch = /^data:image\/[a-z]+;base64,/.exec(url);
if (inlineImageMatch) { if (inlineImageMatch) {
@ -300,9 +297,9 @@ function downloadImages(noteId, content) {
const imageService = require('../services/image'); const imageService = require('../services/image');
const {note} = imageService.saveImage(noteId, imageBuffer, "inline image", true); const {note} = imageService.saveImage(noteId, imageBuffer, "inline image", true);
content = content.substr(0, match.index) content = content.substr(0, imageMatch.index)
+ `<img src="api/images/${note.noteId}/${note.title}"` + `<img src="api/images/${note.noteId}/${note.title}"`
+ content.substr(match.index + match[0].length); + content.substr(imageMatch.index + imageMatch[0].length);
} }
else if (!url.includes('api/images/') else if (!url.includes('api/images/')
// this is an exception for the web clipper's "imageId" // this is an exception for the web clipper's "imageId"
@ -316,7 +313,6 @@ function downloadImages(noteId, content) {
} }
else { else {
content = replaceUrl(content, url, imageNote); content = replaceUrl(content, url, imageNote);
continue; continue;
} }
} }
@ -328,7 +324,6 @@ function downloadImages(noteId, content) {
imageUrlToNoteIdMapping[url] = existingImage.noteId; imageUrlToNoteIdMapping[url] = existingImage.noteId;
content = replaceUrl(content, url, existingImage); content = replaceUrl(content, url, existingImage);
continue; continue;
} }

View File

@ -84,10 +84,11 @@ function exec(opts) {
} }
function getImage(imageUrl) { function getImage(imageUrl) {
const proxyConf = syncOptions.getSyncProxy();
const opts = { const opts = {
method: 'GET', method: 'GET',
url: imageUrl, url: imageUrl,
proxy: syncOptions.getSyncProxy() proxy: proxyConf !== "noproxy" ? proxyConf : null
}; };
const client = getClient(opts); const client = getClient(opts);

View File

@ -155,7 +155,11 @@ function getContentDisposition(filename) {
return `file; filename="${sanitizedFilename}"; filename*=UTF-8''${sanitizedFilename}`; return `file; filename="${sanitizedFilename}"; filename*=UTF-8''${sanitizedFilename}`;
} }
const STRING_MIME_TYPES = ["application/x-javascript", "image/svg+xml"]; const STRING_MIME_TYPES = [
"application/javascript",
"application/x-javascript",
"image/svg+xml"
];
function isStringNote(type, mime) { function isStringNote(type, mime) {
// render and book are string note in the sense that they are expected to contain empty string // render and book are string note in the sense that they are expected to contain empty string