Merge pull request 'v1.7.0 Releases' (PR#81) from dev into main
Build Plugin JAR File / build (push) Successful in 2m11s Details
Build Plugin JAR File / github-release (push) Has been skipped Details

Reviewed-on: #81
This commit is contained in:
zhengyi 2024-05-10 12:56:57 +08:00
commit 1b482b5d9b
10 changed files with 117 additions and 12 deletions

View File

@ -64,7 +64,7 @@ jobs:
name: plugin-starter name: plugin-starter
path: | path: |
build/libs/*.jar build/libs/*.jar
retention-days: 1 retention-days: 90
github-release: github-release:
runs-on: debian-12 runs-on: debian-12

View File

@ -1,5 +1,11 @@
# 更新记录 # 更新记录
### v1.7.0
- ⬆️ 调整 Halo 最低兼容版本为 `2.14.0`
- ✨ 添加`使用第一个h1作为标题`的功能 #33
- 🐛 修复代码块颜色异常的问题 #38
### v1.6.2 ### v1.6.2
- ⬆️ 升级Vditor版本至3.10.2 - ⬆️ 升级Vditor版本至3.10.2

View File

@ -41,7 +41,7 @@ build {
} }
halo { halo {
version = '2.12' version = '2.14'
superAdminUsername = 'admin' superAdminUsername = 'admin'
superAdminPassword = 'admin' superAdminPassword = 'admin'
externalUrl = 'http://localhost:8090' externalUrl = 'http://localhost:8090'

View File

@ -2,8 +2,9 @@
<div id="vditor-debug-panel"> <div id="vditor-debug-panel">
<div id="vditor-debug-op" :class="{ active: debugOpOpen }"> <div id="vditor-debug-op" :class="{ active: debugOpOpen }">
<div id="vditor-debug-op-bar" @click="debugOpOpen = !debugOpOpen"> <div id="vditor-debug-op-bar" @click="debugOpOpen = !debugOpOpen">
<img src="../assets/debug.svg" /> <img src="../assets/debug.svg" alt="DEBUG"/>
</div> </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="getHTML">Get HTML</VButton>
<VButton type="primary" size="sm" @click="getRenderList"> <VButton type="primary" size="sm" @click="getRenderList">
Get Vditor Options Get Vditor Options
@ -36,6 +37,11 @@ const props = defineProps<{
cursor: Range | undefined; cursor: Range | undefined;
}>(); }>();
const getRaw = () => {
if (!props.vditor) return;
console.log("RAW: ", props.vditor?.getValue());
};
const getHTML = () => { const getHTML = () => {
if (!props.vditor) return; if (!props.vditor) return;
console.log("HTML", renderHTML(props.vditor)); console.log("HTML", renderHTML(props.vditor));

View File

@ -7,6 +7,7 @@ export declare type EditorConfig = {
enableQuickInsert: boolean; enableQuickInsert: boolean;
quickInsertUrl: []; quickInsertUrl: [];
disableHTMLBlockPreview: boolean; disableHTMLBlockPreview: boolean;
firstH1AsTitle: boolean;
}; };
extension: { extension: {
allowImageType: string; allowImageType: string;
@ -25,6 +26,7 @@ export const defaultEditorConfig: EditorConfig = {
enableQuickInsert: false, enableQuickInsert: false,
quickInsertUrl: [], quickInsertUrl: [],
disableHTMLBlockPreview: false, disableHTMLBlockPreview: false,
firstH1AsTitle: false,
}, },
extension: { extension: {
allowImageType: "png,jpg,jpeg,bmp,gif,webp,svg", allowImageType: "png,jpg,jpeg,bmp,gif,webp,svg",

View File

@ -7,6 +7,7 @@ import drive from "@/schema/drive";
import gallery from "@/schema/gallery"; import gallery from "@/schema/gallery";
import { addScript, addStyleSheet } from "@/utils/dom-utils"; import { addScript, addStyleSheet } from "@/utils/dom-utils";
import type Vditor from "vditor"; import type Vditor from "vditor";
import type {EditorConfig} from "@/utils/config-utils";
declare const HaloJs: { declare const HaloJs: {
renderHalo: (content: string, cdn: string) => string; renderHalo: (content: string, cdn: string) => string;
@ -233,11 +234,13 @@ function getCustomRenders(options: Options):
* *
* TODO: 该部分建议加入Vditor * TODO: 该部分建议加入Vditor
* @param vditor vditor * @param vditor vditor
* @param config Editor Config
* @returns html * @returns html
*/ */
export function renderHTML(vditor: Vditor): string { export function renderHTML(vditor: Vditor, config: EditorConfig): string {
let value = vditor.getHTML(); let value = vditor.getHTML();
const customRenders = vditor.vditor.options.customRenders; const customRenders = vditor.vditor.options.customRenders;
// FIXME 此部分逻辑有大问题!
customRenders?.forEach((render) => { customRenders?.forEach((render) => {
const reg = new RegExp( const reg = new RegExp(
`<pre><code class="language-${render.language}">(.*?)</code></pre>`, `<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>'); 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; return value;
} }

View File

@ -1,6 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import Vditor from "vditor"; import Vditor from "vditor";
import { onMounted, onUnmounted, ref } from "vue"; import { onMounted, onUnmounted, ref, watch } from "vue";
import "vditor/dist/index.css"; import "vditor/dist/index.css";
import type { Schema } from "@/type/editor"; import type { Schema } from "@/type/editor";
import { getOptions, renderHTML } from "@/utils/vditor-utils"; import { getOptions, renderHTML } from "@/utils/vditor-utils";
@ -18,11 +18,13 @@ import DebugPanel from "@/model/DebugPanel.vue";
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
title?: string;
raw?: string; raw?: string;
content: string; content: string;
uploadImage?: (file: File) => Promise<Attachment>; uploadImage?: (file: File) => Promise<Attachment>;
}>(), }>(),
{ {
title: "",
raw: "", raw: "",
content: "", content: "",
uploadImage: undefined, uploadImage: undefined,
@ -45,17 +47,56 @@ const imageUploadLock = false;
let allowImageUpload: string[] = []; let allowImageUpload: string[] = [];
// Debug // Debug
const debugMode = ref<boolean>(false); const debugMode = ref<boolean>(false);
// updateContent
const internalTitle = ref<string>("");
const emit = defineEmits<{ const emit = defineEmits<{
(event: "update:raw", value: string): void; (event: "update:raw", value: string): void;
(event: "update:content", value: string): void; (event: "update:content", value: string): void;
(event: "update", 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 = () => { const debounceOnUpdate = () => {
emit("update:raw", vditor.value.getValue()); //
emit("update:content", renderHTML(vditor.value) || ""); let value = vditor.value.getValue();
emit("update", 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, defaultRenderMode: editorConfig.value.basic.defaultRenderMode,
typeWriterMode: editorConfig.value.basic.typeWriterMode, typeWriterMode: editorConfig.value.basic.typeWriterMode,
after: () => { 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; vditorLoaded.value = true;
}, },
input: debounceOnUpdate, input: debounceOnUpdate,
@ -196,7 +245,10 @@ const update = (val: string | null) => {
</script> </script>
<template> <template>
<div id="plugin-vditor-mde"> <div
id="plugin-vditor-mde"
:class="{ h1AsTitle: editorConfig?.basic.firstH1AsTitle }"
>
<VLoading v-if="!vditorLoaded" style="height: 100%" /> <VLoading v-if="!vditorLoaded" style="height: 100%" />
<DebugPanel <DebugPanel
v-if="debugMode" v-if="debugMode"
@ -271,4 +323,30 @@ const update = (val: string | null) => {
flex: 1; flex: 1;
padding: 8px 10px; 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> </style>

View File

@ -1 +1 @@
version=1.6.2-SNAPSHOT version=1.6.3-SNAPSHOT

View File

@ -51,6 +51,11 @@ spec:
label: 禁用HTML代码块隐藏 label: 禁用HTML代码块隐藏
help: 开启此选项后HTML代码块将会一直显示 help: 开启此选项后HTML代码块将会一直显示
value: false value: false
- $formkit: checkbox
name: firstH1AsTitle
label: 🧪自动将第一行作为标题
help: 开启此选项后第一行H1将会作为文章标题同时标题会用 T 标识
value: false
- group: extension - group: extension
label: 文件格式 label: 文件格式
formSchema: formSchema:

View File

@ -6,7 +6,7 @@ metadata:
store.halo.run/app-id: app-uBcYw store.halo.run/app-id: app-uBcYw
spec: spec:
enabled: true enabled: true
requires: ">=2.11.0" requires: ">=2.14.0"
author: author:
name: zhengyi59 name: zhengyi59
website: https://github.com/justice2001/halo-plugin-vditor website: https://github.com/justice2001/halo-plugin-vditor