Compare commits
14 Commits
Author | SHA1 | Date |
---|---|---|
zhengyi | 2600445d15 | |
zhengyi59 | 868aec124c | |
zhengyi | 1b482b5d9b | |
zhengyi | 8cab82fa52 | |
zhengyi | b8000377ac | |
justice2001 | ffaf19cf76 | |
Ryan Wang | fe1ba30230 | |
Ryan Wang | eb58dc8028 | |
zhengyi | 7757091b80 | |
zhengyi | d830c03d8b | |
zhengyi | 8c6cfc73d4 | |
zhengyi | c60381920c | |
zhengyi | f927bfb3d5 | |
zhengyi | 6bcf8f89f0 |
|
@ -64,7 +64,7 @@ jobs:
|
|||
name: plugin-starter
|
||||
path: |
|
||||
build/libs/*.jar
|
||||
retention-days: 1
|
||||
retention-days: 90
|
||||
|
||||
github-release:
|
||||
runs-on: debian-12
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
# 更新记录
|
||||
|
||||
### v1.7.0
|
||||
|
||||
- ⬆️ 调整 Halo 最低兼容版本为 `2.14.0`
|
||||
- ✨ 添加`使用第一个h1作为标题`的功能 #33
|
||||
- 🐛 修复代码块颜色异常的问题 #38
|
||||
|
||||
### v1.6.2
|
||||
|
||||
- ⬆️ 升级Vditor版本至3.10.2
|
||||
|
|
|
@ -1,5 +1,10 @@
|
|||
# halo-plugin-vditor
|
||||
|
||||
![](https://img.shields.io/badge/状态-稳定-red.svg)
|
||||
![](https://img.shields.io/badge/启动时间-2023/11/23-green.svg)
|
||||
![](https://img.shields.io/badge/优先级-HIGH-blue.svg)
|
||||
![GitHub Release](https://img.shields.io/github/v/release/justice2001/halo-plugin-vditor?color=yellow&label=版本)
|
||||
|
||||
本插件将Vditor整合进Halo,支持所见即所得编辑模式。 Support English (*Only Editor)!
|
||||
|
||||
编辑器支持数学公式、脑图、图表、流程图、甘特图、时序图、五线谱、graphviz 渲染、plantumlUML图
|
||||
|
@ -58,6 +63,8 @@
|
|||
|
||||
## 🙏 鸣谢
|
||||
|
||||
> 特别感谢来自 [Halo](https://github.com/halo-dev) 的投喂
|
||||
|
||||
> 特别感谢[Vditor](https://github.com/Vanessa219/vditor),本插件大部分内容均为此编辑器提供
|
||||
|
||||
* [Vditor](https://github.com/Vanessa219/vditor) 一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式。
|
||||
|
|
|
@ -41,7 +41,7 @@ build {
|
|||
}
|
||||
|
||||
halo {
|
||||
version = '2.12'
|
||||
version = '2.14'
|
||||
superAdminUsername = 'admin'
|
||||
superAdminPassword = 'admin'
|
||||
externalUrl = 'http://localhost:8090'
|
||||
|
|
|
@ -2,8 +2,9 @@
|
|||
<div id="vditor-debug-panel">
|
||||
<div id="vditor-debug-op" :class="{ active: debugOpOpen }">
|
||||
<div id="vditor-debug-op-bar" @click="debugOpOpen = !debugOpOpen">
|
||||
<img src="../assets/debug.svg" />
|
||||
<img src="../assets/debug.svg" alt="DEBUG"/>
|
||||
</div>
|
||||
<VButton type="primary" size="sm" @click="getRaw">Get Raw</VButton>
|
||||
<VButton type="primary" size="sm" @click="getHTML">Get HTML</VButton>
|
||||
<VButton type="primary" size="sm" @click="getRenderList">
|
||||
Get Vditor Options
|
||||
|
@ -36,6 +37,11 @@ const props = defineProps<{
|
|||
cursor: Range | undefined;
|
||||
}>();
|
||||
|
||||
const getRaw = () => {
|
||||
if (!props.vditor) return;
|
||||
console.log("RAW: ", props.vditor?.getValue());
|
||||
};
|
||||
|
||||
const getHTML = () => {
|
||||
if (!props.vditor) return;
|
||||
console.log("HTML", renderHTML(props.vditor));
|
||||
|
|
|
@ -7,6 +7,7 @@ export declare type EditorConfig = {
|
|||
enableQuickInsert: boolean;
|
||||
quickInsertUrl: [];
|
||||
disableHTMLBlockPreview: boolean;
|
||||
firstH1AsTitle: boolean;
|
||||
};
|
||||
extension: {
|
||||
allowImageType: string;
|
||||
|
@ -25,6 +26,7 @@ export const defaultEditorConfig: EditorConfig = {
|
|||
enableQuickInsert: false,
|
||||
quickInsertUrl: [],
|
||||
disableHTMLBlockPreview: false,
|
||||
firstH1AsTitle: false,
|
||||
},
|
||||
extension: {
|
||||
allowImageType: "png,jpg,jpeg,bmp,gif,webp,svg",
|
||||
|
|
|
@ -7,6 +7,7 @@ import drive from "@/schema/drive";
|
|||
import gallery from "@/schema/gallery";
|
||||
import { addScript, addStyleSheet } from "@/utils/dom-utils";
|
||||
import type Vditor from "vditor";
|
||||
import type {EditorConfig} from "@/utils/config-utils";
|
||||
|
||||
declare const HaloJs: {
|
||||
renderHalo: (content: string, cdn: string) => string;
|
||||
|
@ -233,11 +234,13 @@ function getCustomRenders(options: Options):
|
|||
* 进行自定义渲染器的后处理
|
||||
* TODO: 该部分建议加入Vditor
|
||||
* @param vditor vditor
|
||||
* @param config Editor Config
|
||||
* @returns html
|
||||
*/
|
||||
export function renderHTML(vditor: Vditor): string {
|
||||
export function renderHTML(vditor: Vditor, config: EditorConfig): string {
|
||||
let value = vditor.getHTML();
|
||||
const customRenders = vditor.vditor.options.customRenders;
|
||||
// FIXME 此部分逻辑有大问题!
|
||||
customRenders?.forEach((render) => {
|
||||
const reg = new RegExp(
|
||||
`<pre><code class="language-${render.language}">(.*?)</code></pre>`,
|
||||
|
@ -245,5 +248,10 @@ export function renderHTML(vditor: Vditor): string {
|
|||
);
|
||||
value = value.replace(reg, '<div class="language-halo">$1</div>');
|
||||
});
|
||||
// Remove H1 Title When start with "h1"
|
||||
if (config.basic.firstH1AsTitle && value.startsWith("<h1")) {
|
||||
value = value.replace(/<h1(?:\s+[^>]*)?>(.*?)<\/h1>/, "");
|
||||
console.log(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<script setup lang="ts">
|
||||
import Vditor from "vditor";
|
||||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
import { onMounted, onUnmounted, ref, watch } from "vue";
|
||||
import "vditor/dist/index.css";
|
||||
import type { Schema } from "@/type/editor";
|
||||
import { getOptions, renderHTML } from "@/utils/vditor-utils";
|
||||
|
@ -18,11 +18,13 @@ import DebugPanel from "@/model/DebugPanel.vue";
|
|||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
title?: string;
|
||||
raw?: string;
|
||||
content: string;
|
||||
uploadImage?: (file: File) => Promise<Attachment>;
|
||||
}>(),
|
||||
{
|
||||
title: "",
|
||||
raw: "",
|
||||
content: "",
|
||||
uploadImage: undefined,
|
||||
|
@ -45,17 +47,56 @@ const imageUploadLock = false;
|
|||
let allowImageUpload: string[] = [];
|
||||
// Debug
|
||||
const debugMode = ref<boolean>(false);
|
||||
// 防止内部标题更新触发updateContent
|
||||
const internalTitle = ref<string>("");
|
||||
|
||||
const emit = defineEmits<{
|
||||
(event: "update:raw", value: string): void;
|
||||
(event: "update:content", value: string): void;
|
||||
(event: "update", value: string): void;
|
||||
(event: "update:title", value: string): void;
|
||||
}>();
|
||||
|
||||
// Watch Title Change
|
||||
watch(
|
||||
() => props.title,
|
||||
(val) => {
|
||||
// When option disabled or nothing to update
|
||||
if (
|
||||
!editorConfig.value?.basic.firstH1AsTitle ||
|
||||
internalTitle.value === val
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Get title
|
||||
const vdiVal = vditor.value.getValue();
|
||||
if (vdiVal.startsWith("# ")) {
|
||||
internalTitle.value = val;
|
||||
vditor.value.setValue(vdiVal.replace(/# .*?\n/, `# ${val}\n`));
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Update content
|
||||
const debounceOnUpdate = () => {
|
||||
emit("update:raw", vditor.value.getValue());
|
||||
emit("update:content", renderHTML(vditor.value) || "");
|
||||
emit("update", vditor.value.getValue());
|
||||
// 解析标题
|
||||
let value = vditor.value.getValue();
|
||||
if (editorConfig.value?.basic.firstH1AsTitle && value.startsWith("# ")) {
|
||||
// First Line is Title
|
||||
const firstLine = value.match(/^.*/)[0];
|
||||
console.log(`title is ${firstLine.substring(2)}`);
|
||||
internalTitle.value = firstLine.substring(2);
|
||||
emit("update:title", internalTitle.value);
|
||||
// 删除第一行并清除空行
|
||||
value = value.substring(firstLine.length + 2);
|
||||
}
|
||||
// update content
|
||||
emit("update:raw", value);
|
||||
emit(
|
||||
"update:content",
|
||||
renderHTML(vditor.value, editorConfig.value || defaultEditorConfig) || ""
|
||||
);
|
||||
emit("update", value);
|
||||
};
|
||||
|
||||
// 选取附件后处理
|
||||
|
@ -124,7 +165,15 @@ onMounted(async () => {
|
|||
defaultRenderMode: editorConfig.value.basic.defaultRenderMode,
|
||||
typeWriterMode: editorConfig.value.basic.typeWriterMode,
|
||||
after: () => {
|
||||
vditor.value.setValue(props.raw || "# Title Here");
|
||||
let content = "";
|
||||
if (props.raw) {
|
||||
content = props.raw;
|
||||
}
|
||||
if (editorConfig.value?.basic.firstH1AsTitle) {
|
||||
internalTitle.value = props.title;
|
||||
content = `# ${props.title}\n\n` + content;
|
||||
}
|
||||
vditor.value.setValue(content);
|
||||
vditorLoaded.value = true;
|
||||
},
|
||||
input: debounceOnUpdate,
|
||||
|
@ -196,7 +245,10 @@ const update = (val: string | null) => {
|
|||
</script>
|
||||
|
||||
<template>
|
||||
<div id="plugin-vditor-mde">
|
||||
<div
|
||||
id="plugin-vditor-mde"
|
||||
:class="{ h1AsTitle: editorConfig?.basic.firstH1AsTitle }"
|
||||
>
|
||||
<VLoading v-if="!vditorLoaded" style="height: 100%" />
|
||||
<DebugPanel
|
||||
v-if="debugMode"
|
||||
|
@ -271,4 +323,30 @@ const update = (val: string | null) => {
|
|||
flex: 1;
|
||||
padding: 8px 10px;
|
||||
}
|
||||
|
||||
|
||||
/* title */
|
||||
#plugin-vditor-mde.h1AsTitle .vditor-ir h1:first-child::before,
|
||||
#plugin-vditor-mde.h1AsTitle .vditor-wysiwyg h1:first-child::before {
|
||||
content: "T";
|
||||
}
|
||||
|
||||
#plugin-vditor-mde.h1AsTitle .vditor-ir h1:first-child,
|
||||
#plugin-vditor-mde.h1AsTitle .vditor-wysiwyg h1:first-child {
|
||||
border-bottom: 2px solid #eaecef;
|
||||
color: #333333;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
font-size: 2rem;
|
||||
background: none;
|
||||
}
|
||||
|
||||
/**
|
||||
Fix compatible issues with docsme.
|
||||
https://github.com/justice2001/halo-plugin-vditor/issues/38
|
||||
*/
|
||||
#plugin-vditor-mde code[class*=language-],
|
||||
#plugin-vditor-mde pre[class*=language-] {
|
||||
color: #000000;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1 +1 @@
|
|||
version=1.6.2-SNAPSHOT
|
||||
version=1.6.3-SNAPSHOT
|
||||
|
|
|
@ -51,6 +51,11 @@ spec:
|
|||
label: 禁用HTML代码块隐藏
|
||||
help: 开启此选项后,HTML代码块将会一直显示
|
||||
value: false
|
||||
- $formkit: checkbox
|
||||
name: firstH1AsTitle
|
||||
label: 🧪自动将第一行作为标题
|
||||
help: 开启此选项后,第一行H1将会作为文章标题,同时标题会用 T 标识
|
||||
value: false
|
||||
- group: extension
|
||||
label: 文件格式
|
||||
formSchema:
|
||||
|
|
|
@ -1,22 +1,23 @@
|
|||
apiVersion: plugin.halo.run/v1alpha1
|
||||
kind: Plugin
|
||||
metadata:
|
||||
# The name defines how the plugin is invoked,A unique name
|
||||
name: vditor-mde
|
||||
annotations:
|
||||
store.halo.run/app-id: app-uBcYw
|
||||
spec:
|
||||
enabled: true
|
||||
requires: ">=2.11.0"
|
||||
requires: ">=2.14.0"
|
||||
author:
|
||||
name: zhengyi59
|
||||
website: https://github.com/justice2001/veditor-plugin
|
||||
website: https://github.com/justice2001/halo-plugin-vditor
|
||||
logo: vditor.png
|
||||
# 'homepage' usually links to the GitHub repository of the plugin
|
||||
homepage: https://github.com/justice2001/veditor-plugin
|
||||
# 'displayName' explains what the plugin does in only a few words
|
||||
homepage: https://www.halo.run/store/apps/app-uBcYw
|
||||
repo: https://github.com/justice2001/halo-plugin-vditor
|
||||
issues: https://github.com/justice2001/halo-plugin-vditor/issues
|
||||
settingName: vditor-mde-settings
|
||||
configMapName: vditor-mde-configMap
|
||||
displayName: "Vditor 编辑器"
|
||||
description: "适用于 Halo 的 Vditor 编辑器"
|
||||
license:
|
||||
- name: "GPL-3.0"
|
||||
url: "https://github.com/justice2001/veditor-plugin/blob/main/LICENSE"
|
||||
url: "https://github.com/justice2001/halo-plugin-vditor/blob/main/LICENSE"
|
||||
|
|
Loading…
Reference in New Issue