New HyperMD implementation with custom behaviour.
This commit is contained in:
parent
6abc467a43
commit
0b97e9a295
|
|
@ -1,107 +1,157 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
const External = Annotation.define<boolean>();
|
import type { Editor, EditorConfiguration, EditorChange } from 'codemirror';
|
||||||
|
import { changeEnd } from 'codemirror';
|
||||||
|
import { fromTextArea } from 'hypermd';
|
||||||
|
|
||||||
|
import '#shared/hypermd.extend';
|
||||||
|
|
||||||
|
function onChange(cm: Editor, change: EditorChange)
|
||||||
|
{
|
||||||
|
if (changeEnd(change).line == cm.lastLine())
|
||||||
|
updateBottomMargin(cm);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function updateBottomMargin(cm: Editor)
|
||||||
|
{
|
||||||
|
let padding = "";
|
||||||
|
if (cm.lineCount() > 1)
|
||||||
|
{
|
||||||
|
//@ts-ignore
|
||||||
|
let totalH = cm.display.scroller.clientHeight - 30, lastLineH = cm.getLineHandle(cm.lastLine()).height;
|
||||||
|
padding = (totalH / 2 - lastLineH) + "px";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cm.state.scrollPastEndPadding != padding)
|
||||||
|
{
|
||||||
|
cm.state.scrollPastEndPadding = padding;
|
||||||
|
cm.display.lineSpace.parentNode.style.paddingBottom = padding;
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { dropCursor, crosshairCursor, keymap, EditorView, ViewUpdate, placeholder as placeholderExtension } from '@codemirror/view';
|
|
||||||
import { Annotation, EditorState } from '@codemirror/state';
|
|
||||||
import { indentOnInput, syntaxHighlighting, defaultHighlightStyle, bracketMatching, foldKeymap } from '@codemirror/language';
|
|
||||||
import { history, defaultKeymap, historyKeymap } from '@codemirror/commands';
|
|
||||||
import { search, searchKeymap } from '@codemirror/search';
|
|
||||||
import { closeBrackets, closeBracketsKeymap, completionKeymap } from '@codemirror/autocomplete';
|
|
||||||
import { lintKeymap } from '@codemirror/lint';
|
|
||||||
|
|
||||||
const editor = useTemplateRef('editor');
|
const { placeholder, autofocus = false, gutters = true, format = 'd-any' } = defineProps<{
|
||||||
const view = ref<EditorView>();
|
|
||||||
const state = ref<EditorState>();
|
|
||||||
|
|
||||||
const { placeholder, autofocus = false } = defineProps<{
|
|
||||||
placeholder?: string
|
placeholder?: string
|
||||||
autofocus?: boolean
|
autofocus?: boolean
|
||||||
|
gutters?: boolean
|
||||||
|
format?: 'hypermd' | 'd-any'
|
||||||
}>();
|
}>();
|
||||||
const model = defineModel<string>();
|
const model = defineModel<string>();
|
||||||
|
const editor = ref<Editor>();
|
||||||
|
|
||||||
|
const input = useTemplateRef('input');
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if(editor.value)
|
if(input.value)
|
||||||
{
|
{
|
||||||
state.value = EditorState.create({
|
const e = editor.value = fromTextArea(input.value, {
|
||||||
doc: model.value,
|
mode: {
|
||||||
extensions: [
|
name: format,
|
||||||
history(),
|
hashtag: true,
|
||||||
search(),
|
toc: false,
|
||||||
dropCursor(),
|
math: false,
|
||||||
EditorState.allowMultipleSelections.of(true),
|
orgModeMarkup: false,
|
||||||
indentOnInput(),
|
tokenTypeOverrides: {
|
||||||
syntaxHighlighting(defaultHighlightStyle, { fallback: true }),
|
hr: "line-HyperMD-hr line-background-HyperMD-hr-bg hr",
|
||||||
bracketMatching(),
|
list1: "list-1",
|
||||||
closeBrackets(),
|
list2: "list-2",
|
||||||
crosshairCursor(),
|
list3: "list-3",
|
||||||
placeholderExtension(placeholder ?? ''),
|
code: "inline-code",
|
||||||
EditorView.lineWrapping,
|
hashtag: "hashtag meta"
|
||||||
keymap.of([
|
}
|
||||||
...closeBracketsKeymap,
|
},
|
||||||
...defaultKeymap,
|
spellcheck: true,
|
||||||
...searchKeymap,
|
autofocus: autofocus,
|
||||||
...historyKeymap,
|
lineNumbers: false,
|
||||||
...foldKeymap,
|
showCursorWhenSelecting: true,
|
||||||
...completionKeymap,
|
indentUnit: 4,
|
||||||
...lintKeymap
|
autoCloseBrackets: true,
|
||||||
]),
|
foldGutter: gutters,
|
||||||
EditorView.updateListener.of((viewUpdate: ViewUpdate) => {
|
theme: 'custom'
|
||||||
if (viewUpdate.docChanged && !viewUpdate.transactions.some(tr => tr.annotation(External)))
|
} as EditorConfiguration);
|
||||||
{
|
|
||||||
model.value = viewUpdate.state.doc.toString();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
EditorView.contentAttributes.of({spellcheck: "true"}),
|
|
||||||
]
|
|
||||||
});
|
|
||||||
view.value = new EditorView({
|
|
||||||
state: state.value,
|
|
||||||
parent: editor.value,
|
|
||||||
});
|
|
||||||
|
|
||||||
if(autofocus)
|
e.setValue(model.value ?? '');
|
||||||
{
|
updateBottomMargin(e);
|
||||||
view.value.focus();
|
e.on('change', onChange);
|
||||||
}
|
e.on('change', (cm: Editor, change: EditorChange) => model.value = cm.getValue());
|
||||||
}
|
e.on('refresh', updateBottomMargin);
|
||||||
})
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
if (view.value) {
|
|
||||||
view.value?.destroy()
|
|
||||||
view.value = undefined
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (model.value === void 0) {
|
const value = editor.value?.getValue();
|
||||||
return;
|
if (editor.value && model.value !== value) {
|
||||||
}
|
editor.value.setValue(model.value ?? '');
|
||||||
const currentValue = view.value ? view.value.state.doc.toString() : "";
|
editor.value.clearHistory();
|
||||||
if (view.value && model.value !== currentValue) {
|
|
||||||
view.value.dispatch({
|
|
||||||
changes: { from: 0, to: currentValue.length, insert: model.value || "" },
|
|
||||||
annotations: [External.of(true)],
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div ref="editor" class="flex flex-1 w-full justify-stretch items-stretch border border-light-35 dark:border-dark-35 caret-light-100 dark:caret-dark-100 py-2 px-1.5 font-sans text-base" />
|
<div :class="{ 'cancel-gutters': !gutters }" class="flex flex-1 w-full justify-stretch items-stretch !font-sans !text-base">
|
||||||
|
<textarea ref="input" class="hidden"></textarea>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.cm-editor
|
.CodeMirror
|
||||||
{
|
{
|
||||||
@apply bg-transparent;
|
@apply bg-transparent;
|
||||||
@apply flex-1;
|
@apply flex-1 h-full;
|
||||||
|
@apply font-sans;
|
||||||
|
|
||||||
|
@apply text-light-100 dark:text-dark-100;
|
||||||
}
|
}
|
||||||
.cm-editor .cm-content
|
.cancel-gutters .CodeMirror-gutters
|
||||||
{
|
{
|
||||||
@apply caret-light-100;
|
@apply hidden;
|
||||||
@apply dark:caret-dark-100;
|
}
|
||||||
|
.cancel-gutters .CodeMirror-sizer
|
||||||
|
{
|
||||||
|
@apply ms-2;
|
||||||
|
}
|
||||||
|
.CodeMirror-gutters
|
||||||
|
{
|
||||||
|
@apply bg-transparent;
|
||||||
|
@apply border-transparent;
|
||||||
|
}
|
||||||
|
.CodeMirror-gutter-wrapper
|
||||||
|
{
|
||||||
|
@apply absolute top-0 bottom-0;
|
||||||
|
@apply flex justify-center items-center;
|
||||||
|
}
|
||||||
|
.CodeMirror-foldmarker
|
||||||
|
{
|
||||||
|
@apply text-light-100;
|
||||||
|
@apply dark:text-dark-100;
|
||||||
|
@apply ps-3;
|
||||||
|
text-shadow: none;
|
||||||
|
}
|
||||||
|
.hmd-inactive-line .cm-formatting-header, .hmd-inactive-line .cm-formatting-link, .hmd-inactive-line .cm-link-has-alias, .hmd-inactive-line .cm-link-alias-pipe
|
||||||
|
{
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
.CodeMirror-line
|
||||||
|
{
|
||||||
|
@apply text-base;
|
||||||
|
}
|
||||||
|
.CodeMirror-cursor
|
||||||
|
{
|
||||||
|
@apply border-light-100 dark:border-dark-100;
|
||||||
|
}
|
||||||
|
.CodeMirror-selected
|
||||||
|
{
|
||||||
|
@apply bg-light-35 dark:bg-dark-35;
|
||||||
|
}
|
||||||
|
.HyperMD-list-line-1 {
|
||||||
|
@apply !ps-0;
|
||||||
|
}
|
||||||
|
.HyperMD-list-line-2 {
|
||||||
|
@apply !ps-6;
|
||||||
|
}
|
||||||
|
.HyperMD-list-line-3 {
|
||||||
|
@apply !ps-12;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
@ -25,8 +25,8 @@
|
||||||
<span @mousedown.left="(e) => resizeNode(e, 1, 0, -1, 1)" id="sw" class="cursor-sw-resize absolute -bottom-4 -left-4 w-8 h-8"></span> <!-- South West -->
|
<span @mousedown.left="(e) => resizeNode(e, 1, 0, -1, 1)" id="sw" class="cursor-sw-resize absolute -bottom-4 -left-4 w-8 h-8"></span> <!-- South West -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else style="outline-style: solid;" :class="[style.border, style.outline, { '!outline-4': focusing }]" class="outline-0 transition-[outline-width] border-2 bg-light-20 dark:bg-dark-20 overflow-hidden contain-strict w-full h-full flex" >
|
<div v-else style="outline-style: solid;" :class="[style.border, style.outline, { '!outline-4': focusing }]" class="outline-0 transition-[outline-width] border-2 bg-light-20 dark:bg-dark-20 overflow-hidden contain-strict w-full h-full flex py-2" >
|
||||||
<Editor v-model="node.text" autofocus />
|
<Editor v-model="node.text" autofocus :gutters="false"/>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="!editing && node.type === 'group' && node.label !== undefined" @click.left="(e) => selectNode(e)" @dblclick.left="(e) => editNode(e)" :class="style.border" style="max-width: 100%; font-size: calc(18px * var(--zoom-multiplier))" class="origin-bottom-left tracking-wider border-4 truncate inline-block text-light-100 dark:text-dark-100 absolute bottom-[100%] mb-2 px-2 py-1 font-thin">{{ node.label }}</div>
|
<div v-if="!editing && node.type === 'group' && node.label !== undefined" @click.left="(e) => selectNode(e)" @dblclick.left="(e) => editNode(e)" :class="style.border" style="max-width: 100%; font-size: calc(18px * var(--zoom-multiplier))" class="origin-bottom-left tracking-wider border-4 truncate inline-block text-light-100 dark:text-dark-100 absolute bottom-[100%] mb-2 px-2 py-1 font-thin">{{ node.label }}</div>
|
||||||
<input v-else-if="editing && node.type === 'group'" v-model="node.label" @click="e => e.stopImmediatePropagation()" v-autofocus :class="[style.border, style.outline]" style="max-width: 100%; font-size: calc(18px * var(--zoom-multiplier))" class="origin-bottom-left tracking-wider border-4 truncate inline-block text-light-100 dark:text-dark-100 absolute bottom-[100%] appearance-none bg-transparent outline-4 mb-2 px-2 py-1 font-thin min-w-4" />
|
<input v-else-if="editing && node.type === 'group'" v-model="node.label" @click="e => e.stopImmediatePropagation()" v-autofocus :class="[style.border, style.outline]" style="max-width: 100%; font-size: calc(18px * var(--zoom-multiplier))" class="origin-bottom-left tracking-wider border-4 truncate inline-block text-light-100 dark:text-dark-100 absolute bottom-[100%] appearance-none bg-transparent outline-4 mb-2 px-2 py-1 font-thin min-w-4" />
|
||||||
|
|
|
||||||
|
|
@ -28,3 +28,9 @@ const { hash, pathname } = parseURL(href);
|
||||||
const { content } = useContent();
|
const { content } = useContent();
|
||||||
const overview = computed(() => content.value.find(e => e.path === pathname));
|
const overview = computed(() => content.value.find(e => e.path === pathname));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.cm-link {
|
||||||
|
@apply text-accent-blue inline-flex items-center cursor-pointer hover:text-opacity-85;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -3,3 +3,26 @@
|
||||||
<slot />
|
<slot />
|
||||||
</blockquote>
|
</blockquote>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.HyperMD-quote
|
||||||
|
{
|
||||||
|
@apply before:hidden;
|
||||||
|
}
|
||||||
|
.HyperMD-quote.hmd-inactive-line
|
||||||
|
{
|
||||||
|
@apply before:block empty:before:!hidden !pb-2 !ps-4 !relative before:!absolute before:!-top-1 before:!-bottom-1 before:!left-0 before:!w-1 before:!bg-none before:!bg-light-30 dark:before:!bg-dark-30;
|
||||||
|
}
|
||||||
|
.HyperMD-quote.HyperMD-header
|
||||||
|
{
|
||||||
|
@apply before:!hidden;
|
||||||
|
}
|
||||||
|
.hmd-inactive-line .cm-formatting-quote
|
||||||
|
{
|
||||||
|
@apply !hidden;
|
||||||
|
}
|
||||||
|
.cm-quote
|
||||||
|
{
|
||||||
|
@apply text-light-100 dark:text-dark-100;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<code><slot /></code>
|
<code><slot /></code>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.cm-inline-code
|
||||||
|
{
|
||||||
|
@apply !border-none !bg-transparent !text-light-100 dark:!text-dark-100 !p-0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<h1 :id="parseId(id)" class="text-5xl font-thin mt-3 mb-8 first:pt-0 pt-2 relative lg:right-8 sm:right-4 right-2">
|
<h1 :id="parseId(id)" class="text-5xl font-thin mt-3 mb-8 first:pt-0 pt-2">
|
||||||
<slot />
|
<slot />
|
||||||
</h1>
|
</h1>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -8,3 +8,14 @@
|
||||||
import { parseId } from '#shared/general.util';
|
import { parseId } from '#shared/general.util';
|
||||||
const props = defineProps<{ id?: string }>()
|
const props = defineProps<{ id?: string }>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.HyperMD-header-1
|
||||||
|
{
|
||||||
|
@apply text-5xl pt-4 pb-2 after:hidden;
|
||||||
|
}
|
||||||
|
.HyperMD-header-1 .cm-header
|
||||||
|
{
|
||||||
|
@apply font-thin;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<template>
|
<template>
|
||||||
<h2 :id="parseId(id)" class="text-4xl font-semibold mt-3 mb-6 ms-1 first:pt-0 pt-2 relative sm:right-4 right-2">
|
<h2 :id="parseId(id)" class="text-4xl font-semibold mt-3 mb-6 ms-1 first:pt-0 pt-2">
|
||||||
<slot />
|
<slot />
|
||||||
</h2>
|
</h2>
|
||||||
</template>
|
</template>
|
||||||
|
|
@ -10,3 +10,14 @@ const props = defineProps<{ id?: string }>()
|
||||||
|
|
||||||
const generate = computed(() => props.id)
|
const generate = computed(() => props.id)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.HyperMD-header-2
|
||||||
|
{
|
||||||
|
@apply !text-4xl !pt-4 !pb-2 !ps-1 leading-loose after:hidden;
|
||||||
|
}
|
||||||
|
.HyperMD-header-2 .cm-header
|
||||||
|
{
|
||||||
|
@apply font-semibold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -10,3 +10,14 @@ const props = defineProps<{ id?: string }>()
|
||||||
|
|
||||||
const generate = computed(() => props.id)
|
const generate = computed(() => props.id)
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.HyperMD-header-3
|
||||||
|
{
|
||||||
|
@apply !text-2xl !font-bold !pt-1 after:!hidden;
|
||||||
|
}
|
||||||
|
.HyperMD-header-3 .cm-header
|
||||||
|
{
|
||||||
|
@apply font-bold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -8,3 +8,15 @@
|
||||||
import { parseId } from '#shared/general.util';
|
import { parseId } from '#shared/general.util';
|
||||||
const props = defineProps<{ id?: string }>()
|
const props = defineProps<{ id?: string }>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.HyperMD-header-4
|
||||||
|
{
|
||||||
|
@apply !text-xl font-semibold pt-1 after:hidden;
|
||||||
|
font-variant: small-caps;
|
||||||
|
}
|
||||||
|
.HyperMD-header-4 .cm-header
|
||||||
|
{
|
||||||
|
@apply font-semibold;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,3 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<Separator class="border-b border-light-35 dark:border-dark-35 m-4" />
|
<Separator class="border-b border-light-35 dark:border-dark-35 m-4" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.HyperMD-hr
|
||||||
|
{
|
||||||
|
@apply bg-light-35 dark:bg-dark-35 h-px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -1,3 +1,22 @@
|
||||||
<template>
|
<template>
|
||||||
<li class="before:absolute before:top-2 before:left-0 before:inline-block before:w-2 before:h-2 before:rounded before:bg-light-40 dark:before:bg-dark-40 relative ps-4"><slot /></li>
|
<li class="before:absolute before:top-2 before:left-0 before:inline-block before:w-2 before:h-2 before:rounded before:bg-light-40 dark:before:bg-dark-40 relative ps-4"><slot /></li>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.HyperMD-list-line
|
||||||
|
{
|
||||||
|
@apply !py-1;
|
||||||
|
}
|
||||||
|
.HyperMD-list-line.hmd-inactive-line > span
|
||||||
|
{
|
||||||
|
@apply before:absolute before:top-2 before:left-0 before:inline-block before:w-2 before:h-2 before:rounded before:bg-light-40 dark:before:bg-dark-40 relative ps-4;
|
||||||
|
}
|
||||||
|
.hmd-inactive-line .cm-formatting-list
|
||||||
|
{
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
.cm-hmd-list-indent
|
||||||
|
{
|
||||||
|
@apply !hidden;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -3,3 +3,14 @@
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.cm-hashtag.cm-hashtag-begin
|
||||||
|
{
|
||||||
|
@apply bg-accent-blue bg-opacity-10 text-accent-blue text-sm pb-0.5 ps-1 rounded-l-[12px] border border-r-0 border-accent-blue border-opacity-30;
|
||||||
|
}
|
||||||
|
.cm-hashtag.cm-hashtag-end
|
||||||
|
{
|
||||||
|
@apply bg-accent-blue bg-opacity-10 text-accent-blue text-sm pb-0.5 pe-1 rounded-r-[12px] !rounded-se-none border border-l-0 border-accent-blue border-opacity-30;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
BIN
db.sqlite-shm
BIN
db.sqlite-shm
Binary file not shown.
BIN
db.sqlite-wal
BIN
db.sqlite-wal
Binary file not shown.
30
package.json
30
package.json
|
|
@ -7,30 +7,34 @@
|
||||||
"dev": "NODE_TLS_REJECT_UNAUTHORIZED=0 bunx --bun nuxi dev"
|
"dev": "NODE_TLS_REJECT_UNAUTHORIZED=0 bunx --bun nuxi dev"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atlaskit/pragmatic-drag-and-drop": "^1.4.0",
|
"@atlaskit/pragmatic-drag-and-drop": "^1.5.0",
|
||||||
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.0.3",
|
||||||
"@iconify/vue": "^4.3.0",
|
"@iconify/vue": "^4.3.0",
|
||||||
|
"@lezer/highlight": "^1.2.1",
|
||||||
|
"@markdoc/markdoc": "^0.5.1",
|
||||||
"@nuxtjs/color-mode": "^3.5.2",
|
"@nuxtjs/color-mode": "^3.5.2",
|
||||||
"@nuxtjs/sitemap": "^7.2.3",
|
"@nuxtjs/sitemap": "^7.2.5",
|
||||||
"@nuxtjs/tailwindcss": "^6.13.1",
|
"@nuxtjs/tailwindcss": "^6.13.1",
|
||||||
|
"@types/codemirror": "^5.60.15",
|
||||||
"@vueuse/gesture": "^2.0.0",
|
"@vueuse/gesture": "^2.0.0",
|
||||||
"@vueuse/math": "^12.5.0",
|
"@vueuse/math": "^12.7.0",
|
||||||
"@vueuse/nuxt": "^12.5.0",
|
"@vueuse/nuxt": "^12.7.0",
|
||||||
"codemirror": "^6.0.1",
|
"codemirror": "5.65.18",
|
||||||
"drizzle-orm": "^0.38.4",
|
"drizzle-orm": "^0.39.3",
|
||||||
"hast": "^1.0.0",
|
"hast": "^1.0.0",
|
||||||
"hast-util-heading": "^3.0.0",
|
"hast-util-heading": "^3.0.0",
|
||||||
"hast-util-heading-rank": "^3.0.0",
|
"hast-util-heading-rank": "^3.0.0",
|
||||||
|
"hypermd": "^0.3.11",
|
||||||
"lodash.capitalize": "^4.2.1",
|
"lodash.capitalize": "^4.2.1",
|
||||||
"mdast-util-find-and-replace": "^3.0.2",
|
"mdast-util-find-and-replace": "^3.0.2",
|
||||||
"nodemailer": "^6.10.0",
|
"nodemailer": "^6.10.0",
|
||||||
"nuxt": "3.15.1",
|
"nuxt": "3.15.4",
|
||||||
"nuxt-security": "^2.1.5",
|
"nuxt-security": "^2.1.5",
|
||||||
"radix-vue": "^1.9.12",
|
"radix-vue": "^1.9.15",
|
||||||
"rehype-raw": "^7.0.0",
|
"rehype-raw": "^7.0.0",
|
||||||
"remark-breaks": "^4.0.0",
|
"remark-breaks": "^4.0.0",
|
||||||
"remark-frontmatter": "^5.0.0",
|
"remark-frontmatter": "^5.0.0",
|
||||||
"remark-gfm": "^4.0.0",
|
"remark-gfm": "^4.0.1",
|
||||||
"remark-ofm": "link:remark-ofm",
|
"remark-ofm": "link:remark-ofm",
|
||||||
"remark-parse": "^11.0.0",
|
"remark-parse": "^11.0.0",
|
||||||
"remark-rehype": "^11.1.1",
|
"remark-rehype": "^11.1.1",
|
||||||
|
|
@ -40,16 +44,16 @@
|
||||||
"unist-util-visit": "^5.0.0",
|
"unist-util-visit": "^5.0.0",
|
||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-router": "^4.5.0",
|
"vue-router": "^4.5.0",
|
||||||
"zod": "^3.24.1"
|
"zod": "^3.24.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "^1.2.0",
|
"@types/bun": "^1.2.2",
|
||||||
"@types/lodash.capitalize": "^4.2.9",
|
"@types/lodash.capitalize": "^4.2.9",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@types/unist": "^3.0.3",
|
"@types/unist": "^3.0.3",
|
||||||
"better-sqlite3": "^11.8.1",
|
"better-sqlite3": "^11.8.1",
|
||||||
"bun-types": "^1.2.0",
|
"bun-types": "^1.2.2",
|
||||||
"drizzle-kit": "^0.30.2",
|
"drizzle-kit": "^0.30.4",
|
||||||
"mdast-util-to-string": "^4.0.0",
|
"mdast-util-to-string": "^4.0.0",
|
||||||
"rehype-stringify": "^10.0.1"
|
"rehype-stringify": "^10.0.1"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,670 @@
|
||||||
|
import { defineMode, type Mode, getMode, StringStream, startState } from "codemirror";
|
||||||
|
import type { MarkdownState } from "hypermd/mode/hypermd";
|
||||||
|
|
||||||
|
const EN = /^(?:[*\-+]|^[0-9]+([.)]))\s+/, SN = /^(?:(?:(?:aaas?|about|acap|adiumxtra|af[ps]|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|cap|chrome(?:-extension)?|cid|coap|com-eventbrite-attendee|content|crid|cvs|data|dav|dict|dlna-(?:playcontainer|playsingle)|dns|doi|dtn|dvb|ed2k|facetime|feed|file|finger|fish|ftp|geo|gg|git|gizmoproject|go|gopher|gtalk|h323|hcp|https?|iax|icap|icon|im|imap|info|ipn|ipp|irc[6s]?|iris(?:\.beep|\.lwz|\.xpc|\.xpcs)?|itms|jar|javascript|jms|keyparc|lastfm|ldaps?|magnet|mailto|maps|market|message|mid|mms|ms-help|msnim|msrps?|mtqp|mumble|mupdate|mvn|news|nfs|nih?|nntp|notes|oid|opaquelocktoken|palm|paparazzi|platform|pop|pres|proxy|psyc|query|res(?:ource)?|rmi|rsync|rtmp|rtsp|secondlife|service|session|sftp|sgn|shttp|sieve|sips?|skype|sm[bs]|snmp|soap\.beeps?|soldat|spotify|ssh|steam|svn|tag|teamspeak|tel(?:net)?|tftp|things|thismessage|tip|tn3270|tv|udp|unreal|urn|ut2004|vemmi|ventrilo|view-source|webcal|wss?|wtai|wyciwyg|xcon(?:-userid)?|xfire|xmlrpc\.beeps?|xmpp|xri|ymsgr|z39\.50[rs]?):(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/i, xN = /^(?:(?:[^<>()[\]\\.,;:\s@\"`]+(?:\.[^<>()[\]\\.,;:\s@\"]+)*)|(?:\".+\"))@(?:(?:\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(?:(?:[a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))\b/, TN = /^(?:[^\u2000-\u206F\u2E00-\u2E7F'!"#$%&()*+,.:;<=>?@^`{|}~\[\]\\\s])+/;
|
||||||
|
const PN = /^\s*[^\|].*?\|.*[^|]\s*$/, IN = /^\s*[^\|].*\|/, FN = /^\|(?:[^|]+\|)+?\s*$/, ON = /^\|/, BN = /^\s*-+\s*:\s*$/, NN = /^\s*:\s*-+\s*$/, RN = /^\s*:\s*-+\s*:\s*$/, HN = /^\s*-+\s*$/;
|
||||||
|
const readSideRegex = /(?:([\u200F\p{sc=Arabic}\p{sc=Hebrew}\p{sc=Syriac}\p{sc=Thaana}])|([\u200E\p{sc=Armenian}\p{sc=Bengali}\p{sc=Bopomofo}\p{sc=Braille}\p{sc=Buhid}\p{sc=Canadian_Aboriginal}\p{sc=Cherokee}\p{sc=Cyrillic}\p{sc=Devanagari}\p{sc=Ethiopic}\p{sc=Georgian}\p{sc=Greek}\p{sc=Gujarati}\p{sc=Gurmukhi}\p{sc=Han}\p{sc=Hangul}\p{sc=Hanunoo}\p{sc=Hiragana}\p{sc=Kannada}\p{sc=Katakana}\p{sc=Khmer}\p{sc=Lao}\p{sc=Latin}\p{sc=Limbu}\p{sc=Malayalam}\p{sc=Mongolian}\p{sc=Myanmar}\p{sc=Ogham}\p{sc=Oriya}\p{sc=Runic}\p{sc=Sinhala}\p{sc=Tagalog}\p{sc=Tagbanwa}\p{sc=Tamil}\p{sc=Telugu}\p{sc=Thai}\p{sc=Tibetan}\p{sc=Yi}]))/u;
|
||||||
|
const readSide = function(e: string) {
|
||||||
|
var t = e.match(readSideRegex);
|
||||||
|
if (t) {
|
||||||
|
if (t[1])
|
||||||
|
return "rtl";
|
||||||
|
if (t[2])
|
||||||
|
return "ltr"
|
||||||
|
}
|
||||||
|
return "auto"
|
||||||
|
}
|
||||||
|
const isLetter = (e: string) => /[a-z]/i.test(e);
|
||||||
|
const clearSubstringWords = (str: string, substring: string) => str.replace(new RegExp("\\s?[^\\s]*".concat(substring, "[^\\s]*","g")), "");
|
||||||
|
const enum HashtagType {
|
||||||
|
NONE = 0,
|
||||||
|
NORMAL = 1,
|
||||||
|
WITH_SPACE = 2
|
||||||
|
}
|
||||||
|
const enum TableType {
|
||||||
|
NONE = 0,
|
||||||
|
SIMPLE = 1,
|
||||||
|
NORMAL = 2
|
||||||
|
}
|
||||||
|
const enum NextMaybe {
|
||||||
|
NONE = 0,
|
||||||
|
FRONT_MATTER = 1,
|
||||||
|
FRONT_MATTER_END = 2
|
||||||
|
}
|
||||||
|
const enum LinkType {
|
||||||
|
NONE = 0,
|
||||||
|
BARELINK = 1,
|
||||||
|
FOOTREF = 2,
|
||||||
|
NORMAL = 3,
|
||||||
|
FOOTNOTE = 4,
|
||||||
|
MAYBE_FOOTNOTE_URL = 5,
|
||||||
|
MAYBE_FOOTNOTE_URL_TITLE = 6,
|
||||||
|
BARELINK2 = 7,
|
||||||
|
FOOTREF2 = 8,
|
||||||
|
INTERNAL_LINK = 9,
|
||||||
|
EMBED = 10,
|
||||||
|
}
|
||||||
|
const CLASSES: Record<number, string> = {
|
||||||
|
1: "hmd-barelink",
|
||||||
|
7: "hmd-barelink2",
|
||||||
|
2: "hmd-barelink footref",
|
||||||
|
4: "hmd-barelink hmd-footnote line-HyperMD-footnote",
|
||||||
|
8: "hmd-footref2",
|
||||||
|
9: "hmd-internal-link",
|
||||||
|
10: "hmd-internal-link hmd-embed",
|
||||||
|
}
|
||||||
|
|
||||||
|
export declare type TokenFunc = (stream: CodeMirror.StringStream, state: HyperMDState) => string;
|
||||||
|
export declare type InnerModeExitChecker = (stream: CodeMirror.StringStream, state: HyperMDState) => {
|
||||||
|
endPos?: number;
|
||||||
|
skipInnerMode?: boolean;
|
||||||
|
style?: string;
|
||||||
|
} | null;
|
||||||
|
interface HyperMDState extends MarkdownState {
|
||||||
|
hmdTableRTL: boolean;
|
||||||
|
highlight: boolean;
|
||||||
|
hasAlias: boolean;
|
||||||
|
isAlias: boolean;
|
||||||
|
comment: boolean;
|
||||||
|
mathed: boolean;
|
||||||
|
internalEmbed: any;
|
||||||
|
internalLink: any;
|
||||||
|
inFootnote: boolean;
|
||||||
|
inlineFootnote: boolean;
|
||||||
|
wasHeading: boolean;
|
||||||
|
isHeading: boolean;
|
||||||
|
hmdTable: TableType;
|
||||||
|
hmdTableID: string | null;
|
||||||
|
hmdTableColumns: string[];
|
||||||
|
hmdTableCol: number;
|
||||||
|
hmdTableRow: number;
|
||||||
|
hmdOverride: TokenFunc | null;
|
||||||
|
hmdHashtag: HashtagType | boolean;
|
||||||
|
hmdInnerStyle: string;
|
||||||
|
hmdInnerExitChecker: InnerModeExitChecker | null;
|
||||||
|
hmdInnerMode: CodeMirror.Mode<any> | null;
|
||||||
|
hmdInnerState: any;
|
||||||
|
hmdLinkType: LinkType;
|
||||||
|
hmdNextMaybe: NextMaybe;
|
||||||
|
hmdNextState: HyperMDState | null;
|
||||||
|
hmdNextStyle: string | null;
|
||||||
|
hmdNextPos: number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetTable(state: HyperMDState)
|
||||||
|
{
|
||||||
|
state.hmdTable = TableType.NONE,
|
||||||
|
state.hmdTableRTL = !1,
|
||||||
|
state.hmdTableColumns = [],
|
||||||
|
state.hmdTableID = null,
|
||||||
|
state.hmdTableCol = state.hmdTableRow = 0
|
||||||
|
}
|
||||||
|
defineMode('d-any', function(cm, config) {
|
||||||
|
const markdownMode: Mode<MarkdownState> = getMode(cm, { ...config, name: 'markdown' }) as any;
|
||||||
|
const mode: Mode<HyperMDState> = getMode(cm, { ...config, name: 'hypermd' }) as any;
|
||||||
|
|
||||||
|
config = Object.assign({}, {
|
||||||
|
front_matter: !0,
|
||||||
|
math: !0,
|
||||||
|
table: !0,
|
||||||
|
toc: !0,
|
||||||
|
orgModeMarkup: !0,
|
||||||
|
hashtag: !0,
|
||||||
|
fencedCodeBlockHighlighting: !0,
|
||||||
|
highlightFormatting: !0,
|
||||||
|
taskLists: !0,
|
||||||
|
strikethrough: !0,
|
||||||
|
emoji: !1,
|
||||||
|
highlight: !0,
|
||||||
|
headers: !0,
|
||||||
|
blockquotes: !0,
|
||||||
|
indentedCode: !0,
|
||||||
|
lists: !0,
|
||||||
|
hr: !0,
|
||||||
|
blockId: !0
|
||||||
|
}, config)
|
||||||
|
|
||||||
|
function modeOverride(stream: CodeMirror.StringStream, state: HyperMDState): string {
|
||||||
|
const exit = state.hmdInnerExitChecker!(stream, state);
|
||||||
|
const extraStyle = state.hmdInnerStyle;
|
||||||
|
|
||||||
|
let ans = (!exit || !exit.skipInnerMode) && state.hmdInnerMode!.token(stream, state.hmdInnerState) || "";
|
||||||
|
|
||||||
|
if (extraStyle) ans += " " + extraStyle;
|
||||||
|
if (exit) {
|
||||||
|
if (exit.style) ans += " " + exit.style;
|
||||||
|
if (exit.endPos) stream.pos = exit.endPos;
|
||||||
|
|
||||||
|
state.hmdInnerExitChecker = null;
|
||||||
|
state.hmdInnerMode = null;
|
||||||
|
state.hmdInnerState = null;
|
||||||
|
state.hmdOverride = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function advanceMarkdown(stream: CodeMirror.StringStream, state: HyperMDState) {
|
||||||
|
if (stream.eol() || state.hmdNextState) return false;
|
||||||
|
|
||||||
|
let oldStart = stream.start;
|
||||||
|
let oldPos = stream.pos;
|
||||||
|
|
||||||
|
stream.start = oldPos;
|
||||||
|
let newState = { ...state };
|
||||||
|
let newStyle = mode.token(stream, newState);
|
||||||
|
|
||||||
|
state.hmdNextPos = stream.pos;
|
||||||
|
state.hmdNextState = newState;
|
||||||
|
state.hmdNextStyle = newStyle;
|
||||||
|
|
||||||
|
stream.start = oldStart;
|
||||||
|
stream.pos = oldPos;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDummyMode(endTag: string): CodeMirror.Mode<void> {
|
||||||
|
return {
|
||||||
|
token(stream) {
|
||||||
|
let endTagSince = stream.string.indexOf(endTag, stream.start);
|
||||||
|
if (endTagSince === -1) stream.skipToEnd(); // endTag not in this line
|
||||||
|
else if (endTagSince === 0) stream.pos += endTag.length; // current token is endTag
|
||||||
|
else {
|
||||||
|
stream.pos = endTagSince;
|
||||||
|
if (stream.string.charAt(endTagSince - 1) === "\\") stream.pos++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createSimpleInnerModeExitChecker(endTag: string, retInfo?: ReturnType<InnerModeExitChecker>): InnerModeExitChecker {
|
||||||
|
if (!retInfo) retInfo = {};
|
||||||
|
|
||||||
|
return function (stream, state) {
|
||||||
|
if (stream.string.substring(stream.start, stream.start + endTag.length) === endTag) {
|
||||||
|
retInfo.endPos = stream.start + endTag.length;
|
||||||
|
return retInfo;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BasicInnerModeOptions {
|
||||||
|
skipFirstToken?: boolean
|
||||||
|
style?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InnerModeOptions1 extends BasicInnerModeOptions {
|
||||||
|
fallbackMode: () => CodeMirror.Mode<any>
|
||||||
|
exitChecker: InnerModeExitChecker
|
||||||
|
}
|
||||||
|
|
||||||
|
interface InnerModeOptions2 extends BasicInnerModeOptions {
|
||||||
|
endTag: string
|
||||||
|
}
|
||||||
|
|
||||||
|
type InnerModeOptions = InnerModeOptions1 | InnerModeOptions2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* switch to another mode
|
||||||
|
*
|
||||||
|
* After entering a mode, you can then set `hmdInnerExitStyle` and `hmdInnerState` of `state`
|
||||||
|
*
|
||||||
|
* @returns if `skipFirstToken` not set, returns `innerMode.token(stream, innerState)`, meanwhile, stream advances
|
||||||
|
*/
|
||||||
|
function enterMode(stream: StringStream, state: HyperMDState, mode: string | CodeMirror.Mode<any> | null, opt: InnerModeOptions): string {
|
||||||
|
if (typeof mode === "string") mode = getMode(cm, mode);
|
||||||
|
|
||||||
|
if (!mode || mode["name"] === "null") {
|
||||||
|
if ('endTag' in opt) mode = createDummyMode(opt.endTag);
|
||||||
|
else if(typeof opt.fallbackMode === 'function') mode = opt.fallbackMode();
|
||||||
|
|
||||||
|
if (!mode) throw new Error("no mode");
|
||||||
|
}
|
||||||
|
|
||||||
|
state.hmdInnerExitChecker = ('endTag' in opt) ? createSimpleInnerModeExitChecker(opt.endTag) : opt.exitChecker;
|
||||||
|
state.hmdInnerStyle = opt.style ?? '';
|
||||||
|
state.hmdInnerMode = mode;
|
||||||
|
state.hmdOverride = modeOverride;
|
||||||
|
state.hmdInnerState = startState(mode);
|
||||||
|
|
||||||
|
let ans = opt.style || "";
|
||||||
|
if (!opt.skipFirstToken)
|
||||||
|
ans += " " + mode.token(stream, state.hmdInnerState);
|
||||||
|
|
||||||
|
return ans.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
const i: Record<string, any> = {
|
||||||
|
htmlBlock: null,
|
||||||
|
block: null
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'd-any',
|
||||||
|
...mode,
|
||||||
|
token(stream, _state) {
|
||||||
|
const state = _state as HyperMDState;
|
||||||
|
stream.tabSize = 4;
|
||||||
|
if (state.hmdOverride)
|
||||||
|
return state.hmdOverride(stream, state);
|
||||||
|
|
||||||
|
if (state.hmdTable && " " === stream.peek())
|
||||||
|
{
|
||||||
|
if ("|" === stream.string[stream.pos - 1] && "\\" !== stream.string[stream.pos - 2])
|
||||||
|
return stream.match(/^ +/), "";
|
||||||
|
if (stream.match(/^ +\|/))
|
||||||
|
return stream.backUp(1), "";
|
||||||
|
}
|
||||||
|
if (state.hmdNextMaybe === NextMaybe.FRONT_MATTER)
|
||||||
|
{
|
||||||
|
if ("---" === stream.string)
|
||||||
|
return state.hmdNextMaybe = NextMaybe.FRONT_MATTER_END, enterMode(stream, state, "yaml", {
|
||||||
|
style: "hmd-frontmatter",
|
||||||
|
fallbackMode: function() {
|
||||||
|
return createDummyMode("---");
|
||||||
|
},
|
||||||
|
exitChecker: function(e, stream) {
|
||||||
|
return e.string.startsWith("---") && "" === e.string.substring(3).trim() ? (stream.hmdNextMaybe = NextMaybe.NONE,
|
||||||
|
{
|
||||||
|
endPos: e.string.length
|
||||||
|
}) : null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
state.hmdNextMaybe = NextMaybe.NONE;
|
||||||
|
}
|
||||||
|
let a = state.f === i.htmlBlock, c = -1 === state.code, u = state.quote, h = 0 === stream.start;
|
||||||
|
h && (state.inFootnote && state.hmdLinkType === LinkType.MAYBE_FOOTNOTE_URL || (state.hmdLinkType = LinkType.NONE),
|
||||||
|
state.inlineFootnote = !1,
|
||||||
|
state.wasHeading = state.isHeading,
|
||||||
|
state.isHeading = !1,
|
||||||
|
!state.code || 1 !== state.code && 2 !== state.code || (state.code = 0));
|
||||||
|
let d, p, f = state.linkText, m = state.linkHref, v = !(c || a), g = v && !(state.code || state.indentedCode || state.linkHref), y = "", b = !1, w = -1, k = !1;
|
||||||
|
if (v)
|
||||||
|
{
|
||||||
|
if (g && "\\" === stream.peek() && (k = !0), state.list && !state.header && "#" === stream.peek() && /^\s*[*\-+]\s$/.test(stream.string.substring(0, stream.pos)))
|
||||||
|
{
|
||||||
|
const C = stream.match(/^(#+)(?: |$)/, !0);
|
||||||
|
if (C)
|
||||||
|
{
|
||||||
|
const M = C[1].length;
|
||||||
|
return state.header = M, "formatting formatting-header formatting-header-" + M + " header header-" + M;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config.math && g && "$" === stream.peek() && (state.hmdLinkType === LinkType.NONE || state.hmdLinkType === LinkType.MAYBE_FOOTNOTE_URL) && !state.internalLink && !state.internalEmbed)
|
||||||
|
{
|
||||||
|
let E: string[] | null = stream.match(/^(\$)[^\s$]/, !1), S = stream.match(/^(\${2})/, !1), x = E ? "$" : "$$";
|
||||||
|
if (E)
|
||||||
|
{
|
||||||
|
let I = stream.string.slice(stream.pos + 1).match(/[^\\]\$(.|$)/)
|
||||||
|
if(!I || !I[0].match(/^[^\s\\]\$([^0-9]|$)/))
|
||||||
|
E = null;
|
||||||
|
}
|
||||||
|
let T = !1;
|
||||||
|
if (E || S)
|
||||||
|
{
|
||||||
|
if (0 !== stream.pos || state.mathed)
|
||||||
|
{
|
||||||
|
let D = "math";
|
||||||
|
state.quote && (D += " line-HyperMD-quote line-HyperMD-quote-" + state.quote + " line-HyperMD-quote-lazy");
|
||||||
|
const A = getMode(cm, {
|
||||||
|
name: "stex"
|
||||||
|
}), L = "stex" !== A.name;
|
||||||
|
return y += enterMode(stream, state, A, {
|
||||||
|
style: D,
|
||||||
|
skipFirstToken: L,
|
||||||
|
fallbackMode: function() {
|
||||||
|
return createDummyMode(x);
|
||||||
|
},
|
||||||
|
exitChecker: function(e, stream) {
|
||||||
|
let n = e.start, i = e.string, r = "formatting formatting-math formatting-math-end math-";
|
||||||
|
return stream.hmdTable && "|" === i[n] ? {
|
||||||
|
endPos: n,
|
||||||
|
style: r
|
||||||
|
} : i.substring(n, n + x.length) === x ? {
|
||||||
|
endPos: n + x.length,
|
||||||
|
style: r
|
||||||
|
} : null;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
E ? (L && (stream.pos += E[1].length),
|
||||||
|
y += " formatting formatting-math formatting-math-begin") : (L && (stream.pos += S[1].length),
|
||||||
|
y += " formatting formatting-math formatting-math-begin math-block")
|
||||||
|
}
|
||||||
|
T = !0, w = 0;
|
||||||
|
}
|
||||||
|
state.mathed = T;
|
||||||
|
}
|
||||||
|
if (g) {
|
||||||
|
state.internalLink ? (state.hmdLinkType = LinkType.INTERNAL_LINK,
|
||||||
|
state.internalLink = !1) : state.internalEmbed && (state.hmdLinkType = LinkType.EMBED,
|
||||||
|
state.internalEmbed = !1);
|
||||||
|
let P = state.hmdLinkType === LinkType.INTERNAL_LINK || state.hmdLinkType === LinkType.EMBED;
|
||||||
|
if (P)
|
||||||
|
if ("|" === stream.peek())
|
||||||
|
state.isAlias = !0,
|
||||||
|
w = stream.pos + 1,
|
||||||
|
y += " link-alias-pipe";
|
||||||
|
else if ("]" === stream.peek() && stream.match("]]", !1))
|
||||||
|
state.hmdLinkType = LinkType.NONE,
|
||||||
|
state.linkText = !1,
|
||||||
|
state.isAlias = !1,
|
||||||
|
state.hasAlias = !1,
|
||||||
|
w = stream.pos + 2,
|
||||||
|
y += " formatting-link formatting-link-end";
|
||||||
|
else {
|
||||||
|
b = !0,
|
||||||
|
state.isAlias && (y += " link-alias"),
|
||||||
|
state.hasAlias && !state.isAlias && (y += " link-has-alias");
|
||||||
|
let I = stream.match(/^([^|\]]*?)/, !1);
|
||||||
|
w = stream.pos + Math.max(1, I[0].length)
|
||||||
|
}
|
||||||
|
else if("!" === stream.peek() || "[" === stream.peek())
|
||||||
|
{
|
||||||
|
const I = stream.match(/^(!?\[\[)(.*?)]]/, !1)
|
||||||
|
if(I)
|
||||||
|
"!" === I[1].charAt(0) ? (y += " formatting-link formatting-link-start formatting-embed", state.internalEmbed = !0) : (y += " formatting-link formatting-link-start", state.internalLink = !0), w = stream.pos + I[1].length, state.hasAlias = I[2].includes("|");
|
||||||
|
}
|
||||||
|
if (state.hmdLinkType === LinkType.FOOTREF)
|
||||||
|
if (b = !0,
|
||||||
|
"]" === stream.peek())
|
||||||
|
state.hmdLinkType = LinkType.NONE,
|
||||||
|
w = stream.pos + 1,
|
||||||
|
y += " formatting formatting-link formatting-link-end " + CLASSES[LinkType.FOOTREF];
|
||||||
|
else {
|
||||||
|
let I = stream.match(/^([^\]]*?)/, !1);
|
||||||
|
w = stream.pos + Math.max(1, I[0].length)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const I = stream.peek() === "[" && stream.match(/^\[\^([^\]\s]*?)\](:?)/, false);
|
||||||
|
if(I && (h || I[2]))
|
||||||
|
{
|
||||||
|
stream.match("[^"),
|
||||||
|
y += " formatting formatting-link formatting-link-start",
|
||||||
|
state.hmdLinkType = LinkType.FOOTREF,
|
||||||
|
w = stream.pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (config.blockId && "^" === stream.peek() && stream.match(/^\^([a-zA-Z0-9\-]+)$/))
|
||||||
|
return y += " blockid";
|
||||||
|
!state.inlineFootnote && "^" === stream.peek() && stream.match("^[", !1) ? (state.inlineFootnote = !0,
|
||||||
|
y += " inline-footnote-start formatting-inline-footnote",
|
||||||
|
w = stream.pos + 2) : state.inlineFootnote && !P && state.hmdLinkType === LinkType.NONE && !state.image && stream.match("]") && (state.inlineFootnote = !1,
|
||||||
|
y += " footref inline-footnote inline-footnote-end formatting-inline-footnote",
|
||||||
|
w = stream.pos),
|
||||||
|
"%" === stream.peek() && stream.match("%%", !1) ? (state.comment ? (y += " comment formatting comment-end",
|
||||||
|
state.comment = !1) : (y += " comment formatting comment-start",
|
||||||
|
state.comment = !0),
|
||||||
|
w = stream.pos + 2) : state.comment && (y += " comment")
|
||||||
|
}
|
||||||
|
if (g && (state.hmdLinkType || state.image || state.linkText || (isLetter(stream.peek()!) && stream.match(SN) || (p = stream.peek(),
|
||||||
|
!/[\s<>()[\]\\.,;:\s@\"`]/.test(p!) && stream.match(xN))) && (y += " url",
|
||||||
|
w = stream.pos)),
|
||||||
|
h && state.inFootnote) {
|
||||||
|
let F = stream.match(/^\s*/, !1)[0].replace(/\stream/g, " ").length;
|
||||||
|
F && F % stream.tabSize == 0 ? y += " line-HyperMD-footnote" : state.inFootnote = !1
|
||||||
|
}
|
||||||
|
let O = h && "[" === stream.peek() && stream.match(/^\[((?:[^\]\\]|\\.)*)\]:/, !1);
|
||||||
|
if (O) {
|
||||||
|
let B = O[1];
|
||||||
|
if ("^" !== B[0] || !/\s/.test(B))
|
||||||
|
return stream.match(/\[\^?/),
|
||||||
|
state.hmdLinkType = LinkType.FOOTNOTE,
|
||||||
|
state.formatting = "link",
|
||||||
|
state.linkText = !0,
|
||||||
|
y += "formatting formatting-link link " + CLASSES[LinkType.FOOTNOTE]
|
||||||
|
} else if (state.hmdLinkType === LinkType.FOOTNOTE) {
|
||||||
|
if ("]" === stream.peek() && stream.match("]:"))
|
||||||
|
return y += " formatting formatting-link link " + CLASSES[LinkType.FOOTNOTE],
|
||||||
|
state.linkText = !1,
|
||||||
|
state.inFootnote = !0,
|
||||||
|
state.hmdLinkType = LinkType.MAYBE_FOOTNOTE_URL,
|
||||||
|
//@ts-ignore
|
||||||
|
state.f = state.inline = markdownMode.startState().inline,
|
||||||
|
y;
|
||||||
|
y += " link " + CLASSES[LinkType.FOOTNOTE]
|
||||||
|
} else if (state.hmdLinkType === LinkType.MAYBE_FOOTNOTE_URL) {
|
||||||
|
if (stream.eatSpace())
|
||||||
|
return y;
|
||||||
|
if (isLetter(stream.peek()!) && stream.match(SN))
|
||||||
|
return y += " url hmd-footnote-url",
|
||||||
|
state.hmdLinkType = LinkType.MAYBE_FOOTNOTE_URL_TITLE,
|
||||||
|
y;
|
||||||
|
state.hmdLinkType = LinkType.NONE
|
||||||
|
} else if (state.hmdLinkType === LinkType.MAYBE_FOOTNOTE_URL_TITLE) {
|
||||||
|
if (stream.eatSpace())
|
||||||
|
return y;
|
||||||
|
if (state.hmdLinkType = LinkType.NONE,
|
||||||
|
stream.match(/^(["']).*?\1/) || stream.match(/^\([^)]*?\)/))
|
||||||
|
return y += " hmd-footnote-url-title"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (state.hmdTable && "|" === stream.peek() && "\\" !== stream.string[stream.pos - 1] && function(e)
|
||||||
|
{
|
||||||
|
e.code = !1,
|
||||||
|
e.comment = !1,
|
||||||
|
e.em = !1,
|
||||||
|
e.formatting = !1,
|
||||||
|
e.highlight = !1,
|
||||||
|
e.hmdHashtag = !1,
|
||||||
|
e.hmdLinkType = LinkType.NONE,
|
||||||
|
e.isAlias = !1,
|
||||||
|
e.internalEmbed = !1,
|
||||||
|
e.internalLink = !1,
|
||||||
|
e.linkHref = !1,
|
||||||
|
e.linkText = !1,
|
||||||
|
e.linkTitle = !1,
|
||||||
|
e.strikethrough = !1,
|
||||||
|
e.strong = !1
|
||||||
|
}(state),
|
||||||
|
state.hmdNextState)
|
||||||
|
stream.pos = state.hmdNextPos!,
|
||||||
|
y += " " + (state.hmdNextStyle || ""),
|
||||||
|
Object.assign(state, state.hmdNextState),
|
||||||
|
state.hmdNextState = null,
|
||||||
|
state.hmdNextStyle = null,
|
||||||
|
state.hmdNextPos = null;
|
||||||
|
else {
|
||||||
|
let N = h && 0 !== stream.pos;
|
||||||
|
if (b) {
|
||||||
|
//@ts-ignore
|
||||||
|
let R = markdownMode.copyState(state), H = stream.pos;
|
||||||
|
y += " " + (markdownMode.token(stream, R) || ""),
|
||||||
|
stream.pos = H
|
||||||
|
} else
|
||||||
|
y += " " + (markdownMode.token(stream, state) || "");
|
||||||
|
//@ts-ignore
|
||||||
|
N && state.f === state.block && (state.f = state.inline = markdownMode.startState().inline),
|
||||||
|
state.inFootnote && (state.indentationDiff = 0)
|
||||||
|
}
|
||||||
|
y = function(e, text) {
|
||||||
|
return text ? (!config.hr && e.hr && (text = clearSubstringWords(text, "hr"),
|
||||||
|
e.hr = !1),
|
||||||
|
!config.headers && e.header && (text = clearSubstringWords(text, "header"),
|
||||||
|
e.header = 0),
|
||||||
|
!config.indentedCode && e.indentedCode && (text = clearSubstringWords(text, "inline-code"),
|
||||||
|
e.indentedCode = !1),
|
||||||
|
!config.blockquotes && e.quote && (text = clearSubstringWords(text, "quote"),
|
||||||
|
e.quote = 0),
|
||||||
|
!config.lists && e.list && (text = clearSubstringWords(text, "list"),
|
||||||
|
e.list = !1),
|
||||||
|
text) : text
|
||||||
|
}(state, y),
|
||||||
|
y.includes("formatting-task") && (y += " line-HyperMD-task-line"),
|
||||||
|
state.hmdHashtag && (y += " " + config.tokenTypeOverrides.hashtag),
|
||||||
|
-1 !== w && (stream.pos = w),
|
||||||
|
state.header && (state.isHeading = !0),
|
||||||
|
!i.htmlBlock && state.htmlState && (i.htmlBlock = state.f);
|
||||||
|
let V = state.f === i.htmlBlock
|
||||||
|
, z = -1 === state.code;
|
||||||
|
if (v = v && !(V || z),
|
||||||
|
g = g && v && !(state.code || state.indentedCode || state.linkHref),
|
||||||
|
state.hmdTable && V) {
|
||||||
|
let q = stream.current();
|
||||||
|
/(?:^|[^\\])\|/.test(q) && ("" === y.trim() || /string|attribute/.test(y)) && (V = !1,
|
||||||
|
a = !1,
|
||||||
|
state.htmlState = null,
|
||||||
|
state.block = i.block,
|
||||||
|
//@ts-ignore
|
||||||
|
state.f = state.inline = markdownMode.startState().inline,
|
||||||
|
stream.pos = "|" === q ? stream.start : stream.start + 1)
|
||||||
|
}
|
||||||
|
let U = stream.current();
|
||||||
|
if (V !== a && (V ? (y += " hmd-html-begin",
|
||||||
|
i.htmlBlock = state.f) : y += " hmd-html-end"),
|
||||||
|
(c || z) && (state.localMode && c || (y = y.replace("inline-code", "")),
|
||||||
|
y += " line-HyperMD-codeblock line-background-HyperMD-codeblock-bg hmd-codeblock",
|
||||||
|
z !== c && (z ? c || (y += " line-HyperMD-codeblock-begin line-background-HyperMD-codeblock-begin-bg") : y += " line-HyperMD-codeblock-end line-background-HyperMD-codeblock-end-bg")),
|
||||||
|
v) {
|
||||||
|
let _ = state.hmdTable;
|
||||||
|
if (h && _)
|
||||||
|
(_ == TableType.SIMPLE ? IN : ON).test(stream.string) ? (state.hmdTableCol = 0,
|
||||||
|
state.hmdTableRow++) : resetTable(state);
|
||||||
|
if (h && state.header && (/^(?:---+|===+)\s*$/.test(stream.string) && state.prevLine && state.prevLine.header ? y += " line-HyperMD-header-line line-HyperMD-header-line-" + state.header : y += " line-HyperMD-header line-HyperMD-header-" + state.header),
|
||||||
|
state.indentedCode && (y += " hmd-indented-code"),
|
||||||
|
state.quote) {
|
||||||
|
if (stream.match(/^\s*>/, !1) && !stream.eol() || (y += " line-HyperMD-quote line-HyperMD-quote-" + state.quote,
|
||||||
|
/^ {0,3}\>/.test(stream.string) || (y += " line-HyperMD-quote-lazy")),
|
||||||
|
h && (d = U.match(/^\s+/)))
|
||||||
|
return stream.pos = d![0].length,
|
||||||
|
(y += " hmd-indent-in-quote").trim();
|
||||||
|
if (state.quote > u)
|
||||||
|
{
|
||||||
|
const I = "[" === stream.peek() && stream.match(/^\[!([^\]]+)\]([+\-]?)(?:\s|$)/);
|
||||||
|
if(I)
|
||||||
|
y += " line-HyperMD-callout hmd-callout line-HyperMD-quote line-HyperMD-quote-" + state.quote
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let W = (state.listStack[state.listStack.length - 1] || 0) + 3
|
||||||
|
, j = h && /^\s+$/.test(U) && (!1 !== state.list || stream.indentation() <= W)
|
||||||
|
, G = state.list && y.includes("formatting-list");
|
||||||
|
if (G || j && (!1 !== state.list || stream.match(EN, !1))) {
|
||||||
|
let K = state.listStack && state.listStack.length || 0;
|
||||||
|
if (j) {
|
||||||
|
if (stream.match(EN, !1))
|
||||||
|
!1 === state.list && K++;
|
||||||
|
else {
|
||||||
|
for (; K > 0 && stream.pos < state.listStack[K - 1]; )
|
||||||
|
K--;
|
||||||
|
if (!K)
|
||||||
|
return y.trim() || null;
|
||||||
|
y += " line-HyperMD-list-line-nobullet line-HyperMD-list-line line-HyperMD-list-line-".concat(K.toString())
|
||||||
|
}
|
||||||
|
y += " hmd-list-indent hmd-list-indent-".concat(K.toString())
|
||||||
|
} else
|
||||||
|
G && (y += " line-HyperMD-list-line line-HyperMD-list-line-".concat(K.toString()))
|
||||||
|
}
|
||||||
|
if (f !== state.linkText && (f || state.internalLink || state.internalEmbed ? state.hmdLinkType !== LinkType.FOOTNOTE && (state.hmdLinkType in CLASSES && (y += " " + CLASSES[state.hmdLinkType]),
|
||||||
|
state.hmdLinkType = LinkType.NONE) : (d = stream.match(/^([^\]]+)\](\(| ?\[|\:)?/, !1)) ? d[2] ? "[" !== d[2] && " [" !== d[2] || "]" !== stream.string.charAt(stream.pos + d[0].length) ? state.hmdLinkType = LinkType.NORMAL : state.hmdLinkType = LinkType.BARELINK2 : "^" !== d[1][0] || /\s/.test(d[1]) ? state.hmdLinkType = LinkType.BARELINK : state.hmdLinkType = LinkType.FOOTREF : state.hmdLinkType = LinkType.BARELINK),
|
||||||
|
m !== state.linkHref && (m ? state.hmdLinkType && (y += " " + CLASSES[state.hmdLinkType],
|
||||||
|
state.hmdLinkType = LinkType.NONE) : "[" === U && "]" !== stream.peek() && (state.hmdLinkType = LinkType.FOOTREF2)),
|
||||||
|
state.hmdLinkType !== LinkType.NONE && state.hmdLinkType in CLASSES && (y += " " + CLASSES[state.hmdLinkType]),
|
||||||
|
state.inlineFootnote && (y += " footref inline-footnote"),
|
||||||
|
k && U.length > 1) {
|
||||||
|
let Y = U.length - 1
|
||||||
|
, Z = y.replace("formatting-escape", "escape") + " hmd-escape-char";
|
||||||
|
return state.hmdOverride = function(e, stream) {
|
||||||
|
return e.pos += Y,
|
||||||
|
stream.hmdOverride = null,
|
||||||
|
Z.trim()
|
||||||
|
}
|
||||||
|
,
|
||||||
|
y += " hmd-escape-backslash",
|
||||||
|
stream.pos -= Y,
|
||||||
|
y
|
||||||
|
}
|
||||||
|
if (!y.trim() && config.table) {
|
||||||
|
let X = !1;
|
||||||
|
if ("|" === U.charAt(0) && (stream.pos = stream.start + 1,
|
||||||
|
U = "|",
|
||||||
|
X = !0),
|
||||||
|
!_ && state.prevLine && state.prevLine.stream && state.prevLine.stream.string.trim() && !state.wasHeading && (X = !1),
|
||||||
|
X) {
|
||||||
|
if (!_) {
|
||||||
|
PN.test(stream.string) ? _ = TableType.SIMPLE : FN.test(stream.string) && (_ = TableType.NORMAL);
|
||||||
|
let $: string[] | undefined = void 0;
|
||||||
|
if (_) {
|
||||||
|
let Q = stream.lookAhead(1);
|
||||||
|
if (_ === TableType.NORMAL ? FN.test(Q) ? Q = Q.replace(/^\s*\|/, "").replace(/\|\s*$/, "") : _ = TableType.NONE : _ === TableType.SIMPLE && (PN.test(Q) || (_ = TableType.NONE)),
|
||||||
|
_) {
|
||||||
|
$ = Q.split("|");
|
||||||
|
for (let J = 0; J < $.length; J++) {
|
||||||
|
let ee = $[J];
|
||||||
|
if (BN.test(ee))
|
||||||
|
ee = "right";
|
||||||
|
else if (NN.test(ee))
|
||||||
|
ee = "left";
|
||||||
|
else if (RN.test(ee))
|
||||||
|
ee = "center";
|
||||||
|
else {
|
||||||
|
if (!HN.test(ee)) {
|
||||||
|
_ = TableType.NONE;
|
||||||
|
break
|
||||||
|
}
|
||||||
|
ee = "default"
|
||||||
|
}
|
||||||
|
$[J] = ee
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ && (state.hmdTable = _,
|
||||||
|
state.hmdTableColumns = $!,
|
||||||
|
"rtl" === readSide(stream.string) && (state.hmdTableRTL = !0),
|
||||||
|
state.hmdTableRow = state.hmdTableCol = 0)
|
||||||
|
}
|
||||||
|
if (_) {
|
||||||
|
let te = state.hmdTableColumns.length - 1
|
||||||
|
, ne = state.hmdTableCol
|
||||||
|
, ee = state.hmdTableRow;
|
||||||
|
0 == ne && (y += " line-HyperMD-table-".concat(_.toString(), " line-HyperMD-table-row line-HyperMD-table-row-").concat(ee.toString()),
|
||||||
|
state.hmdTableRTL && (y += " line-HyperMD-table-rtl")),
|
||||||
|
_ === TableType.NORMAL && (0 === state.hmdTableCol && /^\s*\|$/.test(stream.string.slice(0, stream.pos)) || stream.match(/^\s*$/, !1)) ? y += " hmd-table-sep hmd-table-sep-dummy" : state.hmdTableCol < te && (y += " hmd-table-sep hmd-table-sep-".concat(ne.toString()),
|
||||||
|
state.hmdTableCol += 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_ && 1 === state.hmdTableRow && y.includes("emoji") && (y = ""),
|
||||||
|
g && "<" === U) {
|
||||||
|
let ie = null;
|
||||||
|
if ("!" === stream.peek() && stream.match(/^\![A-Z]+/) ? ie = ">" : "!" === stream.peek() && stream.match("![CDATA[") ? ie = "]]>" : "?" === stream.peek() && (ie = "?>"),
|
||||||
|
null != ie)
|
||||||
|
return enterMode(stream, state, null, {
|
||||||
|
endTag: ie,
|
||||||
|
style: (y + " comment hmd-cdata-html").trim()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (config.hashtag && g)
|
||||||
|
if (state.hmdHashtag) {
|
||||||
|
let re = !1;
|
||||||
|
if (!(y = y.replace(/((formatting )?formatting-em|em) /g, "")).includes("formatting") && !/^\s*$/.test(U)) {
|
||||||
|
d = U.match(TN);
|
||||||
|
let oe = U.length - (d ? d[0].length : 0);
|
||||||
|
oe > 0 && (stream.backUp(oe),
|
||||||
|
re = !0)
|
||||||
|
}
|
||||||
|
if (re || (re = stream.eol()),
|
||||||
|
re || (re = !TN.test(stream.peek()!)),
|
||||||
|
re)
|
||||||
|
{
|
||||||
|
let le = stream.current();
|
||||||
|
y += " hashtag-end " + (le = "tag-" + le.replace(/[^_a-zA-Z0-9\-]/g, "")),
|
||||||
|
state.hmdHashtag = !1
|
||||||
|
}
|
||||||
|
} else if ("#" === U && !state.linkText && !state.image && (h || /^\s*$/.test(stream.string.charAt(stream.start - 1)))) {
|
||||||
|
let ae = stream.string.slice(stream.pos).replace(/\\./g, "")
|
||||||
|
, se = TN.exec(ae);
|
||||||
|
if (se && /[^0-9]/.test(se[0])) {
|
||||||
|
let le = "tag-" + se[0].replace(/[^_a-zA-Z0-9\-]/g, "");
|
||||||
|
state.hmdHashtag = !0,
|
||||||
|
y += " formatting formatting-hashtag hashtag-begin " + config.tokenTypeOverrides.hashtag + " " + le
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return y.trim() || null;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}, 'd-any');
|
||||||
Loading…
Reference in New Issue