mirror of https://github.com/laurent22/joplin.git
Improved handling of external links and resources
parent
31bfa72bca
commit
bd8926958f
|
@ -13,6 +13,8 @@ class ResourceServer {
|
|||
this.server_ = null;
|
||||
this.logger_ = new Logger();
|
||||
this.port_ = null;
|
||||
this.linkHandler_ = null;
|
||||
this.started_ = false;
|
||||
}
|
||||
|
||||
setLogger(logger) {
|
||||
|
@ -23,11 +25,19 @@ class ResourceServer {
|
|||
return this.logger_;
|
||||
}
|
||||
|
||||
started() {
|
||||
return this.started_;
|
||||
}
|
||||
|
||||
baseUrl() {
|
||||
if (!this.port_) return '';
|
||||
return 'http://127.0.0.1:' + this.port_;
|
||||
}
|
||||
|
||||
setLinkHandler(handler) {
|
||||
this.linkHandler_ = handler;
|
||||
}
|
||||
|
||||
async start() {
|
||||
this.port_ = await netUtils.findAvailablePort([9167, 9267, 8167, 8267]);
|
||||
if (!this.port_) {
|
||||
|
@ -52,18 +62,18 @@ class ResourceServer {
|
|||
}
|
||||
resourceId = resourceId[1];
|
||||
|
||||
if (!this.linkHandler_) throw new Error('No link handler is defined');
|
||||
|
||||
try {
|
||||
let resource = await Resource.loadByPartialId(resourceId);
|
||||
if (!resource.length) throw new Error('No resource with ID ' + resourceId);
|
||||
if (resource.length > 2) throw new Error('More than one resource match ID ' + resourceId); // That's very unlikely
|
||||
resource = resource[0];
|
||||
if (resource.mime) response.setHeader('Content-Type', resource.mime);
|
||||
writeResponse(await Resource.content(resource));
|
||||
const done = await this.linkHandler_(resourceId, response);
|
||||
if (!done) throw new Error('Unhandled resource: ' + resourceId);
|
||||
} catch (error) {
|
||||
response.setHeader('Content-Type', 'text/plain');
|
||||
response.statusCode = 400;
|
||||
writeResponse('Error: could not retrieve resource: ' + error.message);
|
||||
response.write(error.message);
|
||||
}
|
||||
|
||||
response.end();
|
||||
});
|
||||
|
||||
this.server_.on('error', (error) => {
|
||||
|
@ -73,6 +83,8 @@ class ResourceServer {
|
|||
this.server_.listen(this.port_);
|
||||
|
||||
enableServerDestroy(this.server_);
|
||||
|
||||
this.started_ = true;
|
||||
}
|
||||
|
||||
stop() {
|
||||
|
|
|
@ -3,6 +3,7 @@ import { Folder } from 'lib/models/folder.js';
|
|||
import { Tag } from 'lib/models/tag.js';
|
||||
import { BaseModel } from 'lib/base-model.js';
|
||||
import { Note } from 'lib/models/note.js';
|
||||
import { Resource } from 'lib/models/resource.js';
|
||||
import { cliUtils } from './cli-utils.js';
|
||||
import { reducer, defaultState } from 'lib/reducer.js';
|
||||
import { reg } from 'lib/registry.js';
|
||||
|
@ -46,10 +47,6 @@ class AppGui {
|
|||
|
||||
this.renderer_ = new Renderer(this.term(), this.rootWidget_);
|
||||
|
||||
this.renderer_.on('renderDone', async (event) => {
|
||||
//if (this.widget('console').hasFocus) this.widget('console').resetCursor();
|
||||
});
|
||||
|
||||
this.app_.on('modelAction', async (event) => {
|
||||
await this.handleModelAction(event.action);
|
||||
});
|
||||
|
@ -609,48 +606,70 @@ class AppGui {
|
|||
if (msg !== '') this.widget('statusBar').setItemAt(0, msg);
|
||||
}
|
||||
|
||||
setupResourceServer() {
|
||||
async setupResourceServer() {
|
||||
const linkStyle = chalk.blue.underline;
|
||||
const noteTextWidget = this.widget('noteText');
|
||||
const resourceIdRegex = /^:\/[a-f0-9]+$/i
|
||||
|
||||
const regularUrlRenderer = (url) => {
|
||||
if (!url) return url;
|
||||
const l = url.toLowerCase();
|
||||
if (l.indexOf('http://') === 0 || l.indexOf('https://') === 0 || l.indexOf('www.') === 0) {
|
||||
return linkStyle(url);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
const noteLinks = {};
|
||||
|
||||
// By default, before the server is started, only the regular
|
||||
// URLs appear in blue.
|
||||
noteTextWidget.markdownRendererOptions = {
|
||||
linkUrlRenderer: (url) => {
|
||||
linkUrlRenderer: (index, url) => {
|
||||
if (resourceIdRegex.test(url)) {
|
||||
return url;
|
||||
} else if (url.indexOf('http://') === 0 || url.indexOf('https://') === 0) {
|
||||
return linkStyle(url);
|
||||
} else {
|
||||
return regularUrlRenderer(url);
|
||||
return url;
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
this.resourceServer_ = new ResourceServer();
|
||||
this.resourceServer_.setLogger(this.app().logger());
|
||||
this.resourceServer_.start().then(() => {
|
||||
if (this.resourceServer_.baseUrl()) {
|
||||
noteTextWidget.markdownRendererOptions = {
|
||||
linkUrlRenderer: (url) => {
|
||||
if (resourceIdRegex.test(url)) {
|
||||
const resourceId = url.substr(2);
|
||||
return linkStyle(this.resourceServer_.baseUrl() + '/' + resourceId.substr(0, 7));
|
||||
} else {
|
||||
return regularUrlRenderer(url);
|
||||
}
|
||||
},
|
||||
};
|
||||
this.resourceServer_.setLinkHandler(async (path, response) => {
|
||||
const link = noteLinks[path];
|
||||
|
||||
if (link.type === 'url') {
|
||||
response.writeHead(302, { 'Location': link.url });
|
||||
return true;
|
||||
}
|
||||
|
||||
if (link.type === 'resource') {
|
||||
const resourceId = link.id;
|
||||
let resource = await Resource.load(resourceId);
|
||||
if (!resource) throw new Error('No resource with ID ' + resourceId); // Should be nearly impossible
|
||||
if (resource.mime) response.setHeader('Content-Type', resource.mime);
|
||||
response.write(await Resource.content(resource));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
await this.resourceServer_.start();
|
||||
if (!this.resourceServer_.started()) return;
|
||||
|
||||
noteTextWidget.markdownRendererOptions = {
|
||||
linkUrlRenderer: (index, url) => {
|
||||
if (!url) return url;
|
||||
|
||||
if (resourceIdRegex.test(url)) {
|
||||
noteLinks[index] = {
|
||||
type: 'resource',
|
||||
id: url.substr(2),
|
||||
};
|
||||
} else {
|
||||
noteLinks[index] = {
|
||||
type: 'url',
|
||||
url: url,
|
||||
};
|
||||
}
|
||||
|
||||
return linkStyle(this.resourceServer_.baseUrl() + '/' + index);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async start() {
|
||||
|
|
Loading…
Reference in New Issue