diff --git a/services/web/app/src/Features/Project/ProjectController.mjs b/services/web/app/src/Features/Project/ProjectController.mjs index 7fe87efe1c..1a285feae7 100644 --- a/services/web/app/src/Features/Project/ProjectController.mjs +++ b/services/web/app/src/Features/Project/ProjectController.mjs @@ -486,6 +486,7 @@ const _ProjectController = { 'command-palette', 'overleaf-library', 'compile-timeout-cta', + 'markdown-visual', ].filter(Boolean) const getUserValues = async userId => diff --git a/services/web/config/settings.defaults.js b/services/web/config/settings.defaults.js index aa5c10965a..28746a2b74 100644 --- a/services/web/config/settings.defaults.js +++ b/services/web/config/settings.defaults.js @@ -1027,6 +1027,7 @@ module.exports = { tprFileViewNotOriginalImporter: [], contactUsModal: [], sourceEditorExtensions: [], + sourceEditorVisualExtensions: [], sourceEditorComponents: [], pdfLogEntryHeaderActionComponents: [], pdfLogEntryComponents: [], diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json index be2b05a1fc..73b7e40b72 100644 --- a/services/web/frontend/extracted-translations.json +++ b/services/web/frontend/extracted-translations.json @@ -2350,7 +2350,7 @@ "viewing": "", "viewing_x": "", "visual": "", - "visual_editor_is_only_available_for_tex_files": "", + "visual_editor_does_not_support_this_file_type": "", "want_change_to_apply_before_plan_end": "", "warnings": "", "we_are_unable_to_opt_you_into_this_experiment": "", diff --git a/services/web/frontend/js/features/source-editor/components/editor-switch.tsx b/services/web/frontend/js/features/source-editor/components/editor-switch.tsx index 5fa3dd0c6a..c64bfb701d 100644 --- a/services/web/frontend/js/features/source-editor/components/editor-switch.tsx +++ b/services/web/frontend/js/features/source-editor/components/editor-switch.tsx @@ -100,7 +100,7 @@ const RichTextToggle: FC<{ if (disabled) { return ( PreviewPath | null } +// Language-specific visual editor extensions provided by modules (e.g. the +// markdown visual editor). They live in the visual bundle so they are only +// active in visual mode and react to switching editor modes. +const visualEditorExtensions: Array<(options: Options) => Extension> = + importOverleafModules('sourceEditorVisualExtensions').map( + (item: { import: { extension: (options: Options) => Extension } }) => + item.import.extension + ) + const visualConf = new Compartment() export const toggleVisualEffect = StateEffect.define() @@ -171,6 +181,7 @@ const extension = (options: Options) => [ mousedown, listItemMarker, atomicDecorations(options), + visualEditorExtensions.map(extension => extension(options)), markDecorations, // NOTE: must be after atomicDecorations, so that mark decorations wrap inline widgets visualKeymap, commandTooltip, diff --git a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts index e9fa66935e..c6f3ca2441 100644 --- a/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts +++ b/services/web/frontend/js/features/source-editor/hooks/use-codemirror-scope.ts @@ -63,7 +63,7 @@ import { useActiveOverallTheme } from '@/shared/hooks/use-active-overall-theme' import { useEditorSelectionContext } from '@/shared/context/editor-selection-context' import { useActiveEditorTheme } from '@/shared/hooks/use-active-editor-theme' import { useFeatureFlag } from '@/shared/context/split-test-context' -import { isValidTeXFile } from '@/main/is-valid-tex-file' +import { isCmVisualEditorAvailable } from '../utils/visual-editor' function useCodeMirrorScope(view: EditorView) { const { fileTreeData } = useFileTreeData() @@ -277,7 +277,8 @@ function useCodeMirrorScope(view: EditorView) { const { previewByPath } = useFileTreePathContext() - const showVisual = visual && !!openDocName && isValidTeXFile(openDocName) + const showVisual = + visual && !!openDocName && isCmVisualEditorAvailable(openDocName) const visualRef = useRef({ previewByPath, diff --git a/services/web/frontend/js/features/source-editor/utils/visual-editor.ts b/services/web/frontend/js/features/source-editor/utils/visual-editor.ts index 17fdf4fde1..87e49a57be 100644 --- a/services/web/frontend/js/features/source-editor/utils/visual-editor.ts +++ b/services/web/frontend/js/features/source-editor/utils/visual-editor.ts @@ -2,13 +2,37 @@ import importOverleafModules from '../../../../macros/import-overleaf-module.mac import { isValidTeXFile } from '../../../main/is-valid-tex-file' const visualEditorProviders = importOverleafModules('visualEditorProviders') +const cmVisualEditorProviders = importOverleafModules( + 'sourceEditorVisualExtensions' +) -export function isVisualEditorAvailable(filename: string): boolean { - // Core LaTeX visual editor +/** + * This currently covers LaTeX and Markdown. Other file + * types (e.g. .bib) use module-provided visual editors that render their own + * component instead, so they must NOT enable the CodeMirror visual extensions. + */ +export function isCmVisualEditorAvailable(filename: string): boolean { if (isValidTeXFile(filename)) { return true } + for (const provider of cmVisualEditorProviders) { + if (provider.import.isCmVisualEditorFile?.(filename)) { + return true + } + } + return false +} + +/** + * Whether any visual editor exists for the file, including module-provided + * ones. Drives the editor toggle UI and the default editor mode for a file. + */ +export function isVisualEditorAvailable(filename: string): boolean { + if (isCmVisualEditorAvailable(filename)) { + return true + } + // Visual editors provided by modules for (const provider of visualEditorProviders) { if (provider.import.isVisualEditorAvailable(filename)) { diff --git a/services/web/locales/da.json b/services/web/locales/da.json index 8044e5668e..cc848df0b5 100644 --- a/services/web/locales/da.json +++ b/services/web/locales/da.json @@ -2039,7 +2039,6 @@ "viewer": "Læser", "viewing_x": "Ser <0>__endTime__", "visual_editor": "Visuel editor", - "visual_editor_is_only_available_for_tex_files": "Den visuelle editor er kun tilgængelig for TeX filer", "want_access_to_overleaf_premium_features_through_your_university": "Vil du have adgang til __appName__ Premium-funktioner gennem dit universitet?", "want_change_to_apply_before_plan_end": "Hvis du ønsker at denne ændring skal tage effekt før slutningen på din nuværende faktureringsperiode, kontakt os venligst.", "we_are_unable_to_opt_you_into_this_experiment": "Vi kan ikke melde dig til dette eksperiment lige nu. Tjek venligst at din organisation tillader denne funktion, eller prøv igen senere.", diff --git a/services/web/locales/en.json b/services/web/locales/en.json index 64972f09e1..24acee42e8 100644 --- a/services/web/locales/en.json +++ b/services/web/locales/en.json @@ -2999,7 +2999,7 @@ "viewing": "Viewing", "viewing_x": "Viewing <0>__endTime__", "visual": "Visual", - "visual_editor_is_only_available_for_tex_files": "Visual Editor is only available for TeX files", + "visual_editor_does_not_support_this_file_type": "Visual Editor doesn’t support this file type", "want_access_to_overleaf_premium_features_through_your_university": "Want access to __appName__ premium features through your university?", "want_change_to_apply_before_plan_end": "If you wish this change to apply before the end of your current billing period, please contact us.", "warnings": "Warnings", diff --git a/services/web/locales/zh-CN.json b/services/web/locales/zh-CN.json index 0234e9037f..57d076fc67 100644 --- a/services/web/locales/zh-CN.json +++ b/services/web/locales/zh-CN.json @@ -2369,7 +2369,6 @@ "viewing": "视图", "viewing_x": "正在查看<0>__endTime__", "visual_editor": "可视化编辑器", - "visual_editor_is_only_available_for_tex_files": "可视化编辑器仅适用于 TeX 文件", "want_access_to_overleaf_premium_features_through_your_university": "想要通过您的大学访问__appName__高级功能吗?", "want_change_to_apply_before_plan_end": "如果您希望在当前计费周期结束前应用此更改,请与我们联系。", "we_are_unable_to_opt_you_into_this_experiment": "目前我们无法让您加入此实验,请确保您的组织已允许此功能,或稍后重试。",