Complete multi-document mode

This commit is contained in:
2025-07-01 18:16:05 +08:00
parent 70d88dabba
commit 1604564e63
15 changed files with 1368 additions and 431 deletions

View File

@@ -1,39 +1,30 @@
<script setup lang="ts">
import {onBeforeUnmount, onMounted, ref} from 'vue';
import {useEditorStore} from '@/stores/editorStore';
import {useDocumentStore} from '@/stores/documentStore';
import {useConfigStore} from '@/stores/configStore';
import {createWheelZoomHandler} from './basic/wheelZoomExtension';
import Toolbar from '@/components/toolbar/Toolbar.vue';
const editorStore = useEditorStore();
const documentStore = useDocumentStore();
const configStore = useConfigStore();
const props = defineProps({
initialDoc: {
type: String,
default: ''
}
});
const editorElement = ref<HTMLElement | null>(null);
// 创建滚轮缩放处理器
const wheelHandler = createWheelZoomHandler(
configStore.increaseFontSize,
configStore.decreaseFontSize
configStore.increaseFontSize,
configStore.decreaseFontSize
);
onMounted(async () => {
if (!editorElement.value) return;
await documentStore.initialize();
// 设置编辑器容器
editorStore.setEditorContainer(editorElement.value);
// 如果编辑器还没有初始化,创建编辑器
if (!editorStore.isEditorInitialized) {
await editorStore.createEditor(props.initialDoc);
}
// 添加滚轮事件监听
editorElement.value.addEventListener('wheel', wheelHandler, {passive: false});
});
@@ -49,7 +40,7 @@ onBeforeUnmount(() => {
<template>
<div class="editor-container">
<div ref="editorElement" class="editor"></div>
<Toolbar />
<Toolbar/>
</div>
</template>

View File

@@ -1,109 +0,0 @@
import { EditorView, ViewPlugin, ViewUpdate } from '@codemirror/view';
import { useDocumentStore } from '@/stores/documentStore';
// 自动保存配置选项
export interface AutoSaveOptions {
// 防抖延迟(毫秒)
debounceDelay?: number;
// 保存状态回调
onSaveStart?: () => void;
onSaveSuccess?: () => void;
onSaveError?: () => void;
}
/**
* 简单防抖函数
*/
function debounce<T extends (...args: any[]) => any>(
func: T,
delay: number
): T & { cancel: () => void } {
let timeoutId: number | null = null;
const debounced = ((...args: Parameters<T>) => {
if (timeoutId !== null) {
clearTimeout(timeoutId);
}
timeoutId = window.setTimeout(() => {
timeoutId = null;
func(...args);
}, delay);
}) as T & { cancel: () => void };
debounced.cancel = () => {
if (timeoutId !== null) {
clearTimeout(timeoutId);
timeoutId = null;
}
};
return debounced;
}
/**
* 创建自动保存插件
*/
export function createAutoSavePlugin(options: AutoSaveOptions = {}) {
const {
debounceDelay = 2000,
onSaveStart = () => {},
onSaveSuccess = () => {},
onSaveError = () => {}
} = options;
return ViewPlugin.fromClass(
class AutoSavePlugin {
private documentStore = useDocumentStore();
private debouncedSave: ((content: string) => void) & { cancel: () => void };
private isDestroyed = false;
private lastContent = '';
constructor(private view: EditorView) {
this.lastContent = view.state.doc.toString();
this.debouncedSave = debounce(
(content: string) => this.performSave(content),
debounceDelay
);
}
private async performSave(content: string): Promise<void> {
if (this.isDestroyed) return;
try {
onSaveStart();
const success = await this.documentStore.saveDocumentContent(content);
if (success) {
this.lastContent = content;
onSaveSuccess();
} else {
onSaveError();
}
} catch (error) {
onSaveError();
}
}
update(update: ViewUpdate) {
if (!update.docChanged || this.isDestroyed) return;
const newContent = this.view.state.doc.toString();
if (newContent === this.lastContent) return;
this.debouncedSave(newContent);
}
destroy() {
this.isDestroyed = true;
this.debouncedSave.cancel();
// 如果内容有变化,立即保存
const currentContent = this.view.state.doc.toString();
if (currentContent !== this.lastContent) {
this.documentStore.saveDocumentContent(currentContent).catch(() => {});
}
}
}
);
}

View File

@@ -0,0 +1,39 @@
import { EditorView, ViewPlugin, ViewUpdate } from '@codemirror/view';
import { useDocumentStore } from '@/stores/documentStore';
import { useEditorStore } from '@/stores/editorStore';
/**
* 内容变化监听插件 - 集成文档和编辑器管理
*/
export function createContentChangePlugin() {
return ViewPlugin.fromClass(
class ContentChangePlugin {
private documentStore = useDocumentStore();
private editorStore = useEditorStore();
private lastContent = '';
constructor(private view: EditorView) {
this.lastContent = view.state.doc.toString();
}
update(update: ViewUpdate) {
if (!update.docChanged) return;
const newContent = this.view.state.doc.toString();
if (newContent === this.lastContent) return;
this.lastContent = newContent;
// 通知编辑器管理器内容已变化
const currentDocId = this.documentStore.currentDocumentId;
if (currentDocId) {
this.editorStore.onContentChange(currentDocId);
}
}
destroy() {
}
}
);
}