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:
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user