0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2026-01-11 22:02:41 +00:00

Bind livescrolling when done via scrollbars.

This commit is contained in:
David Bolack
2024-08-24 00:47:06 -05:00
parent 695293333f
commit e27e61aaca
3 changed files with 83 additions and 27 deletions

View File

@@ -19,6 +19,7 @@ const DOMPurify = require('dompurify');
const purifyConfig = { FORCE_BODY: true, SANITIZE_DOM: false }; const purifyConfig = { FORCE_BODY: true, SANITIZE_DOM: false };
const PAGE_HEIGHT = 1056; const PAGE_HEIGHT = 1056;
let isScrolling;
const INITIAL_CONTENT = dedent` const INITIAL_CONTENT = dedent`
<!DOCTYPE html><html><head> <!DOCTYPE html><html><head>
@@ -87,9 +88,16 @@ const BrewRenderer = (props)=>{
const handleScroll = (e)=>{ const handleScroll = (e)=>{
const target = e.target; const target = e.target;
const newPage = Math.floor(target.scrollTop / target.scrollHeight * rawPages.length);
if(newPage != state.viewablePageNumber) {
window.clearTimeout(isScrolling);
isScrolling = setTimeout(function() {
window.parent.document.dispatchEvent(new CustomEvent('renderScrolled', {}));
}, 66);
}
setState((prevState)=>({ setState((prevState)=>({
...prevState, ...prevState,
viewablePageNumber : Math.floor(target.scrollTop / target.scrollHeight * rawPages.length) viewablePageNumber : newPage
})); }));
}; };

View File

@@ -23,6 +23,9 @@ const DEFAULT_STYLE_TEXT = dedent`
}`; }`;
let lastPage = 0; let lastPage = 0;
let lockBrewJump = false;
let lockSourceJump = false;
let scrollingJump = false;
const isElementCodeMirror=(element)=>{ const isElementCodeMirror=(element)=>{
let el = element; let el = element;
@@ -73,6 +76,7 @@ const Editor = createClass({
this.highlightCustomMarkdown(); this.highlightCustomMarkdown();
window.addEventListener('resize', this.updateEditorSize); window.addEventListener('resize', this.updateEditorSize);
document.getElementById('BrewRenderer').addEventListener('keydown', this.handleControlKeys); document.getElementById('BrewRenderer').addEventListener('keydown', this.handleControlKeys);
document.addEventListener('renderScrolled', this.handleBrewScroll);
document.addEventListener('keydown', this.handleControlKeys); document.addEventListener('keydown', this.handleControlKeys);
document.addEventListener('click', (e)=>{ document.addEventListener('click', (e)=>{
if(isElementCodeMirror(e.target) && this.props.liveScroll ) { if(isElementCodeMirror(e.target) && this.props.liveScroll ) {
@@ -128,7 +132,6 @@ const Editor = createClass({
} }
if(!(e.ctrlKey || e.metaKey)) return; if(!(e.ctrlKey || e.metaKey)) return;
console.log(e);
// Handle CTRL-HOME and CTRL-END // Handle CTRL-HOME and CTRL-END
if(((e.keyCode == END_KEY) || (e.keyCode == HOME_KEY)) && this.props.liveScroll) this.brewJump(); if(((e.keyCode == END_KEY) || (e.keyCode == HOME_KEY)) && this.props.liveScroll) this.brewJump();
@@ -140,6 +143,19 @@ const Editor = createClass({
} }
}, },
handleBrewScroll : function() {
if(!this.props.liveScroll) return;
scrollingJump = true;
this.sourceJump();
scrollingJump = false;
},
handleSourceScroll : function(e) {
if(!this.props.liveScroll) return;
scrollingJump = true;
this.brewJump();
scrollingJump = false;
},
updateEditorSize : function() { updateEditorSize : function() {
if(this.codeEditor.current) { if(this.codeEditor.current) {
@@ -318,7 +334,10 @@ const Editor = createClass({
}, },
brewJump : function(targetPage=this.getCurrentPage()){ brewJump : function(targetPage=this.getCurrentPage()){
if(lockBrewJump) return;
if(!window) return; if(!window) return;
lockSourceJump = true;
lockBrewJump = true;
//console.log(`Scroll to: p${targetPage}`); //console.log(`Scroll to: p${targetPage}`);
const brewRenderer = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer')[0]; const brewRenderer = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer')[0];
const currentPos = brewRenderer.scrollTop; const currentPos = brewRenderer.scrollTop;
@@ -328,6 +347,9 @@ const Editor = createClass({
const bounceDelay = 100; const bounceDelay = 100;
const scrollDelay = 500; const scrollDelay = 500;
if(scrollingJump) {
brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'instant', block: 'start' });
} else {
if(!this.throttleBrewMove) { if(!this.throttleBrewMove) {
this.throttleBrewMove = _.throttle((currentPos, interimPos, targetPos)=>{ this.throttleBrewMove = _.throttle((currentPos, interimPos, targetPos)=>{
brewRenderer.scrollTo({ top: currentPos + interimPos, behavior: 'smooth' }); brewRenderer.scrollTo({ top: currentPos + interimPos, behavior: 'smooth' });
@@ -337,15 +359,21 @@ const Editor = createClass({
}, scrollDelay, { leading: true, trailing: false }); }, scrollDelay, { leading: true, trailing: false });
}; };
this.throttleBrewMove(currentPos, interimPos, targetPos); this.throttleBrewMove(currentPos, interimPos, targetPos);
}
lockSourceJump = false;
lockBrewJump = false;
// const hashPage = (page != 1) ? `p${page}` : ''; // const hashPage = (page != 1) ? `p${page}` : '';
// window.location.hash = hashPage; // window.location.hash = hashPage;
}, },
sourceJump : function(targetLine=null){ sourceJump : function(targetLine=null){
if(lockSourceJump) return;
if(this.isText()) { if(this.isText()) {
if(targetLine == null) { if(targetLine == null) {
targetLine = 0; targetLine = 0;
lockBrewJump = true;
lockSourceJump = true;
const pageCollection = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('page'); const pageCollection = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('page');
const brewRendererHeight = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer').item(0).getBoundingClientRect().height; const brewRendererHeight = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer').item(0).getBoundingClientRect().height;
@@ -368,6 +396,7 @@ const Editor = createClass({
let currentY = this.codeEditor.current.codeMirror.getScrollInfo().top; let currentY = this.codeEditor.current.codeMirror.getScrollInfo().top;
let targetY = this.codeEditor.current.codeMirror.heightAtLine(targetLine, 'local', true); let targetY = this.codeEditor.current.codeMirror.heightAtLine(targetLine, 'local', true);
if(!scrollingJump) {
//Scroll 1/10 of the way every 10ms until 1px off. //Scroll 1/10 of the way every 10ms until 1px off.
const incrementalScroll = setInterval(()=>{ const incrementalScroll = setInterval(()=>{
currentY += (targetY - currentY) / 10; currentY += (targetY - currentY) / 10;
@@ -383,8 +412,17 @@ const Editor = createClass({
this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 }); this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 });
this.codeEditor.current.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash'); this.codeEditor.current.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash');
clearInterval(incrementalScroll); clearInterval(incrementalScroll);
lockBrewJump = false;
lockSourceJump = false;
} }
}, 10); }, 10);
} else {
this.codeEditor.current.codeMirror.scrollTo(null, targetY); // Scroll any remaining difference
this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 });
this.codeEditor.current.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash');
lockBrewJump = false;
lockSourceJump = false;
}
} }
} }
}, },
@@ -415,6 +453,7 @@ const Editor = createClass({
view={this.state.view} view={this.state.view}
value={this.props.brew.text} value={this.props.brew.text}
onChange={this.props.onTextChange} onChange={this.props.onTextChange}
onScroll={this.handleSourceScroll}
editorTheme={this.state.editorTheme} editorTheme={this.state.editorTheme}
rerenderParent={this.rerenderParent} /> rerenderParent={this.rerenderParent} />
</>; </>;

View File

@@ -7,6 +7,7 @@ const closeTag = require('./close-tag');
const autoCompleteEmoji = require('./autocompleteEmoji'); const autoCompleteEmoji = require('./autocompleteEmoji');
let CodeMirror; let CodeMirror;
let isScrolling;
if(typeof window !== 'undefined'){ if(typeof window !== 'undefined'){
CodeMirror = require('codemirror'); CodeMirror = require('codemirror');
@@ -190,6 +191,14 @@ const CodeEditor = createClass({
// Note: codeMirror passes a copy of itself in this callback. cm === this.codeMirror. Either one works. // Note: codeMirror passes a copy of itself in this callback. cm === this.codeMirror. Either one works.
this.codeMirror.on('change', (cm)=>{this.props.onChange(cm.getValue());}); this.codeMirror.on('change', (cm)=>{this.props.onChange(cm.getValue());});
this.codeMirror.on('scroll', (cm)=>{
window.clearTimeout(isScrolling);
const props = this.props;
isScrolling = setTimeout(function() {
cm.setCursor({ line: cm.lineAtHeight(cm.getWrapperElement().getBoundingClientRect().top) + 1, ch: 0 });
props.onScroll(cm.lineAtHeight(cm.getWrapperElement().getBoundingClientRect().top));
}, 66);
});
this.updateSize(); this.updateSize();
}, },