mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
Remove CM5 Rich Text module (#11776)
GitOrigin-RevId: 812d3b5f1df7e769c8be732ccb31653e8e9a8aa3
This commit is contained in:
parent
379ead7431
commit
c8f0885316
37 changed files with 129 additions and 587 deletions
12
package-lock.json
generated
12
package-lock.json
generated
|
@ -20065,11 +20065,6 @@
|
|||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/codemirror": {
|
||||
"version": "5.33.0",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.33.0.tgz",
|
||||
"integrity": "sha512-HT6PKVqkwpzwB3jl5hXFoQteEWXbSWMzG3Z8RVYlx8hZwCOLCy4NU7vkSB3dYX3e6ORwRfGw4uFOXaw4rn/a9Q=="
|
||||
},
|
||||
"node_modules/coffee-script": {
|
||||
"version": "1.12.7",
|
||||
"resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz",
|
||||
|
@ -45222,7 +45217,6 @@
|
|||
"chartjs-adapter-moment": "^1.0.1",
|
||||
"chartjs-plugin-datalabels": "^2.2.0",
|
||||
"classnames": "^2.2.6",
|
||||
"codemirror": "~5.33.0",
|
||||
"connect-redis": "^6.1.3",
|
||||
"content-disposition": "^0.5.0",
|
||||
"contentful": "^6.1.1",
|
||||
|
@ -54014,7 +54008,6 @@
|
|||
"chartjs-plugin-datalabels": "^2.2.0",
|
||||
"cheerio": "^1.0.0-rc.3",
|
||||
"classnames": "^2.2.6",
|
||||
"codemirror": "~5.33.0",
|
||||
"connect-redis": "^6.1.3",
|
||||
"content-disposition": "^0.5.0",
|
||||
"contentful": "^6.1.1",
|
||||
|
@ -63599,11 +63592,6 @@
|
|||
"resolved": "https://registry.npmjs.org/co-use/-/co-use-1.1.0.tgz",
|
||||
"integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI="
|
||||
},
|
||||
"codemirror": {
|
||||
"version": "5.33.0",
|
||||
"resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.33.0.tgz",
|
||||
"integrity": "sha512-HT6PKVqkwpzwB3jl5hXFoQteEWXbSWMzG3Z8RVYlx8hZwCOLCy4NU7vkSB3dYX3e6ORwRfGw4uFOXaw4rn/a9Q=="
|
||||
},
|
||||
"coffee-script": {
|
||||
"version": "1.12.7",
|
||||
"resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz",
|
||||
|
|
|
@ -662,6 +662,7 @@ const ProjectController = {
|
|||
}
|
||||
)
|
||||
},
|
||||
// this is only needed until the survey link is removed from the toolbar
|
||||
richTextAssignment(cb) {
|
||||
SplitTestHandler.getAssignment(
|
||||
req,
|
||||
|
@ -755,7 +756,6 @@ const ProjectController = {
|
|||
brandVariation,
|
||||
pdfjsAssignment,
|
||||
editorLeftMenuAssignment,
|
||||
richTextAssignment,
|
||||
sourceEditorToolbarAssigment,
|
||||
historyViewAssignment,
|
||||
reviewPanelAssignment,
|
||||
|
@ -880,13 +880,6 @@ const ProjectController = {
|
|||
? 'project/editor_detached'
|
||||
: 'project/editor'
|
||||
|
||||
let richTextVariant
|
||||
if (!Features.hasFeature('saas')) {
|
||||
richTextVariant = 'cm6'
|
||||
} else {
|
||||
richTextVariant = richTextAssignment.variant
|
||||
}
|
||||
|
||||
res.render(template, {
|
||||
title: project.name,
|
||||
priority_title: true,
|
||||
|
@ -961,7 +954,6 @@ const ProjectController = {
|
|||
fixedSizeDocument: true,
|
||||
useOpenTelemetry: Settings.useOpenTelemetryClient,
|
||||
showCM6SwitchAwaySurvey: Settings.showCM6SwitchAwaySurvey,
|
||||
richTextVariant,
|
||||
historyViewReact: historyViewAssignment.variant === 'react',
|
||||
isReviewPanelReact: reviewPanelAssignment.variant === 'react',
|
||||
showPersonalAccessToken,
|
||||
|
|
|
@ -124,7 +124,5 @@ block foot-scripts
|
|||
each file in (useOpenTelemetry ? entrypointScripts("tracing") : [])
|
||||
script(type="text/javascript", nonce=scriptNonce, src=file)
|
||||
script(type="text/javascript", nonce=scriptNonce, src=(wsUrl || '/socket.io') + '/socket.io.js')
|
||||
if (richTextVariant !== 'cm6')
|
||||
script(type="text/javascript", nonce=scriptNonce, src=mathJaxPath)
|
||||
each file in entrypointScripts("ide")
|
||||
script(type="text/javascript", nonce=scriptNonce, src=file)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
.ui-layout-center(
|
||||
ng-controller="ReviewPanelController",
|
||||
ng-class="{\
|
||||
'rp-unsupported': editor.showRichText,\
|
||||
'rp-state-current-file': (reviewPanel.subView === SubViews.CUR_FILE),\
|
||||
'rp-state-current-file-expanded': (reviewPanel.subView === SubViews.CUR_FILE && ui.reviewPanelOpen),\
|
||||
'rp-state-current-file-mini': (reviewPanel.subView === SubViews.CUR_FILE && !ui.reviewPanelOpen),\
|
||||
|
@ -36,7 +35,6 @@
|
|||
|
||||
.loading-panel(
|
||||
ng-show="(!editor.sharejs_doc || editor.opening) && !editor.error_state",
|
||||
style=showRichText ? "top: 32px" : "",
|
||||
)
|
||||
span(ng-show="editor.open_doc_id")
|
||||
i.fa.fa-spin.fa-refresh
|
||||
|
@ -45,10 +43,9 @@
|
|||
i.fa.fa-arrow-left
|
||||
| #{translate("open_a_file_on_the_left")}
|
||||
|
||||
if moduleIncludesAvailable('editor:main')
|
||||
!= moduleIncludes('editor:main', locals)
|
||||
else
|
||||
.toolbar.toolbar-editor
|
||||
div(ng-controller="EditorLoaderController")
|
||||
if (!showSourceToolbar)
|
||||
include ./toolbar
|
||||
|
||||
div(ng-if="editor.newSourceEditor")
|
||||
include ../../source-editor/source-editor
|
||||
|
|
|
@ -38,12 +38,10 @@ meta(name="ol-useOpenTelemetry" data-type="boolean" content=useOpenTelemetry)
|
|||
meta(name="ol-showSupport", data-type="boolean" content=showSupport)
|
||||
meta(name="ol-showTemplatesServerPro", data-type="boolean" content=showTemplatesServerPro)
|
||||
meta(name="ol-showCM6SwitchAwaySurvey", data-type="boolean" content=showCM6SwitchAwaySurvey)
|
||||
meta(name="ol-richTextVariant" content=richTextVariant)
|
||||
meta(name="ol-showPersonalAccessToken", data-type="boolean" content=showPersonalAccessToken)
|
||||
meta(name="ol-isReviewPanelReact", data-type="boolean" content=isReviewPanelReact)
|
||||
meta(name="ol-hasTrackChangesFeature", data-type="boolean" content=hasTrackChangesFeature)
|
||||
if (richTextVariant === 'cm6')
|
||||
meta(name="ol-mathJax3Path" content=mathJax3Path)
|
||||
meta(name="ol-mathJax3Path" content=mathJax3Path)
|
||||
|
||||
- var fileActionI18n = ['edited', 'renamed', 'created', 'deleted'].reduce((acc, i) => {acc[i] = translate('file_action_' + i); return acc}, {})
|
||||
meta(name="ol-fileActionI18n" data-type="json" content=fileActionI18n)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#editor(
|
||||
ace-editor="editor",
|
||||
ng-if="!editor.showRichText",
|
||||
ng-show="!!editor.sharejs_doc && !editor.opening && multiSelectedCount === 0 && !editor.error_state",
|
||||
theme="settings.editorTheme",
|
||||
keybindings="settings.mode",
|
||||
|
|
46
services/web/app/views/project/editor/toolbar.pug
Normal file
46
services/web/app/views/project/editor/toolbar.pug
Normal file
|
@ -0,0 +1,46 @@
|
|||
.toolbar.toolbar-editor(ng-controller="EditorToolbarController")
|
||||
.toggle-wrapper
|
||||
editor-switch
|
||||
|
||||
div(
|
||||
formatting-buttons
|
||||
ng-cloak
|
||||
ng-if="!editor.showVisual"
|
||||
buttons="editorButtons"
|
||||
opening="editor.opening"
|
||||
resize-on="layout:main:resize,layout:pdf:resize,layout:review:resize,review-panel:toggle"
|
||||
is-fullscreen-editor="ui.view == 'editor' && ui.pdfLayout == 'flat'"
|
||||
class="formatting-buttons"
|
||||
)
|
||||
div(
|
||||
formatting-buttons
|
||||
ng-cloak
|
||||
ng-if="editor.showVisual"
|
||||
buttons="[]"
|
||||
opening="editor.opening"
|
||||
resize-on="layout:main:resize,layout:pdf:resize,layout:review:resize,review-panel:toggle"
|
||||
is-fullscreen-editor="ui.view == 'editor' && ui.pdfLayout == 'flat'"
|
||||
class="formatting-buttons"
|
||||
)
|
||||
|
||||
.toolbar-pdf-right
|
||||
switch-to-pdf-button()
|
||||
detacher-synctex-control()
|
||||
editor-compile-button()
|
||||
|
||||
script(type="text/ng-template", id="formattingButtonsTpl")
|
||||
.formatting-buttons-wrapper
|
||||
|
|
||||
button.btn.formatting-btn.formatting-btn--icon(
|
||||
ng-repeat="button in shownButtons"
|
||||
ng-click="button.handleClick()"
|
||||
ng-class="{ active: button.active }",
|
||||
aria-label="{{button.title}}"
|
||||
tooltip="{{button.title}}"
|
||||
tooltip-placement="bottom"
|
||||
tooltip-append-to-body="true"
|
||||
)
|
||||
i(class="{{button.iconClass}}") {{button.iconText}}
|
||||
|
||||
if moduleIncludesAvailable('editor:galileo')
|
||||
galileo-toolbar-button
|
|
@ -1,5 +1,4 @@
|
|||
source-editor#editor(
|
||||
ng-class="{ 'review-panel-react': reviewPanel.isReact }"
|
||||
ng-if="!editor.showRichText"
|
||||
ng-show="!!editor.sharejs_doc && !editor.opening && multiSelectedCount === 0 && !editor.error_state"
|
||||
)
|
||||
|
|
|
@ -9,9 +9,6 @@ App.controller('OutlineController', function ($scope, ide, eventTracking) {
|
|||
$scope.eventTracking = eventTracking
|
||||
|
||||
function shouldShowOutline() {
|
||||
if ($scope.editor.showRichText) {
|
||||
return true
|
||||
}
|
||||
return !$scope.editor.newSourceEditor
|
||||
}
|
||||
|
||||
|
@ -21,10 +18,6 @@ App.controller('OutlineController', function ($scope, ide, eventTracking) {
|
|||
$scope.show = shouldShowOutline()
|
||||
})
|
||||
|
||||
$scope.$watch('editor.showRichText', function () {
|
||||
$scope.show = shouldShowOutline()
|
||||
})
|
||||
|
||||
$scope.$on('outline-manager:outline-changed', onOutlineChange)
|
||||
|
||||
function onOutlineChange(e, outlineInfo) {
|
||||
|
|
|
@ -68,21 +68,9 @@ class OutlineManager {
|
|||
|
||||
this.updateHighlightedLine(middleVisibleRow + 1)
|
||||
})
|
||||
|
||||
scope.$watch('editor.showRichText', () => {
|
||||
this.ignoreNextScroll = true
|
||||
this.ignoreNextCursorUpdate = true
|
||||
if (this.shouldShowOutline()) {
|
||||
this.updateOutline()
|
||||
this.broadcastChangeEvent()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
shouldShowOutline() {
|
||||
if (this.scope.editor.showRichText) {
|
||||
return true
|
||||
}
|
||||
return !this.scope.editor.newSourceEditor
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { Button } from 'react-bootstrap'
|
||||
import useScopeValue from '../../../shared/hooks/use-scope-value'
|
||||
import {
|
||||
|
@ -12,33 +12,18 @@ type CM6SwitchAwaySurveyState = 'disabled' | 'enabled' | 'shown'
|
|||
export default function CM6SwitchAwaySurvey() {
|
||||
const [state, setState] = useState<CM6SwitchAwaySurveyState>('disabled')
|
||||
const [newSourceEditor] = useScopeValue('editor.newSourceEditor')
|
||||
const [richText] = useScopeValue('editor.showRichText')
|
||||
const initialRichTextPreference = useRef<boolean>(richText)
|
||||
|
||||
useEffect(() => {
|
||||
// If the user has previously seen any switch-away survey, then don't show
|
||||
// the current one
|
||||
if (hasSeenCM6SwitchAwaySurvey()) return
|
||||
|
||||
if (initialRichTextPreference.current) {
|
||||
if (!richText && newSourceEditor) {
|
||||
// If user change from rich text to cm6, we remove the rich text
|
||||
// preference so if user use rich text -> cm6 -> ace, we will show the
|
||||
// current survey
|
||||
initialRichTextPreference.current = false
|
||||
}
|
||||
|
||||
// If the user loaded rich text initially, then don't show the survey
|
||||
// (we are assuming that they will not have used CM6 as much)
|
||||
return
|
||||
}
|
||||
|
||||
if (!newSourceEditor && !richText) {
|
||||
if (!newSourceEditor) {
|
||||
setState('enabled')
|
||||
} else {
|
||||
setState('disabled')
|
||||
}
|
||||
}, [newSourceEditor, richText])
|
||||
}, [newSourceEditor])
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = () => {
|
||||
|
|
|
@ -48,12 +48,12 @@ function EditorSwitch() {
|
|||
const [newSourceEditor, setNewSourceEditor] = useScopeValue(
|
||||
'editor.newSourceEditor'
|
||||
)
|
||||
const [richText, setRichText] = useScopeValue('editor.showRichText')
|
||||
const [visual, setVisual] = useScopeValue('editor.showVisual')
|
||||
|
||||
const [docName] = useScopeValue('editor.open_doc_name')
|
||||
const richTextAvailable = isValidTeXFile(docName)
|
||||
const richTextOrVisual = richText || (richTextAvailable && visual)
|
||||
// TODO: rename this after legacy & toolbar split tests are complete
|
||||
const richTextOrVisual = richTextAvailable && visual
|
||||
|
||||
const handleChange = useCallback(
|
||||
event => {
|
||||
|
@ -61,33 +61,25 @@ function EditorSwitch() {
|
|||
|
||||
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)
|
||||
}
|
||||
setVisual(true)
|
||||
setNewSourceEditor(true)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
sendMB('editor-switch-change', { editorType })
|
||||
},
|
||||
[setRichText, setVisual, setNewSourceEditor]
|
||||
[setVisual, setNewSourceEditor]
|
||||
)
|
||||
|
||||
return (
|
||||
|
|
|
@ -2,7 +2,6 @@ import { ChangeEvent, FC, memo, useCallback } from 'react'
|
|||
import useScopeValue from '../../../shared/hooks/use-scope-value'
|
||||
import Tooltip from '../../../shared/components/tooltip'
|
||||
import { sendMB } from '../../../infrastructure/event-tracking'
|
||||
import getMeta from '../../../utils/meta'
|
||||
import isValidTeXFile from '../../../main/is-valid-tex-file'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import SplitTestBadge from '../../../shared/components/split-test-badge'
|
||||
|
@ -12,12 +11,12 @@ function EditorSwitch() {
|
|||
const [newSourceEditor, setNewSourceEditor] = useScopeValue(
|
||||
'editor.newSourceEditor'
|
||||
)
|
||||
const [richText, setRichText] = useScopeValue('editor.showRichText')
|
||||
const [visual, setVisual] = useScopeValue('editor.showVisual')
|
||||
|
||||
const [docName] = useScopeValue('editor.open_doc_name')
|
||||
const richTextAvailable = isValidTeXFile(docName)
|
||||
const richTextOrVisual = richText || (richTextAvailable && visual)
|
||||
// TODO: rename this after legacy & toolbar split tests are complete
|
||||
const richTextOrVisual = richTextAvailable && visual
|
||||
|
||||
const handleChange = useCallback(
|
||||
event => {
|
||||
|
@ -25,33 +24,24 @@ function EditorSwitch() {
|
|||
|
||||
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)
|
||||
}
|
||||
|
||||
setVisual(true)
|
||||
setNewSourceEditor(true)
|
||||
break
|
||||
}
|
||||
|
||||
sendMB('editor-switch-change', { editorType })
|
||||
},
|
||||
[setRichText, setVisual, setNewSourceEditor]
|
||||
[setVisual, setNewSourceEditor]
|
||||
)
|
||||
|
||||
return (
|
||||
|
|
|
@ -12,7 +12,6 @@ type GrammarlyWarningProps = {
|
|||
export default function GrammarlyWarning({ delay }: GrammarlyWarningProps) {
|
||||
const [show, setShow] = useState(false)
|
||||
const [newSourceEditor] = useScopeValue('editor.newSourceEditor')
|
||||
const [showRichText] = useScopeValue('editor.showRichText')
|
||||
const grammarly = grammarlyExtensionPresent()
|
||||
const hasDismissedGrammarlyWarning = customLocalStorage.getItem(
|
||||
'editor.has_dismissed_grammarly_warning'
|
||||
|
@ -20,10 +19,7 @@ export default function GrammarlyWarning({ delay }: GrammarlyWarningProps) {
|
|||
|
||||
useEffect(() => {
|
||||
const showGrammarlyWarning =
|
||||
!hasDismissedGrammarlyWarning &&
|
||||
grammarly &&
|
||||
newSourceEditor &&
|
||||
!showRichText
|
||||
!hasDismissedGrammarlyWarning && grammarly && newSourceEditor
|
||||
|
||||
let timeoutID: Nullable<number>
|
||||
|
||||
|
@ -41,13 +37,7 @@ export default function GrammarlyWarning({ delay }: GrammarlyWarningProps) {
|
|||
clearTimeout(timeoutID)
|
||||
}
|
||||
}
|
||||
}, [
|
||||
grammarly,
|
||||
hasDismissedGrammarlyWarning,
|
||||
newSourceEditor,
|
||||
showRichText,
|
||||
delay,
|
||||
])
|
||||
}, [grammarly, hasDismissedGrammarlyWarning, newSourceEditor, delay])
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
setShow(false)
|
||||
|
|
|
@ -106,7 +106,7 @@ export class EditorFacade extends EventEmitter {
|
|||
// as new transactions.
|
||||
// This is a broad immitation of helper functions supplied in
|
||||
// the sharejs library. (See vendor/libs/sharejs, in particular
|
||||
// the 'attach_cm' and 'attach_ace' helpers)
|
||||
// the 'attach_ace' helper)
|
||||
attachShareJs(shareDoc: ShareDoc, maxDocLength?: number) {
|
||||
this.shareDoc = shareDoc
|
||||
this.maxDocLength = maxDocLength
|
||||
|
|
|
@ -37,6 +37,7 @@ import './ide/clone/index'
|
|||
import './ide/file-view/index'
|
||||
import './ide/hotkeys/index'
|
||||
import './ide/wordcount/index'
|
||||
import './ide/toolbar/index'
|
||||
import './ide/directives/layout'
|
||||
import './ide/directives/validFile'
|
||||
import './ide/directives/verticalResizablePanes'
|
||||
|
|
|
@ -85,7 +85,6 @@ export default Document = (function () {
|
|||
this.joined = false
|
||||
this.wantToBeJoined = false
|
||||
this._checkAceConsistency = () => this._checkConsistency(this.ace)
|
||||
this._checkCMConsistency = () => this._checkConsistency(this.cm)
|
||||
this._checkCM6Consistency = () => this._checkConsistency(this.cm6)
|
||||
this._bindToEditorEvents()
|
||||
this._bindToSocketEvents()
|
||||
|
@ -96,8 +95,6 @@ export default Document = (function () {
|
|||
return 'ace'
|
||||
} else if (this.cm6) {
|
||||
return 'cm6'
|
||||
} else if (this.cm) {
|
||||
return 'cm-rich-text'
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
|
@ -127,29 +124,6 @@ export default Document = (function () {
|
|||
return this.ide.$scope.$emit('document:closed', this.doc)
|
||||
}
|
||||
|
||||
attachToCM(cm) {
|
||||
this.cm = cm
|
||||
if (this.doc != null) {
|
||||
this.doc.attachToCM(this.cm)
|
||||
}
|
||||
if (this.cm != null) {
|
||||
this.cm.on('change', this._checkCMConsistency)
|
||||
}
|
||||
return this.ide.$scope.$emit('document:opened', this.doc)
|
||||
}
|
||||
|
||||
detachFromCM() {
|
||||
if (this.doc != null) {
|
||||
this.doc.detachFromCM()
|
||||
}
|
||||
if (this.cm != null) {
|
||||
this.cm.off('change', this._checkCMConsistency)
|
||||
}
|
||||
delete this.cm
|
||||
this.clearChaosMonkey()
|
||||
return this.ide.$scope.$emit('document:closed', this.doc)
|
||||
}
|
||||
|
||||
attachToCM6(cm6) {
|
||||
this.cm6 = cm6
|
||||
if (this.doc != null) {
|
||||
|
|
|
@ -17,6 +17,7 @@ import _ from 'lodash'
|
|||
import Document from './Document'
|
||||
import './components/spellMenu'
|
||||
import './directives/aceEditor'
|
||||
import './directives/formattingButtons'
|
||||
import './directives/toggleSwitch'
|
||||
import './controllers/SavingNotificationController'
|
||||
import './controllers/CompileButton'
|
||||
|
@ -45,7 +46,6 @@ export default EditorManager = (function () {
|
|||
trackChanges: false,
|
||||
wantTrackChanges: false,
|
||||
docTooLongErrorShown: false,
|
||||
showRichText: this.showRichText(),
|
||||
showVisual: this.showVisual(),
|
||||
newSourceEditor: this.newSourceEditor(),
|
||||
showSymbolPalette: false,
|
||||
|
@ -184,22 +184,7 @@ export default EditorManager = (function () {
|
|||
return editorType
|
||||
}
|
||||
|
||||
showRichText() {
|
||||
if (getMeta('ol-richTextVariant') === 'cm6') {
|
||||
return false
|
||||
}
|
||||
|
||||
return (
|
||||
this.localStorage(`editor.mode.${this.$scope.project_id}`) ===
|
||||
'rich-text'
|
||||
)
|
||||
}
|
||||
|
||||
showVisual() {
|
||||
if (getMeta('ol-richTextVariant') !== 'cm6') {
|
||||
return false
|
||||
}
|
||||
|
||||
return (
|
||||
this.localStorage(`editor.mode.${this.$scope.project_id}`) ===
|
||||
'rich-text'
|
||||
|
|
|
@ -366,19 +366,6 @@ export default ShareJsDoc = (function () {
|
|||
: undefined
|
||||
}
|
||||
|
||||
attachToCM(cm) {
|
||||
this._attachToEditor('CM', cm, () => {
|
||||
this._doc.attach_cm(cm, window.maxDocLength)
|
||||
})
|
||||
}
|
||||
|
||||
detachFromCM() {
|
||||
this._maybeDetachEditorWatchdogManager()
|
||||
return typeof this._doc.detach_cm === 'function'
|
||||
? this._doc.detach_cm()
|
||||
: undefined
|
||||
} // If we're waiting for the project to join, try again in 0.5 seconds
|
||||
|
||||
attachToCM6(cm6) {
|
||||
this._attachToEditor('CM6', cm6, () => {
|
||||
cm6.attachShareJs(this._doc, window.maxDocLength)
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import App from '../../../base'
|
||||
|
||||
export default App.directive('formattingButtons', () => ({
|
||||
scope: {
|
||||
buttons: '=',
|
||||
opening: '=',
|
||||
isFullscreenEditor: '=',
|
||||
},
|
||||
|
||||
link(scope, element, attrs) {
|
||||
scope.showMore = false
|
||||
scope.shownButtons = scope.buttons
|
||||
scope.overflowedButtons = []
|
||||
},
|
||||
|
||||
templateUrl: 'formattingButtonsTpl',
|
||||
}))
|
|
@ -285,8 +285,7 @@ export default App.controller(
|
|||
function updateScrollbar() {
|
||||
if (
|
||||
scrollbar.isVisible &&
|
||||
ide.$scope.reviewPanel.subView === $scope.SubViews.CUR_FILE &&
|
||||
!$scope.editor.showRichText
|
||||
ide.$scope.reviewPanel.subView === $scope.SubViews.CUR_FILE
|
||||
) {
|
||||
return $reviewPanelEl.css('right', `${scrollbar.scrollbarWidth}px`)
|
||||
} else {
|
||||
|
@ -554,13 +553,10 @@ export default App.controller(
|
|||
const doc_id = $scope.editor.open_doc_id
|
||||
const entries = updateEntries(doc_id)
|
||||
|
||||
// For now, not worrying about entry panels for rich text
|
||||
if (!$scope.editor.showRichText) {
|
||||
$scope.$broadcast('review-panel:recalculate-screen-positions')
|
||||
dispatchReviewPanelEvent('recalculate-screen-positions', entries)
|
||||
$scope.$broadcast('review-panel:recalculate-screen-positions')
|
||||
dispatchReviewPanelEvent('recalculate-screen-positions', entries)
|
||||
|
||||
return ide.$scope.$broadcast('review-panel:layout')
|
||||
}
|
||||
return ide.$scope.$broadcast('review-panel:layout')
|
||||
})
|
||||
|
||||
$scope.$on('editor:track-changes:visibility_changed', () =>
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
import App from '../../base'
|
||||
|
||||
App.controller('EditorLoaderController', function ($scope, localStorage) {
|
||||
$scope.$watch('editor.showVisual', function (val) {
|
||||
localStorage(
|
||||
`editor.mode.${$scope.project_id}`,
|
||||
val === true ? 'rich-text' : 'source'
|
||||
)
|
||||
})
|
||||
|
||||
$scope.$watch('editor.newSourceEditor', function (val) {
|
||||
localStorage(
|
||||
`editor.source_editor.${$scope.project_id}`,
|
||||
val === true ? 'cm6' : 'ace'
|
||||
)
|
||||
})
|
||||
})
|
|
@ -0,0 +1,19 @@
|
|||
import App from '../../base'
|
||||
import importOverleafModules from '../../../macros/import-overleaf-module.macro'
|
||||
|
||||
const eModules = importOverleafModules('editorToolbarButtons')
|
||||
const editorToolbarButtons = eModules.map(item => item.import.default)
|
||||
|
||||
export default App.controller('EditorToolbarController', ($scope, ide) => {
|
||||
const editorButtons = []
|
||||
|
||||
for (const editorToolbarButton of editorToolbarButtons) {
|
||||
const button = editorToolbarButton.button($scope, ide)
|
||||
|
||||
if (editorToolbarButton.source) {
|
||||
editorButtons.push(button)
|
||||
}
|
||||
}
|
||||
|
||||
$scope.editorButtons = editorButtons
|
||||
})
|
2
services/web/frontend/js/ide/toolbar/index.js
Normal file
2
services/web/frontend/js/ide/toolbar/index.js
Normal file
|
@ -0,0 +1,2 @@
|
|||
import './EditorLoaderController'
|
||||
import './EditorToolbarController'
|
114
services/web/frontend/js/vendor/libs/sharejs.js
vendored
114
services/web/frontend/js/vendor/libs/sharejs.js
vendored
|
@ -1584,119 +1584,5 @@ define(['ace/ace','crypto-js/sha1'], function (_ignore, CryptoJSSHA1) {
|
|||
};
|
||||
});
|
||||
|
||||
// This is some utility code to connect a CodeMirror editor
|
||||
// to a sharejs document.
|
||||
// It is heavily inspired from the Ace editor hook.
|
||||
|
||||
// Convert a CodeMirror delta into an op understood by share.js
|
||||
var applyCMToShareJS = function applyCMToShareJS(editorDoc, delta, doc, fromUndo) {
|
||||
// CodeMirror deltas give a text replacement.
|
||||
// I tuned this operation a little bit, for speed.
|
||||
var startPos = 0; // Get character position from # of chars in each line.
|
||||
var i = 0; // i goes through all lines.
|
||||
// Compute the position from the shareJS snapshot because we are in the CodeMirror
|
||||
// change event, where the change has already been applied to the editorDoc
|
||||
var docLines = doc.snapshot.split('\n', delta.from.line) // only split the document as far as we need to
|
||||
while (i < delta.from.line) {
|
||||
startPos += docLines[i].length + 1; // Add 1 for '\n'
|
||||
i++;
|
||||
}
|
||||
startPos += delta.from.ch;
|
||||
|
||||
// NOTE: Keep in sync with EditorWatchdogManager.
|
||||
if (delta.removed) {
|
||||
doc.del(startPos, delta.removed.join('\n').length, fromUndo);
|
||||
}
|
||||
if (delta.text) {
|
||||
return doc.insert(startPos, delta.text.join('\n'), fromUndo);
|
||||
}
|
||||
};
|
||||
|
||||
// Attach a CodeMirror editor to the document. The editor's contents are replaced
|
||||
// with the document's contents.
|
||||
// NOTE: When upgrading CM, make sure to check for new special cases of
|
||||
// origin prefixes as documented for `doc.setSelection`. We are using
|
||||
// a custom `origin: 'remote'` which may conflict.
|
||||
// Perma link of the docs at the time of writing this note:
|
||||
// https://web.archive.org/web/20201029163528/https://codemirror.net/doc/manual.html#selection_origin
|
||||
window.sharejs.extendDoc('attach_cm', function (editor, maxDocLength) {
|
||||
if (!this.provides.text) {
|
||||
throw new Error('Only text documents can be attached to CodeMirror2');
|
||||
}
|
||||
|
||||
var sharedoc = this;
|
||||
var editorDoc = editor.getDoc();
|
||||
|
||||
function check() {
|
||||
return window.setTimeout(function () {
|
||||
var editorText = editor.getValue();
|
||||
var otText = sharedoc.getText();
|
||||
|
||||
if (editorText !== otText) {
|
||||
sharedoc.emit('error','Text does not match in CodeMirror')
|
||||
console.error('Text does not match!');
|
||||
console.error('editor: ' + editorText);
|
||||
return console.error('ot: ' + otText);
|
||||
}
|
||||
}
|
||||
// Removed editor.setValue here as it would cause recursive loops if
|
||||
// consistency check failed - because setting the value would trigger
|
||||
// the change event
|
||||
, 0);
|
||||
};
|
||||
|
||||
onDelete(0, editor.getValue());
|
||||
onInsert(0, sharedoc.getText());
|
||||
|
||||
check();
|
||||
|
||||
// Listen for edits in CodeMirror.
|
||||
function editorListener(ed, change) {
|
||||
if (change.origin === 'remote') {
|
||||
// this change has been injected via sharejs
|
||||
return;
|
||||
}
|
||||
if (maxDocLength != null && editorDoc.getValue().length >= maxDocLength) {
|
||||
sharedoc.emit('error', new Error('document length is greater than maxDocLength'));
|
||||
return;
|
||||
}
|
||||
var fromUndo = (change.origin === 'undo')
|
||||
applyCMToShareJS(editorDoc, change, sharedoc, fromUndo);
|
||||
return check();
|
||||
};
|
||||
|
||||
editorDoc.on('change', editorListener);
|
||||
|
||||
function onInsert(pos, text) {
|
||||
// All the primitives we need are already in CM's API.
|
||||
// call signature: editor.replaceRange(text, from, to, origin)
|
||||
editor.replaceRange(text, editor.posFromIndex(pos), undefined, 'remote');
|
||||
// Clear CM's undo/redo history on remote edit. This prevents issues where
|
||||
// a user can accidentally remove another user's edits
|
||||
editor.clearHistory();
|
||||
return check();
|
||||
};
|
||||
|
||||
function onDelete(pos, text) {
|
||||
var from = editor.posFromIndex(pos);
|
||||
var to = editor.posFromIndex(pos + text.length);
|
||||
editor.replaceRange('', from, to, 'remote');
|
||||
// Clear CM's undo/redo history on remote edit. This prevents issues where
|
||||
// a user can accidentally remove another user's edits
|
||||
editor.clearHistory()
|
||||
return check();
|
||||
};
|
||||
|
||||
this.on('insert', onInsert);
|
||||
this.on('delete', onDelete);
|
||||
|
||||
this.detach_cm = function () {
|
||||
this.removeListener('insert', onInsert);
|
||||
this.removeListener('delete', onDelete);
|
||||
editorDoc.off('change', editorListener);
|
||||
return delete this.detach_cm;
|
||||
};
|
||||
});
|
||||
|
||||
return window.sharejs;
|
||||
});
|
||||
|
|
|
@ -2,7 +2,6 @@ import { ScopeDecorator } from './decorators/scope'
|
|||
import { useLocalCompileContext } from '../js/shared/context/local-compile-context'
|
||||
import { useEffect } from 'react'
|
||||
import { PdfPreviewMessages } from '../js/features/pdf-preview/components/pdf-preview-messages'
|
||||
import { useScope } from './hooks/use-scope'
|
||||
import CompileTimeWarning from '../js/features/pdf-preview/components/compile-time-warning'
|
||||
|
||||
export default {
|
||||
|
@ -18,12 +17,6 @@ export const Dismissible = () => {
|
|||
setShowCompileTimeWarning(true)
|
||||
}, [setShowCompileTimeWarning])
|
||||
|
||||
useScope({
|
||||
editor: {
|
||||
showRichText: true,
|
||||
},
|
||||
})
|
||||
|
||||
return (
|
||||
<div style={{ width: 800, position: 'relative' }}>
|
||||
<PdfPreviewMessages>
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
@import './editor/online-users.less';
|
||||
@import './editor/hotkeys.less';
|
||||
@import './editor/review-panel.less';
|
||||
@import './editor/rich-text.less';
|
||||
@import './editor/publish-modal.less';
|
||||
@import './editor/outline.less';
|
||||
@import './editor/logs.less';
|
||||
|
@ -93,8 +92,7 @@
|
|||
}
|
||||
}
|
||||
|
||||
#editor,
|
||||
#editor-rich-text {
|
||||
#editor {
|
||||
.full-size;
|
||||
}
|
||||
|
||||
|
|
|
@ -858,12 +858,6 @@
|
|||
right: 0;
|
||||
}
|
||||
|
||||
#editor-rich-text {
|
||||
.rp-size-expanded & {
|
||||
right: @review-panel-width;
|
||||
}
|
||||
}
|
||||
|
||||
.rp-unsupported-msg-wrapper {
|
||||
display: none;
|
||||
|
||||
|
|
|
@ -1,254 +0,0 @@
|
|||
@rt-font-family-serif: 'Palatino Linotype', 'Book Antiqua', Palatino, serif;
|
||||
@rt-line-padding: 8%;
|
||||
|
||||
.rich-text .CodeMirror {
|
||||
font-family: @rt-font-family-serif;
|
||||
font-size: 1.15em;
|
||||
|
||||
pre {
|
||||
font-family: @rt-font-family-serif;
|
||||
}
|
||||
|
||||
.CodeMirror-line {
|
||||
// Add horizontal padding, to emulate a manuscript more closely
|
||||
padding: 0 @rt-line-padding;
|
||||
}
|
||||
|
||||
.CodeMirror-linenumber {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
// TODO: Change prefix away from wl- ?
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
.preamble h1 {
|
||||
text-align: center;
|
||||
font-size: 2em;
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
.preamble ul.authors {
|
||||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
list-style: none;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.preamble ul.authors li {
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
// wl-indent-X is used to add extra left padding to nested itemize/enumerate
|
||||
// environments, so that the inner list appears more indented than the outer
|
||||
.wl-indent-0 {
|
||||
padding-left: calc(~'2.5em + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
.wl-indent-1 {
|
||||
padding-left: calc(~'3.5em + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
.wl-indent-2 {
|
||||
padding-left: calc(~'4.5em + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
.wl-indent-3 {
|
||||
padding-left: calc(~'5.5em + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
.wl-indent-4 {
|
||||
padding-left: calc(~'6.5em + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
// wl-indent-env-X is used to add extra left padding to empty nested itemize/
|
||||
// enumerate environments
|
||||
.wl-indent-env-0 {
|
||||
padding-left: calc(~'4px + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
.wl-indent-env-1 {
|
||||
padding-left: calc(~'1.5em + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
.wl-indent-env-2 {
|
||||
padding-left: calc(~'2.5em + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
.wl-indent-env-3 {
|
||||
padding-left: calc(~'3.5em + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
.wl-indent-env-4 {
|
||||
padding-left: calc(~'4.5em + @{rt-line-padding}') !important;
|
||||
}
|
||||
|
||||
.wl-enumerate-item-open {
|
||||
text-align: right;
|
||||
width: 1.5em;
|
||||
display: inline-block;
|
||||
padding-right: 0.2em;
|
||||
}
|
||||
|
||||
.wl-item-open {
|
||||
text-align: right;
|
||||
width: 1.5em;
|
||||
display: inline-block;
|
||||
padding-right: 0.2em;
|
||||
}
|
||||
|
||||
.wl-input {
|
||||
font-style: oblique;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
.wl-abstract-open,
|
||||
.wl-abstract-close {
|
||||
border-top: 1px solid #999;
|
||||
font-size: large;
|
||||
font-weight: bold;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wl-figure {
|
||||
max-height: 120px;
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.wl-figure-wrap {
|
||||
padding: 10px 0;
|
||||
background-color: #f5f5f5;
|
||||
box-shadow: 1.3px 2px 2px #dfdfdf;
|
||||
width: 96%;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wl-figure-caption {
|
||||
padding: 3px 0 4px;
|
||||
font-size: small;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
.wl-chapter,
|
||||
.wl-chapter-open,
|
||||
.wl-chapter-close {
|
||||
font-size: 2.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.wl-chapter-open,
|
||||
.wl-chapter-close {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
.wl-section,
|
||||
.wl-section-open,
|
||||
.wl-section-close {
|
||||
font-size: 1.8em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.wl-section-open,
|
||||
.wl-section-close {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
.wl-subsection,
|
||||
.wl-subsection-open,
|
||||
.wl-subsection-close {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.wl-subsection-open,
|
||||
.wl-subsection-close {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
.wl-subsubsection,
|
||||
.wl-subsubsection-open,
|
||||
.wl-subsubsection-close {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.wl-subsubsection-open,
|
||||
.wl-subsubsection-close {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
.wl-textbf {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.wl-textbf-open {
|
||||
font-weight: bold;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.wl-textbf-close {
|
||||
font-weight: bold;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.wl-label-bracket {
|
||||
font-weight: bold;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.wl-label-open,
|
||||
.wl-input-link {
|
||||
.wl-icon {
|
||||
padding-left: 5px;
|
||||
padding-right: 2px;
|
||||
vertical-align: middle;
|
||||
// @include wl-icon-size(inherit);
|
||||
}
|
||||
}
|
||||
|
||||
.wl-img-default {
|
||||
width: 0.9em;
|
||||
padding: 0 1px 1px;
|
||||
}
|
||||
|
||||
.wl-label-close {
|
||||
background-color: #f7f7f9;
|
||||
border: 1px solid #e1e1e8;
|
||||
border-radius: 4px;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
.wl-textit {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.wl-textit-open {
|
||||
font-style: italic;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.wl-textit-close {
|
||||
font-style: italic;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.spelling-error {
|
||||
background-image: url(../../../../public/img/spellcheck-underline.png);
|
||||
background-repeat: repeat-x;
|
||||
background-position: bottom;
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@
|
|||
@import 'core/ol-ieee-variables.less';
|
||||
|
||||
@is-overleaf-light: false;
|
||||
@show-rich-text: true;
|
||||
|
||||
@ieee-wedge: 30px;
|
||||
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
@import 'core/ol-light-variables.less';
|
||||
|
||||
@is-overleaf-light: true;
|
||||
@show-rich-text: true;
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
@import 'variables/themes/ieee.less';
|
||||
|
||||
@is-overleaf-light: false;
|
||||
@show-rich-text: true;
|
||||
|
||||
@ieee-wedge: 30px;
|
||||
|
||||
|
|
|
@ -2,4 +2,3 @@
|
|||
@import 'variables/themes/light.less';
|
||||
|
||||
@is-overleaf-light: true;
|
||||
@show-rich-text: true;
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
@import (less) '../fonts/material-symbols.css';
|
||||
|
||||
@is-overleaf-light: false;
|
||||
@show-rich-text: true;
|
||||
@is-new-css: true;
|
||||
|
||||
// Core variables and mixins
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
@import (less) '../fonts/material-symbols.css';
|
||||
|
||||
@is-overleaf-light: false;
|
||||
@show-rich-text: true;
|
||||
@is-new-css: false;
|
||||
|
||||
// Core variables and mixins
|
||||
|
|
|
@ -146,7 +146,6 @@
|
|||
"chartjs-adapter-moment": "^1.0.1",
|
||||
"chartjs-plugin-datalabels": "^2.2.0",
|
||||
"classnames": "^2.2.6",
|
||||
"codemirror": "~5.33.0",
|
||||
"connect-redis": "^6.1.3",
|
||||
"content-disposition": "^0.5.0",
|
||||
"contentful": "^6.1.1",
|
||||
|
|
|
@ -104,27 +104,6 @@ describe('<GrammarlyWarning />', function () {
|
|||
})
|
||||
})
|
||||
|
||||
it('does not show warning when user have rich text as their preference', async function () {
|
||||
grammarlyStub.returns(true)
|
||||
|
||||
renderWithEditorContext(<GrammarlyWarning delay={100} />, {
|
||||
scope: {
|
||||
editor: {
|
||||
newSourceEditor: true,
|
||||
showRichText: true,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
await waitFor(() => {
|
||||
expect(
|
||||
screen.queryByText(
|
||||
'A browser extension, for example Grammarly, may be slowing down Overleaf.'
|
||||
)
|
||||
).to.not.exist
|
||||
})
|
||||
})
|
||||
|
||||
it('hides warning if close button is pressed', async function () {
|
||||
grammarlyStub.returns(true)
|
||||
|
||||
|
|
Loading…
Reference in a new issue