mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-30 10:23:04 -05:00
c8f0885316
GitOrigin-RevId: 812d3b5f1df7e769c8be732ccb31653e8e9a8aa3
128 lines
3.7 KiB
JavaScript
128 lines
3.7 KiB
JavaScript
import { isEqual, cloneDeep } from 'lodash'
|
|
import './controllers/outline-controller'
|
|
import { matchOutline, nestOutline } from './outline-parser'
|
|
import isValidTeXFile from '../../main/is-valid-tex-file'
|
|
|
|
class OutlineManager {
|
|
constructor(ide, scope) {
|
|
this.ide = ide
|
|
this.scope = scope
|
|
this.shareJsDoc = null
|
|
this.isTexFile = false
|
|
this.flatOutline = []
|
|
this.previousFlatOutline = []
|
|
this.outline = []
|
|
this.highlightedLine = null
|
|
this.ignoreNextScroll = false
|
|
this.ignoreNextCursorUpdate = false
|
|
|
|
scope.$watch('editor.newSourceEditor', (now, before) => {
|
|
if (before && !now) {
|
|
this.updateOutline()
|
|
this.broadcastChangeEvent()
|
|
}
|
|
})
|
|
|
|
scope.$on('doc:after-opened', (ev, { isNewDoc }) => {
|
|
if (isNewDoc) {
|
|
// if a new doc is opened a cursor updates will be triggered before the
|
|
// content is loaded. We have to ignore it or the outline highlight
|
|
// will be incorrect. This doesn't happen when `doc:after-opened` is
|
|
// fired without a new doc opened.
|
|
this.ignoreNextCursorUpdate = true
|
|
}
|
|
// always ignore the next scroll update so the cursor update takes
|
|
// precedence
|
|
this.ignoreNextScroll = true
|
|
this.shareJsDoc = scope.editor.sharejs_doc
|
|
this.isTexFile = isValidTeXFile(scope.editor.open_doc_name)
|
|
this.updateOutline()
|
|
this.broadcastChangeEvent()
|
|
})
|
|
|
|
scope.$on('doc:changed', () => {
|
|
this.updateOutline()
|
|
this.broadcastChangeEvent()
|
|
})
|
|
|
|
scope.$on('file-view:file-opened', () => {
|
|
this.isTexFile = false
|
|
this.updateOutline()
|
|
this.broadcastChangeEvent()
|
|
})
|
|
|
|
scope.$on('cursor:editor:update', (event, cursorPosition) => {
|
|
if (this.ignoreNextCursorUpdate) {
|
|
this.ignoreNextCursorUpdate = false
|
|
return
|
|
}
|
|
this.updateHighlightedLine(cursorPosition.row + 1)
|
|
this.broadcastChangeEvent()
|
|
})
|
|
|
|
scope.$on('scroll:editor:update', (event, middleVisibleRow) => {
|
|
if (this.ignoreNextScroll) {
|
|
this.ignoreNextScroll = false
|
|
return
|
|
}
|
|
|
|
this.updateHighlightedLine(middleVisibleRow + 1)
|
|
})
|
|
}
|
|
|
|
shouldShowOutline() {
|
|
return !this.scope.editor.newSourceEditor
|
|
}
|
|
|
|
updateOutline() {
|
|
// Disable if using CM6
|
|
if (!this.shouldShowOutline()) {
|
|
return
|
|
}
|
|
if (this.isTexFile) {
|
|
const content = this.ide.editorManager.getCurrentDocValue()
|
|
if (content) {
|
|
this.flatOutline = matchOutline(content)
|
|
if (!isEqual(this.flatOutline, this.previousFlatOutline)) {
|
|
this.previousFlatOutline = cloneDeep(this.flatOutline)
|
|
this.outline = nestOutline(this.flatOutline)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
this.previousFlatOutline = []
|
|
this.outline = []
|
|
}
|
|
|
|
// set highlightedLine to the closest outline line above the editorLine
|
|
updateHighlightedLine(editorLine) {
|
|
let closestOutlineLine = null
|
|
for (let lineId = 0; lineId < this.flatOutline.length; lineId++) {
|
|
const outline = this.flatOutline[lineId]
|
|
if (editorLine < outline.line) break // editorLine is above
|
|
closestOutlineLine = outline.line
|
|
}
|
|
if (closestOutlineLine === this.highlightedLine) return
|
|
this.highlightedLine = closestOutlineLine
|
|
this.broadcastChangeEvent()
|
|
}
|
|
|
|
jumpToLine(line, syncToPdf) {
|
|
this.ignoreNextScroll = true
|
|
this.ide.editorManager.jumpToLine({ gotoLine: line, syncToPdf })
|
|
}
|
|
|
|
broadcastChangeEvent() {
|
|
// Disable if using CM6
|
|
if (!this.shouldShowOutline()) {
|
|
return
|
|
}
|
|
this.scope.$broadcast('outline-manager:outline-changed', {
|
|
isTexFile: this.isTexFile,
|
|
outline: this.outline,
|
|
highlightedLine: this.highlightedLine,
|
|
})
|
|
}
|
|
}
|
|
|
|
export default OutlineManager
|