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:
parent
c75618eb8f
commit
fbb0ac5892
@ -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();
|
||||
});
|
||||
|
||||
});
|
@ -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) + ')]';
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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;
|
@ -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;
|
Loading…
Reference in New Issue
Block a user