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 { storeToRefs } from 'pinia';
|
||||
import MonacoEditor from './MonacoEditor.vue';
|
||||
import CodeMirrorMobileEditor from './CodeMirrorMobileEditor.vue'; // +++ Import new mobile editor
|
||||
import FileEditorTabs from './FileEditorTabs.vue';
|
||||
import { useFileEditorStore, type FileTab } from '../stores/fileEditor.store';
|
||||
import { useSettingsStore } from '../stores/settings.store';
|
||||
@@ -575,9 +576,11 @@ onBeforeUnmount(() => {
|
||||
<div class="editor-content-area">
|
||||
<div v-if="currentTabIsLoading" class="editor-loading">{{ t('fileManager.loadingFile') }}</div>
|
||||
<div v-else-if="currentTabLoadingError" class="editor-error">{{ currentTabLoadingError }}</div>
|
||||
|
||||
<!-- Desktop Editor -->
|
||||
<MonacoEditor
|
||||
v-else-if="activeTab"
|
||||
:key="activeTab.id"
|
||||
v-else-if="activeTab && !props.isMobile"
|
||||
:key="`monaco-${activeTab.id}`"
|
||||
v-model="activeEditorContent"
|
||||
:language="currentTabLanguage"
|
||||
:font-family="currentEditorFontFamily"
|
||||
@@ -586,9 +589,18 @@ onBeforeUnmount(() => {
|
||||
:font-size="currentEditorFontSize"
|
||||
@request-save="handleSaveRequest"
|
||||
@update:fontSize="handleEditorFontSizeUpdate"
|
||||
:initialScrollTop="activeTab?.scrollTop ?? 0"
|
||||
:initialScrollLeft="activeTab?.scrollLeft ?? 0"
|
||||
@update:scrollPosition="handleEditorScroll"
|
||||
:initialScrollTop="activeTab?.scrollTop ?? 0"
|
||||
:initialScrollLeft="activeTab?.scrollLeft ?? 0"
|
||||
@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>
|
||||
|
||||
Reference in New Issue
Block a user