152 lines
4.9 KiB
JavaScript
152 lines
4.9 KiB
JavaScript
// @flow
|
|
import defineFunction from "../defineFunction";
|
|
import type {Measurement} from "../units";
|
|
import {calculateSize, validUnit, makeEm} from "../units";
|
|
import ParseError from "../ParseError";
|
|
import {Img} from "../domTree";
|
|
import mathMLTree from "../mathMLTree";
|
|
import {assertNodeType} from "../parseNode";
|
|
import type {CssStyle} from "../domTree";
|
|
|
|
const sizeData = function(str: string): Measurement {
|
|
if (/^[-+]? *(\d+(\.\d*)?|\.\d+)$/.test(str)) {
|
|
// str is a number with no unit specified.
|
|
// default unit is bp, per graphix package.
|
|
return {number: +str, unit: "bp"};
|
|
} else {
|
|
const match = (/([-+]?) *(\d+(?:\.\d*)?|\.\d+) *([a-z]{2})/).exec(str);
|
|
if (!match) {
|
|
throw new ParseError("Invalid size: '" + str
|
|
+ "' in \\includegraphics");
|
|
}
|
|
const data = {
|
|
number: +(match[1] + match[2]), // sign + magnitude, cast to number
|
|
unit: match[3],
|
|
};
|
|
if (!validUnit(data)) {
|
|
throw new ParseError("Invalid unit: '" + data.unit
|
|
+ "' in \\includegraphics.");
|
|
}
|
|
return data;
|
|
}
|
|
};
|
|
|
|
defineFunction({
|
|
type: "includegraphics",
|
|
names: ["\\includegraphics"],
|
|
props: {
|
|
numArgs: 1,
|
|
numOptionalArgs: 1,
|
|
argTypes: ["raw", "url"],
|
|
allowedInText: false,
|
|
},
|
|
handler: ({parser}, args, optArgs) => {
|
|
let width = {number: 0, unit: "em"};
|
|
let height = {number: 0.9, unit: "em"}; // sorta character sized.
|
|
let totalheight = {number: 0, unit: "em"};
|
|
let alt = "";
|
|
|
|
if (optArgs[0]) {
|
|
const attributeStr = assertNodeType(optArgs[0], "raw").string;
|
|
|
|
// Parser.js does not parse key/value pairs. We get a string.
|
|
const attributes = attributeStr.split(",");
|
|
for (let i = 0; i < attributes.length; i++) {
|
|
const keyVal = attributes[i].split("=");
|
|
if (keyVal.length === 2) {
|
|
const str = keyVal[1].trim();
|
|
switch (keyVal[0].trim()) {
|
|
case "alt":
|
|
alt = str;
|
|
break;
|
|
case "width":
|
|
width = sizeData(str);
|
|
break;
|
|
case "height":
|
|
height = sizeData(str);
|
|
break;
|
|
case "totalheight":
|
|
totalheight = sizeData(str);
|
|
break;
|
|
default:
|
|
throw new ParseError("Invalid key: '" + keyVal[0] +
|
|
"' in \\includegraphics.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
const src = assertNodeType(args[0], "url").url;
|
|
|
|
if (alt === "") {
|
|
// No alt given. Use the file name. Strip away the path.
|
|
alt = src;
|
|
alt = alt.replace(/^.*[\\/]/, '');
|
|
alt = alt.substring(0, alt.lastIndexOf('.'));
|
|
}
|
|
|
|
if (!parser.settings.isTrusted({
|
|
command: "\\includegraphics",
|
|
url: src,
|
|
})) {
|
|
return parser.formatUnsupportedCmd("\\includegraphics");
|
|
}
|
|
|
|
return {
|
|
type: "includegraphics",
|
|
mode: parser.mode,
|
|
alt: alt,
|
|
width: width,
|
|
height: height,
|
|
totalheight: totalheight,
|
|
src: src,
|
|
};
|
|
},
|
|
htmlBuilder: (group, options) => {
|
|
const height = calculateSize(group.height, options);
|
|
let depth = 0;
|
|
|
|
if (group.totalheight.number > 0) {
|
|
depth = calculateSize(group.totalheight, options) - height;
|
|
}
|
|
|
|
let width = 0;
|
|
if (group.width.number > 0) {
|
|
width = calculateSize(group.width, options);
|
|
}
|
|
|
|
const style: CssStyle = {height: makeEm(height + depth)};
|
|
if (width > 0) {
|
|
style.width = makeEm(width);
|
|
}
|
|
if (depth > 0) {
|
|
style.verticalAlign = makeEm(-depth);
|
|
}
|
|
|
|
const node = new Img(group.src, group.alt, style);
|
|
node.height = height;
|
|
node.depth = depth;
|
|
|
|
return node;
|
|
},
|
|
mathmlBuilder: (group, options) => {
|
|
const node = new mathMLTree.MathNode("mglyph", []);
|
|
node.setAttribute("alt", group.alt);
|
|
|
|
const height = calculateSize(group.height, options);
|
|
let depth = 0;
|
|
if (group.totalheight.number > 0) {
|
|
depth = calculateSize(group.totalheight, options) - height;
|
|
node.setAttribute("valign", makeEm(-depth));
|
|
}
|
|
node.setAttribute("height", makeEm(height + depth));
|
|
|
|
if (group.width.number > 0) {
|
|
const width = calculateSize(group.width, options);
|
|
node.setAttribute("width", makeEm(width));
|
|
}
|
|
node.setAttribute("src", group.src);
|
|
return node;
|
|
},
|
|
});
|