[remark-wiki-link][m]: Add image size adjustment in remark-wiki-link (#1084)
* [remark-wiki-link][m]: Add image size adjustment in `remark-wiki-link` * [remark-wiki-links][m]: Add image size feature to images
This commit is contained in:
@@ -1,23 +1,23 @@
|
||||
import { isSupportedFileFormat } from "./isSupportedFileFormat";
|
||||
import { isSupportedFileFormat } from './isSupportedFileFormat';
|
||||
|
||||
const defaultWikiLinkResolver = (target: string) => {
|
||||
// for [[#heading]] links
|
||||
if (!target) {
|
||||
return [];
|
||||
}
|
||||
let permalink = target.replace(/\/index$/, "");
|
||||
let permalink = target.replace(/\/index$/, '');
|
||||
// TODO what to do with [[index]] link?
|
||||
if (permalink.length === 0) {
|
||||
permalink = "/";
|
||||
permalink = '/';
|
||||
}
|
||||
return [permalink];
|
||||
};
|
||||
|
||||
export interface FromMarkdownOptions {
|
||||
pathFormat?:
|
||||
| "raw" // default; use for regular relative or absolute paths
|
||||
| "obsidian-absolute" // use for Obsidian-style absolute paths (with no leading slash)
|
||||
| "obsidian-short"; // use for Obsidian-style shortened paths (shortest path possible)
|
||||
| 'raw' // default; use for regular relative or absolute paths
|
||||
| 'obsidian-absolute' // use for Obsidian-style absolute paths (with no leading slash)
|
||||
| 'obsidian-short'; // use for Obsidian-style shortened paths (shortest path possible)
|
||||
permalinks?: string[]; // list of permalinks to match possible permalinks of a wiki link against
|
||||
wikiLinkResolver?: (name: string) => string[]; // function to resolve wiki links to an array of possible permalinks
|
||||
newClassName?: string; // class name to add to links that don't have a matching permalink
|
||||
@@ -25,14 +25,23 @@ export interface FromMarkdownOptions {
|
||||
hrefTemplate?: (permalink: string) => string; // function to generate the href attribute of a link
|
||||
}
|
||||
|
||||
export function getImageSize(size: string) {
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [width, height] = size.split('x');
|
||||
|
||||
if (!height) height = width;
|
||||
|
||||
return { width, height };
|
||||
}
|
||||
|
||||
// mdas-util-from-markdown extension
|
||||
// https://github.com/syntax-tree/mdast-util-from-markdown#extension
|
||||
function fromMarkdown(opts: FromMarkdownOptions = {}) {
|
||||
const pathFormat = opts.pathFormat || "raw";
|
||||
const pathFormat = opts.pathFormat || 'raw';
|
||||
const permalinks = opts.permalinks || [];
|
||||
const wikiLinkResolver = opts.wikiLinkResolver || defaultWikiLinkResolver;
|
||||
const newClassName = opts.newClassName || "new";
|
||||
const wikiLinkClassName = opts.wikiLinkClassName || "internal";
|
||||
const newClassName = opts.newClassName || 'new';
|
||||
const wikiLinkClassName = opts.wikiLinkClassName || 'internal';
|
||||
const defaultHrefTemplate = (permalink: string) => permalink;
|
||||
|
||||
const hrefTemplate = opts.hrefTemplate || defaultHrefTemplate;
|
||||
@@ -44,9 +53,9 @@ function fromMarkdown(opts: FromMarkdownOptions = {}) {
|
||||
function enterWikiLink(token) {
|
||||
this.enter(
|
||||
{
|
||||
type: "wikiLink",
|
||||
type: 'wikiLink',
|
||||
data: {
|
||||
isEmbed: token.isType === "embed",
|
||||
isEmbed: token.isType === 'embed',
|
||||
target: null, // the target of the link, e.g. "Foo Bar#Heading" in "[[Foo Bar#Heading]]"
|
||||
alias: null, // the alias of the link, e.g. "Foo" in "[[Foo Bar|Foo]]"
|
||||
permalink: null, // TODO shouldn't this be named just "link"?
|
||||
@@ -80,18 +89,18 @@ function fromMarkdown(opts: FromMarkdownOptions = {}) {
|
||||
} = wikiLink;
|
||||
// eslint-disable-next-line no-useless-escape
|
||||
const wikiLinkWithHeadingPattern = /^(.*?)(#.*)?$/u;
|
||||
const [, path, heading = ""] = target.match(wikiLinkWithHeadingPattern);
|
||||
const [, path, heading = ''] = target.match(wikiLinkWithHeadingPattern);
|
||||
|
||||
const possibleWikiLinkPermalinks = wikiLinkResolver(path);
|
||||
|
||||
const matchingPermalink = permalinks.find((e) => {
|
||||
return possibleWikiLinkPermalinks.find((p) => {
|
||||
if (pathFormat === "obsidian-short") {
|
||||
if (pathFormat === 'obsidian-short') {
|
||||
if (e === p || e.endsWith(p)) {
|
||||
return true;
|
||||
}
|
||||
} else if (pathFormat === "obsidian-absolute") {
|
||||
if (e === "/" + p) {
|
||||
} else if (pathFormat === 'obsidian-absolute') {
|
||||
if (e === '/' + p) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
@@ -106,20 +115,19 @@ function fromMarkdown(opts: FromMarkdownOptions = {}) {
|
||||
// TODO this is ugly
|
||||
const link =
|
||||
matchingPermalink ||
|
||||
(pathFormat === "obsidian-absolute"
|
||||
? "/" + possibleWikiLinkPermalinks[0]
|
||||
(pathFormat === 'obsidian-absolute'
|
||||
? '/' + possibleWikiLinkPermalinks[0]
|
||||
: possibleWikiLinkPermalinks[0]) ||
|
||||
"";
|
||||
'';
|
||||
|
||||
wikiLink.data.exists = !!matchingPermalink;
|
||||
wikiLink.data.permalink = link;
|
||||
|
||||
// remove leading # if the target is a heading on the same page
|
||||
const displayName = alias || target.replace(/^#/, "");
|
||||
const headingId = heading.replace(/\s+/g, "-").toLowerCase();
|
||||
const displayName = alias || target.replace(/^#/, '');
|
||||
const headingId = heading.replace(/\s+/g, '-').toLowerCase();
|
||||
let classNames = wikiLinkClassName;
|
||||
if (!matchingPermalink) {
|
||||
classNames += " " + newClassName;
|
||||
classNames += ' ' + newClassName;
|
||||
}
|
||||
|
||||
if (isEmbed) {
|
||||
@@ -127,44 +135,55 @@ function fromMarkdown(opts: FromMarkdownOptions = {}) {
|
||||
if (!isSupportedFormat) {
|
||||
// Temporarily render note transclusion as a regular wiki link
|
||||
if (!format) {
|
||||
wikiLink.data.hName = "a";
|
||||
wikiLink.data.hName = 'a';
|
||||
wikiLink.data.hProperties = {
|
||||
className: classNames + " " + "transclusion",
|
||||
className: classNames + ' ' + 'transclusion',
|
||||
href: hrefTemplate(link) + headingId,
|
||||
};
|
||||
wikiLink.data.hChildren = [{ type: "text", value: displayName }];
|
||||
|
||||
wikiLink.data.hChildren = [{ type: 'text', value: displayName }];
|
||||
} else {
|
||||
wikiLink.data.hName = "p";
|
||||
wikiLink.data.hName = 'p';
|
||||
wikiLink.data.hChildren = [
|
||||
{
|
||||
type: "text",
|
||||
type: 'text',
|
||||
value: `![[${target}]]`,
|
||||
},
|
||||
];
|
||||
}
|
||||
} else if (format === "pdf") {
|
||||
wikiLink.data.hName = "iframe";
|
||||
} else if (format === 'pdf') {
|
||||
wikiLink.data.hName = 'iframe';
|
||||
wikiLink.data.hProperties = {
|
||||
className: classNames,
|
||||
width: "100%",
|
||||
width: '100%',
|
||||
src: `${hrefTemplate(link)}#toolbar=0`,
|
||||
};
|
||||
} else {
|
||||
wikiLink.data.hName = "img";
|
||||
wikiLink.data.hProperties = {
|
||||
className: classNames,
|
||||
src: hrefTemplate(link),
|
||||
alt: displayName,
|
||||
};
|
||||
const hasDimensions = alias && /^\d+(x\d+)?$/.test(alias);
|
||||
// Take the target as alt text except if alt name was provided [[target|alt text]]
|
||||
const altText = hasDimensions || !alias ? target : alias;
|
||||
|
||||
wikiLink.data.hName = 'img';
|
||||
wikiLink.data.hProperties = {
|
||||
className: classNames,
|
||||
src: hrefTemplate(link),
|
||||
alt: altText
|
||||
};
|
||||
|
||||
if (hasDimensions) {
|
||||
const { width, height } = getImageSize(alias as string);
|
||||
Object.assign(wikiLink.data.hProperties, {
|
||||
width,
|
||||
height,
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
wikiLink.data.hName = "a";
|
||||
wikiLink.data.hName = 'a';
|
||||
wikiLink.data.hProperties = {
|
||||
className: classNames,
|
||||
href: hrefTemplate(link) + headingId,
|
||||
};
|
||||
wikiLink.data.hChildren = [{ type: "text", value: displayName }];
|
||||
wikiLink.data.hChildren = [{ type: 'text', value: displayName }];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,23 +1,24 @@
|
||||
import { isSupportedFileFormat } from "./isSupportedFileFormat";
|
||||
import { getImageSize } from './fromMarkdown';
|
||||
import { isSupportedFileFormat } from './isSupportedFileFormat';
|
||||
|
||||
const defaultWikiLinkResolver = (target: string) => {
|
||||
// for [[#heading]] links
|
||||
if (!target) {
|
||||
return [];
|
||||
}
|
||||
let permalink = target.replace(/\/index$/, "");
|
||||
let permalink = target.replace(/\/index$/, '');
|
||||
// TODO what to do with [[index]] link?
|
||||
if (permalink.length === 0) {
|
||||
permalink = "/";
|
||||
permalink = '/';
|
||||
}
|
||||
return [permalink];
|
||||
};
|
||||
|
||||
export interface HtmlOptions {
|
||||
pathFormat?:
|
||||
| "raw" // default; use for regular relative or absolute paths
|
||||
| "obsidian-absolute" // use for Obsidian-style absolute paths (with no leading slash)
|
||||
| "obsidian-short"; // use for Obsidian-style shortened paths (shortest path possible)
|
||||
| 'raw' // default; use for regular relative or absolute paths
|
||||
| 'obsidian-absolute' // use for Obsidian-style absolute paths (with no leading slash)
|
||||
| 'obsidian-short'; // use for Obsidian-style shortened paths (shortest path possible)
|
||||
permalinks?: string[]; // list of permalinks to match possible permalinks of a wiki link against
|
||||
wikiLinkResolver?: (name: string) => string[]; // function to resolve wiki links to an array of possible permalinks
|
||||
newClassName?: string; // class name to add to links that don't have a matching permalink
|
||||
@@ -28,11 +29,11 @@ export interface HtmlOptions {
|
||||
// Micromark HtmlExtension
|
||||
// https://github.com/micromark/micromark#htmlextension
|
||||
function html(opts: HtmlOptions = {}) {
|
||||
const pathFormat = opts.pathFormat || "raw";
|
||||
const pathFormat = opts.pathFormat || 'raw';
|
||||
const permalinks = opts.permalinks || [];
|
||||
const wikiLinkResolver = opts.wikiLinkResolver || defaultWikiLinkResolver;
|
||||
const newClassName = opts.newClassName || "new";
|
||||
const wikiLinkClassName = opts.wikiLinkClassName || "internal";
|
||||
const newClassName = opts.newClassName || 'new';
|
||||
const wikiLinkClassName = opts.wikiLinkClassName || 'internal';
|
||||
const defaultHrefTemplate = (permalink: string) => permalink;
|
||||
const hrefTemplate = opts.hrefTemplate || defaultHrefTemplate;
|
||||
|
||||
@@ -41,21 +42,21 @@ function html(opts: HtmlOptions = {}) {
|
||||
}
|
||||
|
||||
function enterWikiLink() {
|
||||
let stack = this.getData("wikiLinkStack");
|
||||
if (!stack) this.setData("wikiLinkStack", (stack = []));
|
||||
let stack = this.getData('wikiLinkStack');
|
||||
if (!stack) this.setData('wikiLinkStack', (stack = []));
|
||||
|
||||
stack.push({});
|
||||
}
|
||||
|
||||
function exitWikiLinkTarget(token) {
|
||||
const target = this.sliceSerialize(token);
|
||||
const current = top(this.getData("wikiLinkStack"));
|
||||
const current = top(this.getData('wikiLinkStack'));
|
||||
current.target = target;
|
||||
}
|
||||
|
||||
function exitWikiLinkAlias(token) {
|
||||
const alias = this.sliceSerialize(token);
|
||||
const current = top(this.getData("wikiLinkStack"));
|
||||
const current = top(this.getData('wikiLinkStack'));
|
||||
current.alias = alias;
|
||||
}
|
||||
|
||||
@@ -111,7 +112,9 @@ function html(opts: HtmlOptions = {}) {
|
||||
// Temporarily render note transclusion as a regular wiki link
|
||||
if (!format) {
|
||||
this.tag(
|
||||
`<a href="${hrefTemplate(link + headingId)}" class="${classNames} transclusion">`
|
||||
`<a href="${hrefTemplate(
|
||||
link + headingId
|
||||
)}" class="${classNames} transclusion">`
|
||||
);
|
||||
this.raw(displayName);
|
||||
this.tag("</a>");
|
||||
@@ -125,11 +128,18 @@ function html(opts: HtmlOptions = {}) {
|
||||
)}#toolbar=0" class="${classNames}" />`
|
||||
);
|
||||
} else {
|
||||
this.tag(
|
||||
`<img src="${hrefTemplate(
|
||||
link
|
||||
)}" alt="${displayName}" class="${classNames}" />`
|
||||
);
|
||||
const hasDimensions = alias && /^\d+(x\d+)?$/.test(alias);
|
||||
// Take the target as alt text except if alt name was provided [[target|alt text]]
|
||||
const altText = hasDimensions || !alias ? target : alias;
|
||||
let imgAttributes = `src="${hrefTemplate(
|
||||
link
|
||||
)}" alt="${altText}" class="${classNames}"`;
|
||||
|
||||
if (hasDimensions) {
|
||||
const { width, height } = getImageSize(alias as string);
|
||||
imgAttributes += ` width="${width}" height="${height}"`;
|
||||
}
|
||||
this.tag(`<img ${imgAttributes} />`);
|
||||
}
|
||||
} else {
|
||||
this.tag(
|
||||
|
||||
Reference in New Issue
Block a user