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
15 changed files with 210 additions and 172 deletions

View File

@@ -81,6 +81,8 @@ function setupGlobs() {
$("body").on("click", "a.external", function () {
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}`)
.css("max-width", "100%");
}
else if (type === 'file') {
else if (type === 'file' || type === 'pdf') {
function getFileUrl() {
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
$openButton.toggle(!note.isProtected);
$rendered = $('<div>');
$rendered = $('<div style="display: flex; flex-direction: column; height: 100%;">');
if (note.mime === 'application/pdf' && utils.isElectron()) {
const $pdfPreview = $('<iframe class="pdf-preview" style="width: 100%; height: 100%; flex-grow: 100;"></iframe>');
if (type === 'pdf') {
const $pdfPreview = $('<iframe class="pdf-preview" style="width: 100%; flex-grow: 100;"></iframe>');
$pdfPreview.attr("src", utils.getUrlForDownload("api/notes/" + note.noteId + "/open"));
$rendered.append($pdfPreview);
}
$rendered
.append($downloadButton)
.append(' &nbsp; ')
.append($openButton);
$rendered.append(
$("<div>")
.append($downloadButton)
.append(' &nbsp; ')
.append($openButton)
);
}
else if (type === 'render') {
$rendered = $('<div>');
@@ -90,6 +92,10 @@ async function getRenderedContent(note) {
function getRenderingType(note) {
let type = note.type;
if (type === 'file' && note.mime === 'application/pdf' && utils.isElectron()) {
type = 'pdf';
}
if (note.isProtected) {
if (protectedSessionHolder.isProtectedSessionAvailable()) {
protectedSessionHolder.touchProtectedSession();
@@ -104,4 +110,4 @@ function getRenderingType(note) {
export default {
getRenderedContent
};
};

View File

@@ -288,6 +288,13 @@ class TreeCache {
async getNoteComplement(noteId) {
if (!this.noteComplementPromises[noteId]) {
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];

View File

@@ -329,4 +329,9 @@ export default class NoteDetailWidget extends TabAwareWidget {
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
extensions: utils.isMobile() ? ["dnd5", "clones"] : ["hotkeys", "dnd5", "clones"],
source: treeData,
scrollOfs: {
top: 200,
bottom: 200
},
scrollParent: this.$tree,
minExpandLevel: 2, // root can't be collapsed
click: (event, data) => {

View File

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

View File

@@ -135,7 +135,7 @@ export default class FileTypeWidget extends TypeWidget {
this.$pdfPreview.attr('src', '').empty().hide();
if (noteComplement.content) {
this.$previewContent.show();
this.$previewContent.show().scrollTop(0);
this.$previewContent.text(noteComplement.content);
}
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;
}
.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 {
max-height: 20em;
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 {
color: var(--main-text-color) !important;
background-color: var(--accented-background-color) !important;

View File

@@ -17,8 +17,9 @@ function getNote(req) {
if (note.isStringNote()) {
note.content = note.getContent();
if (note.type === 'file') {
note.content = note.content.substr(0, 10000);
if (note.type === 'file' && note.content.length > 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) {
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) {
const re = /<img[^>]*?\ssrc=['"]([^'">]+)['"]/ig;
let match;
const origContent = content;
while (match = re.exec(origContent)) {
const url = match[1];
const imageRe = /<img[^>]*?\ssrc=['"]([^'">]+)['"]/ig;
let imageMatch;
while (imageMatch = imageRe.exec(content)) {
const url = imageMatch[1];
const inlineImageMatch = /^data:image\/[a-z]+;base64,/.exec(url);
if (inlineImageMatch) {
@@ -300,9 +297,9 @@ function downloadImages(noteId, content) {
const imageService = require('../services/image');
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}"`
+ content.substr(match.index + match[0].length);
+ content.substr(imageMatch.index + imageMatch[0].length);
}
else if (!url.includes('api/images/')
// this is an exception for the web clipper's "imageId"
@@ -316,7 +313,6 @@ function downloadImages(noteId, content) {
}
else {
content = replaceUrl(content, url, imageNote);
continue;
}
}
@@ -328,7 +324,6 @@ function downloadImages(noteId, content) {
imageUrlToNoteIdMapping[url] = existingImage.noteId;
content = replaceUrl(content, url, existingImage);
continue;
}

View File

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

View File

@@ -155,7 +155,11 @@ function getContentDisposition(filename) {
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) {
// render and book are string note in the sense that they are expected to contain empty string