diff --git a/lib/filter.js b/lib/filter.js index 7a60616..c9a165d 100644 --- a/lib/filter.js +++ b/lib/filter.js @@ -39,7 +39,8 @@ export default function filter({t: key, c: value}, format, meta) { const imageValue = utils.isFigure(key, value) ? value[0]['c'] : value; // https://hackage.haskell.org/package/pandoc-types-1.22.2.1/docs/Text-Pandoc-Definition.html#t:Inline - let [[id, classes, keyvals], caption, [fname, title]] = imageValue; + /* eslint-disable-next-line no-unused-vars */ + const [[id, classes, keyvals], caption, [fname, title]] = imageValue; // If image is not an SVG or if it has class 'ignore', return. if (!utils.isSVG(fname) || classes.includes('ignore')) { @@ -48,38 +49,11 @@ export default function filter({t: key, c: value}, format, meta) { // Load SVG, then load the SVG's DOM using jsdom. let svgString = utils.loadSVG(fname); - if (!svgString) { - return; - } + if (!svgString) return; const svgDOM = utils.createDOM(svgString); - // Resize SVG? - const dimKeyvals = []; - keyvals = keyvals.filter( ([key, val]) => { - if (key === 'width' || key === 'height') { - dimKeyvals.push([key, val]); - return false; - } - return true; - }); - if (dimKeyvals.length !== 0) { - const dimObj = Object.fromEntries(dimKeyvals); - resize(svgDOM, dimObj); - } else { - if (!classes.includes('keep-size')) { - let scaleFactor; - keyvals = keyvals.filter( ([key, val]) => { - if (key === 'scale-factor') { - scaleFactor = val; - return false; - } - return true; - }); - resize(svgDOM, {scaleFactor: scaleFactor}); - } else { - classes.splice(classes.indexOf('keep-size'), 1); - } - } + // Resize SVG. Convert keyvals to more convenient object representation. + resize(svgDOM, classes, utils.fromEntries(keyvals)); if (format === 'html') { // Optimize SVG. This needs to be done before text2foreignObject is called, diff --git a/lib/resize.js b/lib/resize.js index 900a942..1aab41a 100644 --- a/lib/resize.js +++ b/lib/resize.js @@ -3,19 +3,22 @@ import {round} from './utils.js'; /** - * Resize SVG `width` and `height` units to `em`. No unit implies `px`. - * If `dimObject` contains `width` or `height`, apply those values instead, - * maintaining aspect ratio. If the SVG is already sized in relative units, - * only apply `scaleFactor`. + * Resize SVG `width` and `height` units to `em`. No unit implies `px`. If + * `attrs` contains keys `width` or `height`, apply the corresponding values + * instead, maintaining aspect ratio. If the SVG is already sized in relative + * units, only apply `scaleFactor`. * @param {object} svgDOM - SVG DOM - * @param {object} dimObj - Object containing information for dimensioning + * @param {array} classes - Class list + * @param {object} attrs - Object containing information for dimensioning */ -export default function resize(svgDOM, dimObj) { - let {scaleFactor, width, height} = dimObj; +export default function resize(svgDOM, classes, attrs) { + let {'scale-factor': scaleFactor, width, height} = attrs; - if (typeof scaleFactor === 'undefined') { - scaleFactor = 1; - } + // If class `keep-size` is set, and neither width nor height have been + // supplied, don't resize SVG. + if (classes.includes('keep-size') && !width && !height) return; + + if (typeof scaleFactor === 'undefined') scaleFactor = 1; const dimRegex = /^(?[\d\.]+)(?[^\d\.]*)$/; diff --git a/lib/utils.js b/lib/utils.js index 34d74a5..8e91bd5 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -148,6 +148,20 @@ export function round(number) { return parseFloat(number.toPrecision(10)); } +/** + * Convert keyvals to JS object. + * @param {array} keyvals - Array of key-value pairs + * @return {object} - Corresponding object + */ +export function fromEntries(keyvals) { + // When only one pair of keyvals is provided, for some reason pandoc creates + // an array ['key', 'val'] rather than [['key', 'val']]. + if (keyvals.length === 2 && typeof keyvals[0] === 'string') { + keyvals = [keyvals]; + } + return Object.fromEntries(keyvals); +} + /** * Flatten children of passed DOM element, by replacing child elements with * their content. diff --git a/tests/test.js b/tests/test.js index 18abadd..f552ea8 100644 --- a/tests/test.js +++ b/tests/test.js @@ -240,7 +240,7 @@ describe('resize', () => { beforeEach( () => svgDOM = utils.createDOM(svg)); it('converts units to `em`', () => { - resize(svgDOM, {}); + resize(svgDOM, [], {}); const widthPX = utils.round(widthMM * 0.1 * 37.8); const heightPX = utils.round(heightMM * 0.1 * 37.8); expect(svgDOM.querySelector('svg').getAttribute('width')) @@ -250,21 +250,21 @@ describe('resize', () => { }); it('applies width', () => { - resize(svgDOM, {width: '1.5in'}); + resize(svgDOM, [], {width: '1.5in'}); expect(svgDOM.querySelector('svg').getAttribute('width')).toEqual('1.5in'); expect(svgDOM.querySelector('svg').getAttribute('height')) .toEqual(utils.round(1.5 / aspectRatio) + 'in'); }); it('applies height', () => { - resize(svgDOM, {height: '1.5in'}); + resize(svgDOM, [], {height: '1.5in'}); expect(svgDOM.querySelector('svg').getAttribute('width')) .toEqual(utils.round(1.5 * aspectRatio) + 'in'); expect(svgDOM.querySelector('svg').getAttribute('height')).toEqual('1.5in'); }); it('applies width and height', () => { - resize(svgDOM, {width: '1inch', height: '2inch'}); + resize(svgDOM, [], {width: '1inch', height: '2inch'}); expect(svgDOM.querySelector('svg').getAttribute('width')).toEqual('1in'); expect(svgDOM.querySelector('svg').getAttribute('height')).toEqual('2in'); }); @@ -272,12 +272,12 @@ describe('resize', () => { it('excludes SVGs with mixed relative/absolute units', () => { const svg = ''; const svgDOM = utils.createDOM(svg); - resize(svgDOM, {}); + resize(svgDOM, [], {}); expect(svgDOM.querySelector('svg').outerHTML).toEqual(svg); }); it('leaves SVG unmodified when given invalid height/width', () => { - resize(svgDOM, {height: "50ducks"}); + resize(svgDOM, [], {height: "50ducks"}); expect(svgDOM.querySelector('svg').outerHTML).toEqual(svg); }); });