1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Clipper: Refactored image rules to re-use more code

This commit is contained in:
Laurent Cozic 2019-07-15 20:43:28 +00:00
parent c75618eb8f
commit fbb0ac5892
5 changed files with 76 additions and 48 deletions

View File

@ -30,4 +30,19 @@ describe('htmlUtils', function() {
done();
});
it('should encode attributes', async (done) => {
const testCases = [
[{ a: 'one', b: 'two' }, 'a="one" b="two"'],
[{ a: 'one&two' }, 'a="one&two"'],
];
for (let i = 0; i < testCases.length; i++) {
const attrs = testCases[i][0];
const expected = testCases[i][1];
expect(htmlUtils.attributesHtml(attrs)).toBe(expected);
}
done();
});
});

View File

@ -1,26 +1,13 @@
const Entities = require('html-entities').AllHtmlEntities;
const htmlentities = (new Entities()).encode;
const Resource = require('lib/models/Resource.js');
const htmlUtils = require('lib/htmlUtils.js');
const utils = require('../utils');
function renderImageHtml(before, src, after, ruleOptions) {
const resourceId = Resource.urlToId(src);
const result = ruleOptions.resources[resourceId];
const resource = result ? result.item : null;
const resourceStatus = utils.resourceStatus(result);
if (resourceStatus !== 'ready') {
const icon = utils.resourceStatusImage(resourceStatus);
return '<div class="not-loaded-resource resource-status-' + resourceStatus + '" data-resource-id="' + resourceId + '">' + '<img src="data:image/svg+xml;utf8,' + htmlentities(icon) + '"/>' + '</div>';
}
const mime = resource.mime ? resource.mime.toLowerCase() : '';
if (Resource.isSupportedImageMimeType(mime)) {
let newSrc = './' + Resource.filename(resource);
if (ruleOptions.resourceBaseUrl) newSrc = ruleOptions.resourceBaseUrl + newSrc;
return '<img ' + before + ' data-resource-id="' + resource.id + '" src="' + newSrc + '" ' + after + '/>';
}
const r = utils.imageReplacement(src, ruleOptions.resources, ruleOptions.resourceBaseUrl);
if (typeof r === 'string') return r;
if (r) return '<img ' + before + ' ' + htmlUtils.attributesHtml(r) + ' ' + after + '/>';
return '[Image: ' + htmlentities(resource.title) + ' (' + htmlentities(mime) + ')]';
}

View File

@ -2,6 +2,7 @@ const Entities = require('html-entities').AllHtmlEntities;
const htmlentities = (new Entities()).encode;
const Resource = require('lib/models/Resource.js');
const utils = require('../utils');
const htmlUtils = require('lib/htmlUtils.js');
function installRule(markdownIt, mdOptions, ruleOptions) {
const defaultRender = markdownIt.renderer.rules.image;
@ -13,23 +14,9 @@ function installRule(markdownIt, mdOptions, ruleOptions) {
if (!Resource.isResourceUrl(src)) return defaultRender(tokens, idx, options, env, self);
const resourceId = Resource.urlToId(src);
const result = ruleOptions.resources[resourceId];
const resource = result ? result.item : null;
const resourceStatus = utils.resourceStatus(result);
if (resourceStatus !== 'ready') {
const icon = utils.resourceStatusImage(resourceStatus);
return '<div class="not-loaded-resource resource-status-' + resourceStatus + '" data-resource-id="' + resourceId + '">' + '<img src="data:image/svg+xml;utf8,' + htmlentities(icon) + '"/>' + '</div>';
}
const mime = resource.mime ? resource.mime.toLowerCase() : '';
if (Resource.isSupportedImageMimeType(mime)) {
let realSrc = './' + Resource.filename(resource);
if (ruleOptions.resourceBaseUrl) realSrc = ruleOptions.resourceBaseUrl + realSrc;
let output = '<img data-from-md data-resource-id="' + resource.id + '" title="' + htmlentities(title) + '" src="' + realSrc + '"/>';
return output;
}
const r = utils.imageReplacement(src, ruleOptions.resources, ruleOptions.resourceBaseUrl);
if (typeof r === 'string') return r;
if (r) return '<img data-from-md ' + htmlUtils.attributesHtml(Object.assign({}, r, { title: title })) + '/>';
return defaultRender(tokens, idx, options, env, self);
};

View File

@ -68,7 +68,7 @@ utils.resourceStatusFile = function(state) {
throw new Error('Unknown state: ' + state);
}
utils.resourceStatus = function(resourceInfo, localState) {
utils.resourceStatus = function(resourceInfo) {
let resourceStatus = 'ready';
if (resourceInfo) {
@ -91,4 +91,28 @@ utils.resourceStatus = function(resourceInfo, localState) {
return resourceStatus;
}
utils.imageReplacement = function(src, resources, resourceBaseUrl) {
const resourceId = Resource.urlToId(src);
const result = resources[resourceId];
const resource = result ? result.item : null;
const resourceStatus = utils.resourceStatus(result);
if (resourceStatus !== 'ready') {
const icon = utils.resourceStatusImage(resourceStatus);
return '<div class="not-loaded-resource resource-status-' + resourceStatus + '" data-resource-id="' + resourceId + '">' + '<img src="data:image/svg+xml;utf8,' + htmlentities(icon) + '"/>' + '</div>';
}
const mime = resource.mime ? resource.mime.toLowerCase() : '';
if (Resource.isSupportedImageMimeType(mime)) {
let newSrc = './' + Resource.filename(resource);
if (resourceBaseUrl) newSrc = resourceBaseUrl + newSrc;
return {
'data-resource-id': resource.id,
'src': newSrc,
};
}
return null;
}
module.exports = utils;

View File

@ -1,15 +1,17 @@
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const urlUtils = require('lib/urlUtils.js');
const Entities = require('html-entities').AllHtmlEntities;
const htmlentities = (new Entities()).encode;
function headAndBodyHtml_(doc) {
const output = [];
if (doc.head) output.push(doc.head.innerHTML);
if (doc.body) output.push(doc.body.innerHTML);
return output.join('\n');
}
class HtmlUtils {
const htmlUtils = {
headAndBodyHtml(doc) {
const output = [];
if (doc.head) output.push(doc.head.innerHTML);
if (doc.body) output.push(doc.body.innerHTML);
return output.join('\n');
}
extractImageUrls(html) {
if (!html) return [];
@ -25,7 +27,7 @@ const htmlUtils = {
}
return output;
},
}
replaceImageUrls(html, callback) {
if (!html) return '';
@ -42,8 +44,8 @@ const htmlUtils = {
// This function returns the head and body but without the <head> and <body>
// tag, which for our purpose are not needed and can cause issues when present.
return headAndBodyHtml_(doc);
},
return this.headAndBodyHtml(doc);
}
prependBaseUrl(html, baseUrl) {
const dom = new JSDOM(html);
@ -57,9 +59,22 @@ const htmlUtils = {
anchor.setAttribute('href', newHref);
}
return headAndBodyHtml_(doc);
},
return this.headAndBodyHtml(doc);
}
};
attributesHtml(attr) {
const output = [];
for (const n in attr) {
if (!attr.hasOwnProperty(n)) continue;
output.push(n + '="' + htmlentities(attr[n]) + '"');
}
return output.join(' ');
}
}
const htmlUtils = new HtmlUtils();
module.exports = htmlUtils;