diff --git a/services/web/app/src/Features/Project/ProjectController.js b/services/web/app/src/Features/Project/ProjectController.js
index e015d47871..4ec958f735 100644
--- a/services/web/app/src/Features/Project/ProjectController.js
+++ b/services/web/app/src/Features/Project/ProjectController.js
@@ -683,6 +683,21 @@ const ProjectController = {
cb()
})
},
+ sourceEditorToolbarAssigment(cb) {
+ SplitTestHandler.getAssignment(
+ req,
+ res,
+ 'source-editor-toolbar',
+ (error, assignment) => {
+ // do not fail editor load if assignment fails
+ if (error) {
+ cb(null, { variant: 'default' })
+ } else {
+ cb(null, assignment)
+ }
+ }
+ )
+ },
historyViewAssignment(cb) {
SplitTestHandler.getAssignment(
req,
@@ -729,6 +744,7 @@ const ProjectController = {
pdfjsAssignment,
editorLeftMenuAssignment,
richTextAssignment,
+ sourceEditorToolbarAssigment,
historyViewAssignment,
reviewPanelAssignment,
}
@@ -919,6 +935,9 @@ const ProjectController = {
pdfjsVariant: pdfjsAssignment.variant,
debugPdfDetach,
showLegacySourceEditor,
+ showSourceToolbar:
+ !showLegacySourceEditor &&
+ sourceEditorToolbarAssigment.variant === 'enabled',
showSymbolPalette,
galileoEnabled,
galileoFeatures,
diff --git a/services/web/app/views/project/editor/editor-pane.pug b/services/web/app/views/project/editor/editor-pane.pug
index d19dde250b..66fb1217c0 100644
--- a/services/web/app/views/project/editor/editor-pane.pug
+++ b/services/web/app/views/project/editor/editor-pane.pug
@@ -22,6 +22,7 @@
include ./file-view
.editor-container.full-size(
+ class={"has-source-toolbar" : showSourceToolbar},
ng-show="ui.view == 'editor' && editor.multiSelectedCount === 0"
vertical-resizable-panes="south-pane-resizer"
vertical-resizable-panes-hidden-externally-on="south-pane-toggled"
diff --git a/services/web/app/views/project/editor/meta.pug b/services/web/app/views/project/editor/meta.pug
index 68d14e5c10..15c5a6b433 100644
--- a/services/web/app/views/project/editor/meta.pug
+++ b/services/web/app/views/project/editor/meta.pug
@@ -22,6 +22,7 @@ meta(name="ol-wsRetryHandshake" data-type="json" content=settings.wsRetryHandsha
meta(name="ol-pdfjsVariant" content=pdfjsVariant)
meta(name="ol-debugPdfDetach" data-type="boolean" content=debugPdfDetach)
meta(name="ol-showLegacySourceEditor", data-type="boolean" content=showLegacySourceEditor)
+meta(name="ol-showSourceToolbar", data-type="boolean" content=showSourceToolbar)
meta(name="ol-showSymbolPalette" data-type="boolean" content=showSymbolPalette)
meta(name="ol-galileoEnabled" data-type="string" content=galileoEnabled)
meta(name="ol-galileoPromptWords" data-type="string" content=galileoPromptWords)
diff --git a/services/web/frontend/extracted-translations.json b/services/web/frontend/extracted-translations.json
index 560fbb5dd7..8a61400235 100644
--- a/services/web/frontend/extracted-translations.json
+++ b/services/web/frontend/extracted-translations.json
@@ -1016,6 +1016,7 @@
"toolbar_insert_figure": "",
"toolbar_insert_inline_math": "",
"toolbar_insert_link": "",
+ "toolbar_insert_math": "",
"toolbar_insert_table": "",
"toolbar_numbered_list": "",
"toolbar_redo": "",
diff --git a/services/web/frontend/js/features/source-editor/components/codemirror-toolbar.tsx b/services/web/frontend/js/features/source-editor/components/codemirror-toolbar.tsx
index cd566a2007..fb038297bf 100644
--- a/services/web/frontend/js/features/source-editor/components/codemirror-toolbar.tsx
+++ b/services/web/frontend/js/features/source-editor/components/codemirror-toolbar.tsx
@@ -13,6 +13,13 @@ import { ToolbarOverflow } from './toolbar/overflow'
import useDropdown from '../../../shared/hooks/use-dropdown'
import { getPanel } from '@codemirror/view'
import { createToolbarPanel } from '../extensions/toolbar/toolbar-panel'
+import EditorSwitch from './editor-switch'
+import SwitchToPDFButton from './switch-to-pdf-button'
+import { DetacherSynctexControl } from '../../pdf-preview/components/detach-synctex-control'
+import DetachCompileButtonWrapper from '../../pdf-preview/components/detach-compile-button-wrapper'
+import getMeta from '../../../utils/meta'
+import { isVisual } from '../extensions/visual/visual'
+import SplitTestBadge from '../../../shared/components/split-test-badge'
export const CodeMirrorToolbar = () => {
const view = useCodeMirrorViewContext()
@@ -26,7 +33,10 @@ export const CodeMirrorToolbar = () => {
}
const Toolbar = memo(function Toolbar() {
+ const showSourceToolbar: boolean = getMeta('ol-showSourceToolbar')
+
const state = useCodeMirrorStateContext()
+ const view = useCodeMirrorViewContext()
const [overflowed, setOverflowed] = useState(false)
const [collapsed, setCollapsed] = useState(false)
@@ -85,9 +95,13 @@ const Toolbar = memo(function Toolbar() {
}
return (
-
+
+ {showSourceToolbar &&
}
-
+
+ {!isVisual(view) && (
+
+ )}
+ {showSourceToolbar && (
+ <>
+
+
+
+ >
+ )}
+ Overleaf has upgraded the source editor. You can still use the old editor
+ by selecting "Source (legacy)".
+
+
+ Click to learn more and give feedback
+ >
+ )
+
+ return (
+
+
+ {content}
+
+
+ )
+}
+
+const showLegacySourceEditor: boolean = getMeta('ol-showLegacySourceEditor')
+const visualEditorNameVariant: string = getMeta('ol-visualEditorNameVariant')
+const isParticipatingInVisualEditorNamingTest: boolean = getMeta(
+ 'ol-isParticipatingInVisualEditorNamingTest'
+)
+
+function EditorSwitch() {
+ const [newSourceEditor, setNewSourceEditor] = useScopeValue(
+ 'editor.newSourceEditor'
+ )
+ const [richText, setRichText] = useScopeValue('editor.showRichText')
+ const sourceName =
+ visualEditorNameVariant === 'code-visual'
+ ? 'Code Editor'
+ : visualEditorNameVariant === 'source-visual'
+ ? 'Source Editor'
+ : 'Source'
+
+ const [visual, setVisual] = useScopeValue('editor.showVisual')
+
+ const [docName] = useScopeValue('editor.open_doc_name')
+ const richTextAvailable = isValidTeXFile(docName)
+ const richTextOrVisual = richText || (richTextAvailable && visual)
+
+ const handleChange = useCallback(
+ event => {
+ const editorType = event.target.value
+
+ switch (editorType) {
+ case 'ace':
+ setRichText(false)
+ setVisual(false)
+ setNewSourceEditor(false)
+ break
+
+ case 'cm6':
+ setRichText(false)
+ setVisual(false)
+ setNewSourceEditor(true)
+ break
+
+ case 'rich-text':
+ if (getMeta('ol-richTextVariant') === 'cm6') {
+ setRichText(false)
+ setVisual(true)
+ setNewSourceEditor(true)
+ } else {
+ setRichText(true)
+ setVisual(false)
+ }
+
+ break
+ }
+
+ sendMB('editor-switch-change', { editorType })
+ },
+ [setRichText, setVisual, setNewSourceEditor]
+ )
+
+ return (
+
+ {showLegacySourceEditor ? : null}
+
+
+
+ {!!richTextOrVisual && !isParticipatingInVisualEditorNamingTest && (
+
+ )}
+
+ )
+}
+
+const RichTextToggle: FC<{
+ checked: boolean
+ disabled: boolean
+ handleChange: (event: ChangeEvent) => void
+}> = ({ checked, disabled, handleChange }) => {
+ const { t } = useTranslation()
+
+ const richTextName =
+ visualEditorNameVariant === 'default' ? 'Rich Text' : 'Visual Editor'
+
+ const toggle = (
+
+
+
+
+ )
+
+ if (disabled) {
+ return (
+
+ {toggle}
+
+ )
+ }
+
+ return toggle
+}
+
+export default memo(EditorSwitch)
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 f168902d01..7eb052b781 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
@@ -7,41 +7,6 @@ import isValidTeXFile from '../../../main/is-valid-tex-file'
import { useTranslation } from 'react-i18next'
import SplitTestBadge from '../../../shared/components/split-test-badge'
-function Badge() {
- const content = (
- <>
- Overleaf has upgraded the source editor. You can still use the old editor
- by selecting "Source (legacy)".
-
-
- Click to learn more and give feedback
- >
- )
-
- return (
-
-
- {content}
-
-
- )
-}
-
-const showLegacySourceEditor: boolean = getMeta('ol-showLegacySourceEditor')
-
function EditorSwitch() {
const { t } = useTranslation()
const [newSourceEditor, setNewSourceEditor] = useScopeValue(
@@ -91,8 +56,6 @@ function EditorSwitch() {
return (
- {showLegacySourceEditor ?
: null}
-