-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
aa434dd
commit e3364a7
Showing
6 changed files
with
295 additions
and
67 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<script lang="ts"> | ||
import { iframe } from "$lib/milkdown/iframe"; | ||
import { pageref } from "$lib/milkdown/pageref"; | ||
import { Editor, defaultValueCtx, rootCtx } from "@milkdown/core"; | ||
import { diagram } from "@milkdown/plugin-diagram"; | ||
import { listener, listenerCtx } from "@milkdown/plugin-listener"; | ||
import { prism, prismConfig } from "@milkdown/plugin-prism"; | ||
import { commonmark } from "@milkdown/preset-commonmark"; | ||
import { gfm } from "@milkdown/preset-gfm"; | ||
import javascript from "refractor/lang/javascript"; | ||
import markdown from "refractor/lang/markdown"; | ||
import { onDestroy, onMount } from "svelte"; | ||
export let initialValue: string; | ||
export let fileName: string; | ||
let unsavedMarkdown: string | null = null; | ||
const save = () => { | ||
if (unsavedMarkdown) { | ||
fetch(`/api/save/${fileName}`, { | ||
method: "PUT", | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify({ fileContents: unsavedMarkdown }), | ||
}); | ||
unsavedMarkdown = null; | ||
} | ||
}; | ||
const editor = (dom: HTMLElement) => { | ||
Editor.make() | ||
.config((ctx) => { | ||
const listener = ctx.get(listenerCtx); | ||
listener.markdownUpdated((_ctx, markdown, prevMarkdown) => { | ||
if (markdown === prevMarkdown) return; | ||
unsavedMarkdown = markdown; | ||
}); | ||
ctx.set(rootCtx, dom); | ||
ctx.set(defaultValueCtx, initialValue); | ||
ctx.set(prismConfig.key, { | ||
configureRefractor: (refractor) => { | ||
refractor.register(markdown); | ||
refractor.register(javascript); | ||
}, | ||
}); | ||
}) | ||
.use(commonmark) | ||
.use(gfm) | ||
.use(iframe) | ||
.use(pageref) | ||
.use(prism) | ||
.use(diagram) | ||
.use(listener) | ||
.create(); | ||
}; | ||
onMount(() => { | ||
const interval = setInterval(() => save(), 5000); | ||
const onVisibilityChange = () => { | ||
if (document.visibilityState === "hidden") { | ||
save(); | ||
} | ||
}; | ||
document.addEventListener("visibilitychange", onVisibilityChange); | ||
return () => { | ||
clearInterval(interval); | ||
document.removeEventListener("visibilitychange", onVisibilityChange); | ||
}; | ||
}); | ||
onDestroy(() => { | ||
save(); | ||
}); | ||
</script> | ||
|
||
<div use:editor></div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { $node, $remark, $inputRule } from "@milkdown/utils"; | ||
import directive from "remark-directive"; | ||
import { InputRule } from "prosemirror-inputrules"; | ||
|
||
const iframeNode = $node("iframe", () => ({ | ||
group: "block", | ||
atom: true, | ||
isolating: true, | ||
marks: "", | ||
attrs: { | ||
src: { default: null }, | ||
}, | ||
parseDOM: [ | ||
{ | ||
tag: "iframe", | ||
getAttrs: (dom) => ({ | ||
src: (dom as HTMLElement).getAttribute("src"), | ||
}), | ||
}, | ||
], | ||
toDOM: (node) => ["iframe", { ...node.attrs, contenteditable: false }, 0], | ||
parseMarkdown: { | ||
match: (node) => node.type === "leafDirective" && node.name === "iframe", | ||
runner: (state, node, type) => { | ||
state.addNode(type, { src: (node.attributes as { src: string }).src }); | ||
}, | ||
}, | ||
toMarkdown: { | ||
match: (node) => node.type.name === "iframe", | ||
runner: (state, node) => { | ||
state.addNode("leafDirective", undefined, undefined, { | ||
name: "iframe", | ||
attributes: { src: node.attrs.src }, | ||
}); | ||
}, | ||
}, | ||
})); | ||
|
||
const remarkPluginId = "iframe"; | ||
const remarkDirective = $remark(remarkPluginId, () => directive); | ||
|
||
const iframeInputRule = $inputRule( | ||
(ctx) => | ||
new InputRule(/::iframe\{src\="(?<src>[^"]+)?"?\}/, (state, match, start, end) => { | ||
const [okay, src = ""] = match; | ||
const { tr } = state; | ||
|
||
if (okay) { | ||
tr.replaceWith(start - 1, end, iframeNode.type(ctx).create({ src })); | ||
} | ||
|
||
return tr; | ||
}), | ||
); | ||
|
||
export const iframe = [remarkDirective, iframeNode, iframeInputRule]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
import { $node, $remark, $inputRule } from "@milkdown/utils"; | ||
import directive from "remark-directive"; | ||
import { InputRule } from "prosemirror-inputrules"; | ||
|
||
const pagerefNode = $node("pageref", () => ({ | ||
group: "inline", | ||
inline: true, | ||
attrs: { | ||
page: { default: "" }, | ||
}, | ||
parseDOM: [ | ||
{ | ||
tag: "a", | ||
getAttrs: (dom) => { | ||
console.log("parseDOM getAttrs", { dom }); | ||
return { | ||
page: (dom as HTMLElement).getAttribute("href").replace("/page/", ""), | ||
}; | ||
}, | ||
}, | ||
], | ||
toDOM: (node) => { | ||
console.log("toDOM", { node }); | ||
return ["a", { href: `/page/${node.attrs.page}` }, node.attrs.page]; | ||
}, | ||
parseMarkdown: { | ||
match: (node) => { | ||
console.log("parseMarkdown match", { node }); | ||
return node.type === "textDirective" && node.name === "pageref"; | ||
}, | ||
runner: (state, node, type) => { | ||
console.log("parseMarkdown runner", { node }); | ||
state.addNode(type, { page: (node.attributes as { page: string }).page }); | ||
console.log("parseMarkdown runner post-addnode", { node }); | ||
}, | ||
}, | ||
toMarkdown: { | ||
match: (node) => { | ||
console.log("toMarkdown match", { node }); | ||
return node.type.name === "pageref"; | ||
}, | ||
runner: (state, node) => { | ||
console.log("toMarkdown runner", { node }); | ||
state.addNode("textDirective", undefined, undefined, { | ||
name: "pageref", | ||
attributes: { page: node.attrs.page }, | ||
}); | ||
}, | ||
}, | ||
})); | ||
|
||
const remarkPluginId = "pageref"; | ||
const remarkDirective = $remark(remarkPluginId, () => directive); | ||
|
||
const pagerefInputRule = $inputRule( | ||
(ctx) => | ||
new InputRule( | ||
/::pageref\{page\="(?<page>[^"]+)?"?\}/, | ||
(state, match, start, end) => { | ||
console.log("pagerefInputRule", { match, start, end }); | ||
const [okay, page = ""] = match; | ||
const { tr } = state; | ||
|
||
if (okay) { | ||
tr.replaceWith(start - 1, end, pagerefNode.type(ctx).create({ page })); | ||
} | ||
|
||
return tr; | ||
}, | ||
), | ||
); | ||
|
||
export const pageref = [remarkDirective, pagerefNode, pagerefInputRule]; |
Oops, something went wrong.