Cat /dev/Nulo
7375a12c91
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
346 lines
7.6 KiB
TypeScript
346 lines
7.6 KiB
TypeScript
import { Schema } from "prosemirror-model";
|
|
import { parse } from "regexparam";
|
|
import { routes } from "../lib/routes";
|
|
|
|
const hex = (x: string) => ("0" + parseInt(x).toString(16)).slice(-2);
|
|
// https://stackoverflow.com/a/3627747
|
|
// TODO: cambiar por una solución más copada
|
|
function rgbToHex(rgb: string): string {
|
|
const matches = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
|
if (!matches) throw new Error("no pude parsear el rgb()");
|
|
return "#" + hex(matches[1]) + hex(matches[2]) + hex(matches[3]);
|
|
}
|
|
|
|
export type MultimediaKind = "img" | "video" | "audio" | "iframe";
|
|
|
|
export const schema = new Schema({
|
|
nodes: {
|
|
doc: {
|
|
content: "block+",
|
|
},
|
|
|
|
paragraph: {
|
|
content: "inline*",
|
|
group: "block",
|
|
parseDOM: [
|
|
{
|
|
tag: "p",
|
|
},
|
|
],
|
|
toDOM() {
|
|
return ["p", 0];
|
|
},
|
|
},
|
|
|
|
blockquote: {
|
|
content: "block+",
|
|
group: "block",
|
|
parseDOM: [{ tag: "blockquote" }],
|
|
toDOM() {
|
|
return ["blockquote", 0];
|
|
},
|
|
},
|
|
|
|
horizontal_rule: {
|
|
group: "block",
|
|
parseDOM: [{ tag: "hr" }],
|
|
toDOM() {
|
|
return ["div", ["hr"]];
|
|
},
|
|
},
|
|
|
|
heading: {
|
|
attrs: { level: { default: 1 } },
|
|
content: "text*",
|
|
group: "block",
|
|
defining: true,
|
|
parseDOM: [
|
|
{ tag: "h1" },
|
|
{ tag: "h2" },
|
|
{ tag: "h3" },
|
|
{ tag: "h4" },
|
|
{ tag: "h5" },
|
|
{ tag: "h6" },
|
|
],
|
|
toDOM(node) {
|
|
return ["h" + node.attrs.level, 0];
|
|
},
|
|
},
|
|
|
|
code_block: {
|
|
content: "text*",
|
|
group: "block",
|
|
code: true,
|
|
defining: true,
|
|
marks: "",
|
|
attrs: { params: { default: "" } },
|
|
parseDOM: [
|
|
{
|
|
tag: "pre",
|
|
preserveWhitespace: "full",
|
|
getAttrs: (node) => ({
|
|
params: (node as Element).getAttribute("data-params") || "",
|
|
}),
|
|
},
|
|
],
|
|
toDOM(node) {
|
|
return [
|
|
"pre",
|
|
node.attrs.params ? { "data-params": node.attrs.params } : {},
|
|
["code", 0],
|
|
];
|
|
},
|
|
},
|
|
|
|
ordered_list: {
|
|
content: "list_item+",
|
|
group: "block",
|
|
attrs: { order: { default: 1 } },
|
|
parseDOM: [
|
|
{
|
|
tag: "ol",
|
|
getAttrs(dom) {
|
|
dom = dom as HTMLElement;
|
|
const start = dom.getAttribute("start");
|
|
return {
|
|
order: start ? +start : 1,
|
|
};
|
|
},
|
|
},
|
|
],
|
|
toDOM(node) {
|
|
return node.attrs.order == 1
|
|
? ["ol", 0]
|
|
: ["ol", { start: node.attrs.order }, 0];
|
|
},
|
|
},
|
|
bullet_list: {
|
|
content: "list_item+",
|
|
group: "block",
|
|
parseDOM: [{ tag: "ul" }],
|
|
toDOM: () => ["ul", 0],
|
|
},
|
|
|
|
list_item: {
|
|
content: "paragraph block*",
|
|
defining: true,
|
|
parseDOM: [{ tag: "li" }],
|
|
toDOM() {
|
|
return ["li", 0];
|
|
},
|
|
},
|
|
|
|
text: {
|
|
group: "inline",
|
|
},
|
|
|
|
multimedia: {
|
|
group: "block",
|
|
attrs: { src: {}, kind: {} },
|
|
content: "text*",
|
|
parseDOM: [
|
|
{
|
|
tag: "figure",
|
|
getAttrs(dom) {
|
|
const child: HTMLElement | null =
|
|
(dom as Element).querySelector("img") ||
|
|
(dom as Element).querySelector("video") ||
|
|
(dom as Element).querySelector("audio") ||
|
|
(dom as Element).querySelector("iframe");
|
|
if (!child) return false;
|
|
|
|
if (child instanceof HTMLImageElement) {
|
|
return { src: child.src, kind: "img" };
|
|
} else if (child instanceof HTMLVideoElement) {
|
|
return { src: child.src, kind: "video" };
|
|
} else if (child instanceof HTMLAudioElement) {
|
|
return { src: child.src, kind: "audio" };
|
|
} else if (child instanceof HTMLIFrameElement) {
|
|
return { src: child.src, kind: "iframe" };
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
tag: "img",
|
|
getAttrs(dom) {
|
|
return { src: (dom as HTMLImageElement).src, kind: "img" };
|
|
},
|
|
},
|
|
{
|
|
tag: "video",
|
|
getAttrs(dom) {
|
|
return { src: (dom as HTMLVideoElement).src, kind: "video" };
|
|
},
|
|
},
|
|
{
|
|
tag: "audio",
|
|
getAttrs(dom) {
|
|
return { src: (dom as HTMLAudioElement).src, kind: "audio" };
|
|
},
|
|
},
|
|
{
|
|
tag: "iframe",
|
|
getAttrs(dom) {
|
|
return { src: (dom as HTMLIFrameElement).src, kind: "iframe" };
|
|
},
|
|
},
|
|
],
|
|
toDOM(node) {
|
|
return [
|
|
"figure",
|
|
[node.attrs.kind, { src: node.attrs.src }],
|
|
["figcaption", 0],
|
|
];
|
|
},
|
|
draggable: true,
|
|
},
|
|
|
|
hard_break: {
|
|
inline: true,
|
|
group: "inline",
|
|
selectable: false,
|
|
parseDOM: [{ tag: "br" }],
|
|
toDOM() {
|
|
return ["br"];
|
|
},
|
|
},
|
|
},
|
|
|
|
marks: {
|
|
em: {
|
|
parseDOM: [
|
|
{ tag: "i" },
|
|
{ tag: "em" },
|
|
{ style: "font-style", getAttrs: (value) => value == "italic" && null },
|
|
],
|
|
toDOM() {
|
|
return ["em"];
|
|
},
|
|
},
|
|
|
|
strong: {
|
|
parseDOM: [
|
|
{ tag: "b" },
|
|
{ tag: "strong" },
|
|
{
|
|
style: "font-weight",
|
|
getAttrs: (value) =>
|
|
/^(bold(er)?|[5-9]\d{2,})$/.test(value as string) && null,
|
|
},
|
|
],
|
|
toDOM() {
|
|
return ["strong"];
|
|
},
|
|
},
|
|
|
|
underline: {
|
|
parseDOM: [{ tag: "u" }],
|
|
toDOM() {
|
|
return ["u"];
|
|
},
|
|
},
|
|
strikethrough: {
|
|
parseDOM: [{ tag: "del" }],
|
|
toDOM() {
|
|
return ["del"];
|
|
},
|
|
},
|
|
small: {
|
|
parseDOM: [{ tag: "small" }],
|
|
toDOM() {
|
|
return ["small"];
|
|
},
|
|
},
|
|
|
|
mark: {
|
|
attrs: {
|
|
color: { default: "#f206f9" },
|
|
},
|
|
parseDOM: [
|
|
{
|
|
tag: "mark",
|
|
getAttrs(dom) {
|
|
const prop = (dom as HTMLElement).style.backgroundColor;
|
|
const hex = rgbToHex(prop);
|
|
return {
|
|
color: hex,
|
|
};
|
|
},
|
|
},
|
|
],
|
|
toDOM(node) {
|
|
return ["mark", { style: `background-color:${node.attrs.color}` }];
|
|
},
|
|
},
|
|
|
|
link: {
|
|
attrs: {
|
|
href: {},
|
|
},
|
|
inclusive: false,
|
|
parseDOM: [
|
|
{
|
|
tag: "a[href]",
|
|
getAttrs(dom) {
|
|
return {
|
|
href: (dom as Element).getAttribute("href"),
|
|
};
|
|
},
|
|
},
|
|
],
|
|
toDOM(node) {
|
|
const attrs = {
|
|
...node.attrs,
|
|
rel: "noopener",
|
|
referrerpolicy: "strict-origin-when-cross-origin",
|
|
};
|
|
|
|
return ["a", attrs];
|
|
},
|
|
},
|
|
internal_link: {
|
|
attrs: {
|
|
id: {},
|
|
},
|
|
inclusive: false,
|
|
parseDOM: [
|
|
{
|
|
tag: "a[href]",
|
|
priority: 100,
|
|
getAttrs(dom) {
|
|
dom = dom as HTMLElement;
|
|
const href = dom.getAttribute("href");
|
|
if (
|
|
href &&
|
|
(/^[useandom\-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict]{21}$/.test(
|
|
href
|
|
) || href === 'index')
|
|
) {
|
|
return {
|
|
id: href,
|
|
};
|
|
} else return false;
|
|
},
|
|
},
|
|
],
|
|
toDOM(node) {
|
|
return [
|
|
"a",
|
|
{
|
|
href: node.attrs.id,
|
|
//inject(routes.Page, {world:})
|
|
},
|
|
];
|
|
},
|
|
},
|
|
|
|
code: {
|
|
parseDOM: [{ tag: "code" }],
|
|
toDOM() {
|
|
return ["code"];
|
|
},
|
|
},
|
|
},
|
|
});
|