update
This commit is contained in:
@@ -0,0 +1,124 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="editorRef" class="codemirror-mobile-editor-container"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onBeforeUnmount, watch, shallowRef } from 'vue';
|
||||||
|
import { EditorState, Compartment } from '@codemirror/state';
|
||||||
|
import { EditorView, keymap } from '@codemirror/view';
|
||||||
|
import { basicSetup } from 'codemirror'; // Use basicSetup from the main 'codemirror' package
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: String,
|
||||||
|
default: '',
|
||||||
|
},
|
||||||
|
language: {
|
||||||
|
type: String,
|
||||||
|
default: 'plaintext', // Default to plaintext if no language is specified
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(['update:modelValue', 'request-save']);
|
||||||
|
|
||||||
|
const editorRef = ref<HTMLDivElement | null>(null);
|
||||||
|
const view = shallowRef<EditorView | null>(null);
|
||||||
|
const languageCompartment = new Compartment(); // For dynamic language switching
|
||||||
|
|
||||||
|
const createEditorState = (doc: string, languageExtension: any) => {
|
||||||
|
return EditorState.create({
|
||||||
|
doc,
|
||||||
|
extensions: [
|
||||||
|
basicSetup, // Includes many common features like line numbers, history, default keymaps etc.
|
||||||
|
keymap.of([
|
||||||
|
{ key: "Mod-s", run: () => { emit('request-save'); return true; } }
|
||||||
|
]),
|
||||||
|
EditorView.updateListener.of((update) => {
|
||||||
|
if (update.docChanged) {
|
||||||
|
emit('update:modelValue', update.state.doc.toString());
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
languageCompartment.of(languageExtension), // Initial language
|
||||||
|
],
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const getLanguageExtension = async (lang: string) => {
|
||||||
|
if (lang === 'javascript') {
|
||||||
|
const { javascript } = await import('@codemirror/lang-javascript');
|
||||||
|
return javascript();
|
||||||
|
}
|
||||||
|
if (lang === 'css') {
|
||||||
|
const { css } = await import('@codemirror/lang-css');
|
||||||
|
return css();
|
||||||
|
}
|
||||||
|
if (lang === 'html') {
|
||||||
|
const { html } = await import('@codemirror/lang-html');
|
||||||
|
return html();
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
if (editorRef.value) {
|
||||||
|
const langExt = await getLanguageExtension(props.language);
|
||||||
|
const startState = createEditorState(props.modelValue, langExt);
|
||||||
|
|
||||||
|
view.value = new EditorView({
|
||||||
|
state: startState,
|
||||||
|
parent: editorRef.value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
if (view.value) {
|
||||||
|
view.value.destroy();
|
||||||
|
view.value = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => props.modelValue, (newValue) => {
|
||||||
|
if (view.value && newValue !== view.value.state.doc.toString()) {
|
||||||
|
view.value.dispatch({
|
||||||
|
changes: { from: 0, to: view.value.state.doc.length, insert: newValue },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
watch(() => props.language, async (newLanguage, oldLanguage) => {
|
||||||
|
if (view.value && newLanguage !== oldLanguage) {
|
||||||
|
console.log(`Language changing from ${oldLanguage} to: ${newLanguage}.`);
|
||||||
|
const langExt = await getLanguageExtension(newLanguage);
|
||||||
|
view.value.dispatch({
|
||||||
|
effects: languageCompartment.reconfigure(langExt)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
focus: () => view.value?.focus(),
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.codemirror-mobile-editor-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 200px; /* Adjust as needed for mobile */
|
||||||
|
text-align: left;
|
||||||
|
overflow: auto; /* Enable both horizontal and vertical scrolling */
|
||||||
|
}
|
||||||
|
|
||||||
|
.codemirror-mobile-editor-container :deep(.cm-gutters) {
|
||||||
|
background-color: #1E1E1E !important; /* Match typical dark editor background */
|
||||||
|
color: #858585 !important; /* Ensure line numbers are visible */
|
||||||
|
border-right: 1px solid var(--border-color, #cccccc) !important; /* Use theme border color */
|
||||||
|
}
|
||||||
|
|
||||||
|
.codemirror-mobile-editor-container :deep(.cm-selectionBackground) {
|
||||||
|
background-color: #5264ac !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -3,6 +3,7 @@ import { computed, ref, onMounted, onBeforeUnmount, watch, nextTick } from 'vue'
|
|||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { storeToRefs } from 'pinia';
|
import { storeToRefs } from 'pinia';
|
||||||
import MonacoEditor from './MonacoEditor.vue';
|
import MonacoEditor from './MonacoEditor.vue';
|
||||||
|
import CodeMirrorMobileEditor from './CodeMirrorMobileEditor.vue'; // +++ Import new mobile editor
|
||||||
import FileEditorTabs from './FileEditorTabs.vue';
|
import FileEditorTabs from './FileEditorTabs.vue';
|
||||||
import { useFileEditorStore, type FileTab } from '../stores/fileEditor.store';
|
import { useFileEditorStore, type FileTab } from '../stores/fileEditor.store';
|
||||||
import { useSettingsStore } from '../stores/settings.store';
|
import { useSettingsStore } from '../stores/settings.store';
|
||||||
@@ -575,9 +576,11 @@ onBeforeUnmount(() => {
|
|||||||
<div class="editor-content-area">
|
<div class="editor-content-area">
|
||||||
<div v-if="currentTabIsLoading" class="editor-loading">{{ t('fileManager.loadingFile') }}</div>
|
<div v-if="currentTabIsLoading" class="editor-loading">{{ t('fileManager.loadingFile') }}</div>
|
||||||
<div v-else-if="currentTabLoadingError" class="editor-error">{{ currentTabLoadingError }}</div>
|
<div v-else-if="currentTabLoadingError" class="editor-error">{{ currentTabLoadingError }}</div>
|
||||||
|
|
||||||
|
<!-- Desktop Editor -->
|
||||||
<MonacoEditor
|
<MonacoEditor
|
||||||
v-else-if="activeTab"
|
v-else-if="activeTab && !props.isMobile"
|
||||||
:key="activeTab.id"
|
:key="`monaco-${activeTab.id}`"
|
||||||
v-model="activeEditorContent"
|
v-model="activeEditorContent"
|
||||||
:language="currentTabLanguage"
|
:language="currentTabLanguage"
|
||||||
:font-family="currentEditorFontFamily"
|
:font-family="currentEditorFontFamily"
|
||||||
@@ -586,9 +589,18 @@ onBeforeUnmount(() => {
|
|||||||
:font-size="currentEditorFontSize"
|
:font-size="currentEditorFontSize"
|
||||||
@request-save="handleSaveRequest"
|
@request-save="handleSaveRequest"
|
||||||
@update:fontSize="handleEditorFontSizeUpdate"
|
@update:fontSize="handleEditorFontSizeUpdate"
|
||||||
:initialScrollTop="activeTab?.scrollTop ?? 0"
|
:initialScrollTop="activeTab?.scrollTop ?? 0"
|
||||||
:initialScrollLeft="activeTab?.scrollLeft ?? 0"
|
:initialScrollLeft="activeTab?.scrollLeft ?? 0"
|
||||||
@update:scrollPosition="handleEditorScroll"
|
@update:scrollPosition="handleEditorScroll"
|
||||||
|
/>
|
||||||
|
<!-- Mobile Editor -->
|
||||||
|
<CodeMirrorMobileEditor
|
||||||
|
v-else-if="activeTab && props.isMobile"
|
||||||
|
:key="`cm-${activeTab.id}`"
|
||||||
|
v-model="activeEditorContent"
|
||||||
|
:language="currentTabLanguage"
|
||||||
|
class="editor-instance"
|
||||||
|
@request-save="handleSaveRequest"
|
||||||
/>
|
/>
|
||||||
<!-- 如果容器可见但没有活动标签页 -->
|
<!-- 如果容器可见但没有活动标签页 -->
|
||||||
<div v-else class="editor-placeholder">{{ t('fileManager.selectFileToEdit') }}</div>
|
<div v-else class="editor-placeholder">{{ t('fileManager.selectFileToEdit') }}</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user