1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 09:46:22 +00:00

Sync Split Editor scroll position

This commit is contained in:
Sander Steenhuis
2018-02-09 03:19:04 +01:00
parent 46a733ba5b
commit c82eba05d1
3 changed files with 62 additions and 0 deletions

View File

@@ -47,6 +47,7 @@ export default class CodeEditor extends React.Component {
this.loadStyleHandler = (e) => { this.loadStyleHandler = (e) => {
this.editor.refresh() this.editor.refresh()
} }
this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, {leading: false, trailing: true})
} }
componentDidMount () { componentDidMount () {
@@ -107,6 +108,7 @@ export default class CodeEditor extends React.Component {
this.editor.on('blur', this.blurHandler) this.editor.on('blur', this.blurHandler)
this.editor.on('change', this.changeHandler) this.editor.on('change', this.changeHandler)
this.editor.on('paste', this.pasteHandler) this.editor.on('paste', this.pasteHandler)
this.editor.on('scroll', this.scrollHandler)
const editorTheme = document.getElementById('editorTheme') const editorTheme = document.getElementById('editorTheme')
editorTheme.addEventListener('load', this.loadStyleHandler) editorTheme.addEventListener('load', this.loadStyleHandler)
@@ -126,6 +128,7 @@ export default class CodeEditor extends React.Component {
this.editor.off('blur', this.blurHandler) this.editor.off('blur', this.blurHandler)
this.editor.off('change', this.changeHandler) this.editor.off('change', this.changeHandler)
this.editor.off('paste', this.pasteHandler) this.editor.off('paste', this.pasteHandler)
this.editor.off('scroll', this.scrollHandler)
const editorTheme = document.getElementById('editorTheme') const editorTheme = document.getElementById('editorTheme')
editorTheme.removeEventListener('load', this.loadStyleHandler) editorTheme.removeEventListener('load', this.loadStyleHandler)
} }
@@ -254,6 +257,12 @@ export default class CodeEditor extends React.Component {
} }
} }
handleScroll (e) {
if (this.props.onScroll) {
this.props.onScroll(e)
}
}
render () { render () {
const { className, fontSize } = this.props const { className, fontSize } = this.props
let fontFamily = this.props.fontFamily let fontFamily = this.props.fontFamily

View File

@@ -121,6 +121,7 @@ export default class MarkdownPreview extends React.Component {
this.mouseDownHandler = (e) => this.handleMouseDown(e) this.mouseDownHandler = (e) => this.handleMouseDown(e)
this.mouseUpHandler = (e) => this.handleMouseUp(e) this.mouseUpHandler = (e) => this.handleMouseUp(e)
this.DoubleClickHandler = (e) => this.handleDoubleClick(e) this.DoubleClickHandler = (e) => this.handleDoubleClick(e)
this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, {leading: false, trailing: true})
this.anchorClickHandler = (e) => this.handlePreviewAnchorClick(e) this.anchorClickHandler = (e) => this.handlePreviewAnchorClick(e)
this.checkboxClickHandler = (e) => this.handleCheckboxClick(e) this.checkboxClickHandler = (e) => this.handleCheckboxClick(e)
this.saveAsTextHandler = () => this.handleSaveAsText() this.saveAsTextHandler = () => this.handleSaveAsText()
@@ -151,6 +152,12 @@ export default class MarkdownPreview extends React.Component {
this.props.onCheckboxClick(e) this.props.onCheckboxClick(e)
} }
handleScroll (e) {
if (this.props.onScroll) {
this.props.onScroll(e)
}
}
handleContextMenu (e) { handleContextMenu (e) {
this.props.onContextMenu(e) this.props.onContextMenu(e)
} }
@@ -279,6 +286,7 @@ export default class MarkdownPreview extends React.Component {
this.refs.root.contentWindow.document.addEventListener('dblclick', this.DoubleClickHandler) this.refs.root.contentWindow.document.addEventListener('dblclick', this.DoubleClickHandler)
this.refs.root.contentWindow.document.addEventListener('drop', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.addEventListener('drop', this.preventImageDroppedHandler)
this.refs.root.contentWindow.document.addEventListener('dragover', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.addEventListener('dragover', this.preventImageDroppedHandler)
this.refs.root.contentWindow.document.addEventListener('scroll', this.scrollHandler)
eventEmitter.on('export:save-text', this.saveAsTextHandler) eventEmitter.on('export:save-text', this.saveAsTextHandler)
eventEmitter.on('export:save-md', this.saveAsMdHandler) eventEmitter.on('export:save-md', this.saveAsMdHandler)
eventEmitter.on('export:save-html', this.saveAsHtmlHandler) eventEmitter.on('export:save-html', this.saveAsHtmlHandler)
@@ -292,6 +300,7 @@ export default class MarkdownPreview extends React.Component {
this.refs.root.contentWindow.document.removeEventListener('dblclick', this.DoubleClickHandler) this.refs.root.contentWindow.document.removeEventListener('dblclick', this.DoubleClickHandler)
this.refs.root.contentWindow.document.removeEventListener('drop', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.removeEventListener('drop', this.preventImageDroppedHandler)
this.refs.root.contentWindow.document.removeEventListener('dragover', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.removeEventListener('dragover', this.preventImageDroppedHandler)
this.refs.root.contentWindow.document.removeEventListener('scroll', this.scrollHandler)
eventEmitter.off('export:save-text', this.saveAsTextHandler) eventEmitter.off('export:save-text', this.saveAsTextHandler)
eventEmitter.off('export:save-md', this.saveAsMdHandler) eventEmitter.off('export:save-md', this.saveAsMdHandler)
eventEmitter.off('export:save-html', this.saveAsHtmlHandler) eventEmitter.off('export:save-html', this.saveAsHtmlHandler)

View File

@@ -2,6 +2,7 @@ import React from 'react'
import CodeEditor from 'browser/components/CodeEditor' import CodeEditor from 'browser/components/CodeEditor'
import MarkdownPreview from 'browser/components/MarkdownPreview' import MarkdownPreview from 'browser/components/MarkdownPreview'
import { findStorage } from 'browser/lib/findStorage' import { findStorage } from 'browser/lib/findStorage'
import _ from 'lodash'
import styles from './MarkdownSplitEditor.styl' import styles from './MarkdownSplitEditor.styl'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
@@ -12,6 +13,7 @@ class MarkdownSplitEditor extends React.Component {
this.value = props.value this.value = props.value
this.focus = () => this.refs.code.focus() this.focus = () => this.refs.code.focus()
this.reload = () => this.refs.code.reload() this.reload = () => this.refs.code.reload()
this.userScroll = true
} }
handleOnChange () { handleOnChange () {
@@ -19,6 +21,46 @@ class MarkdownSplitEditor extends React.Component {
this.props.onChange() this.props.onChange()
} }
handleScroll (e) {
const previewDoc = _.get(this, 'refs.preview.refs.root.contentWindow.document')
const codeDoc = _.get(this, 'refs.code.editor.doc')
let srcTop, srcHeight, targetTop, targetHeight
if (this.userScroll) {
if (e.doc) {
srcTop = _.get(e, 'doc.scrollTop')
srcHeight = _.get(e, 'doc.height')
targetTop = _.get(previewDoc, 'body.scrollTop')
targetHeight = _.get(previewDoc, 'body.scrollHeight')
} else {
srcTop = _.get(previewDoc, 'body.scrollTop')
srcHeight = _.get(previewDoc, 'body.scrollHeight')
targetTop = _.get(codeDoc, 'scrollTop')
targetHeight = _.get(codeDoc, 'height')
}
const factor = srcTop / srcHeight
const previewTarget = targetHeight * factor
const distance = previewTarget - targetTop
this.userScroll = false
const s = 20
let i = s
let f, t
const timer = setInterval(() => {
t = (s - i) / s
f = t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t
if (e.doc) _.set(previewDoc, 'body.scrollTop', targetTop + f * distance)
else _.get(this, 'refs.code.editor').scrollTo(0, targetTop + f * distance)
if (!i) {
clearInterval(timer)
setTimeout(() => { this.userScroll = true }, 400)
}
i -= 1
}, 1000 / 60)
}
}
handleCheckboxClick (e) { handleCheckboxClick (e) {
e.preventDefault() e.preventDefault()
e.stopPropagation() e.stopPropagation()
@@ -68,6 +110,7 @@ class MarkdownSplitEditor extends React.Component {
scrollPastEnd={config.editor.scrollPastEnd} scrollPastEnd={config.editor.scrollPastEnd}
storageKey={storageKey} storageKey={storageKey}
onChange={this.handleOnChange.bind(this)} onChange={this.handleOnChange.bind(this)}
onScroll={this.handleScroll.bind(this)}
/> />
<MarkdownPreview <MarkdownPreview
style={previewStyle} style={previewStyle}
@@ -84,6 +127,7 @@ class MarkdownSplitEditor extends React.Component {
tabInde='0' tabInde='0'
value={value} value={value}
onCheckboxClick={(e) => this.handleCheckboxClick(e)} onCheckboxClick={(e) => this.handleCheckboxClick(e)}
onScroll={this.handleScroll.bind(this)}
showCopyNotification={config.ui.showCopyNotification} showCopyNotification={config.ui.showCopyNotification}
storagePath={storage.path} storagePath={storage.path}
/> />