93 lines
2.0 KiB
TypeScript
93 lines
2.0 KiB
TypeScript
|
|
import { Lazy, resolve_lazy } from './lazy';
|
|
|
|
const attrs_pattern = /\s+\{\s*(?:[\.#:][^\s]+(?:\s*[\.#:][^\s]+)*)?\s*}$/;
|
|
|
|
export interface ParsedAttributes {
|
|
id?: string;
|
|
classes: string[];
|
|
attrs: Record<string, string | string[]>;
|
|
html_attrs: string[];
|
|
text: string;
|
|
}
|
|
|
|
export function parse_attributes(text: string, fallback_id?: Lazy<string>) {
|
|
const attrs: ParsedAttributes = {
|
|
id: null,
|
|
classes: [ ],
|
|
attrs: { },
|
|
html_attrs: [ ],
|
|
text,
|
|
};
|
|
|
|
const attrs_match = attrs_pattern.exec(text);
|
|
|
|
if (attrs_match) {
|
|
attrs.text = text.slice(0, -attrs_match[0].length).trim();
|
|
|
|
const raw_attrs = attrs_match[0].trim().slice(1, -1).trim().split(/\s+/g);
|
|
|
|
for (const attr of raw_attrs) {
|
|
if (attr.startsWith('.')) {
|
|
attrs.classes.push(attr.slice(1));
|
|
}
|
|
|
|
else if (attr.startsWith('#')) {
|
|
attrs.id = attr.slice(1);
|
|
}
|
|
|
|
else if (attr.startsWith(':')) {
|
|
const eq_index = attr.indexOf('=');
|
|
|
|
if (eq_index === -1) {
|
|
const name = attr.slice(1);
|
|
attrs.attrs[name] = '';
|
|
}
|
|
|
|
const name = attr.slice(1, eq_index);
|
|
const value = attr.slice(eq_index + 1);
|
|
|
|
// Enable passing the same attribute more than once for lists, i.e.:
|
|
// {:rel=external :rel=nofollow}
|
|
// should render as:
|
|
// rel="external nofollow"
|
|
if (attrs.attrs[name]) {
|
|
if (! Array.isArray(attrs.attrs[name])) {
|
|
attrs.attrs[name] = [ attrs.attrs[name] as string ];
|
|
}
|
|
|
|
(attrs.attrs[name] as string[]).push(value);
|
|
}
|
|
|
|
else {
|
|
attrs.attrs[name] = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (! attrs.id) {
|
|
attrs.id = resolve_lazy(fallback_id);
|
|
}
|
|
|
|
if (attrs.id) {
|
|
attrs.html_attrs.push(`id="${attrs.id}"`);
|
|
}
|
|
|
|
if (attrs.classes.length) {
|
|
attrs.html_attrs.push(`class="${attrs.classes.join(' ')}"`);
|
|
}
|
|
|
|
for (const [name, value] of Object.entries(attrs.attrs)) {
|
|
if (Array.isArray(value)) {
|
|
attrs.html_attrs.push(`${name}="${value.join(' ')}"`);
|
|
}
|
|
|
|
else {
|
|
attrs.html_attrs.push(value ? `${name}="${value}"` : name);
|
|
}
|
|
}
|
|
|
|
return attrs;
|
|
}
|