diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx
index 5cbac23f7..5f7772d55 100644
--- a/client/homebrew/brewRenderer/brewRenderer.jsx
+++ b/client/homebrew/brewRenderer/brewRenderer.jsx
@@ -58,6 +58,7 @@ const BrewRenderer = (props)=>{
errors : [],
currentEditorPage : 0,
themeBundle : {},
+ onPageChange : ()=>{},
...props
};
@@ -88,27 +89,12 @@ const BrewRenderer = (props)=>{
}));
};
- const handleScroll = (e)=>{
- 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)=>({
- ...prevState,
- viewablePageNumber : newPage
- }));
- };
-
const getCurrentPage = (e)=>{
const { scrollTop, clientHeight, scrollHeight } = e.target;
const totalScrollableHeight = scrollHeight - clientHeight;
const currentPageNumber = Math.ceil((scrollTop / totalScrollableHeight) * rawPages.length);
- handleScroll(e);
+ props.onPageChange(currentPageNumber);
setState((prevState)=>({
...prevState,
@@ -116,7 +102,6 @@ const BrewRenderer = (props)=>{
}));
};
-
const isInView = (index)=>{
if(!state.isMounted)
return false;
diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx
index e2b28cdc1..28dd6e6d7 100644
--- a/client/homebrew/editor/editor.jsx
+++ b/client/homebrew/editor/editor.jsx
@@ -23,9 +23,7 @@ const DEFAULT_STYLE_TEXT = dedent`
}`;
let lastPage = 0;
-let lockBrewJump = false;
-let lockSourceJump = false;
-let scrollingJump = false;
+let isJumping = false;
const isElementCodeMirror=(element)=>{
let el = element;
@@ -76,7 +74,6 @@ const Editor = createClass({
this.highlightCustomMarkdown();
window.addEventListener('resize', this.updateEditorSize);
document.getElementById('BrewRenderer').addEventListener('keydown', this.handleControlKeys);
- document.addEventListener('renderScrolled', this.handleBrewScroll);
document.addEventListener('keydown', this.handleControlKeys);
document.addEventListener('click', (e)=>{
if(isElementCodeMirror(e.target) && this.props.liveScroll ) {
@@ -112,6 +109,9 @@ const Editor = createClass({
if(prevProps.liveScroll != this.props.liveScroll) {
if((prevProps.liveScroll != undefined) && (this.props.liveScroll)) this.brewJump();
};
+ if(prevProps.currentBrewRendererPage !== this.props.currentBrewRendererPage) {
+ this.handleBrewScroll();
+ }
},
handleControlKeys : function(e){
@@ -149,17 +149,12 @@ const Editor = createClass({
handleBrewScroll : function() {
if(!this.props.liveScroll) return;
- scrollingJump = true;
- this.sourceJump();
- scrollingJump = false;
+ this.sourceJump(undefined, false);
},
handleSourceScroll : function() {
if(!this.props.liveScroll) return;
- console.log("handleSourceScroll")
- scrollingJump = true;
- this.brewJump(this.getCurrentPage(false));
- scrollingJump = false;
+ this.brewJump(this.getCurrentPage(false), false);
},
updateEditorSize : function() {
@@ -361,13 +356,10 @@ const Editor = createClass({
}
},
- brewJump : function(targetPage=this.getCurrentPage()){
- console.log(`jumpBrew to page ${targetPage}`)
- if(lockBrewJump) return;
+ brewJump : function(targetPage=this.getCurrentPage(), smooth=true){
+ if(isJumping) return;
if(!window) return;
- lockSourceJump = true;
- lockBrewJump = true;
- //console.log(`Scroll to: p${targetPage}`);
+
const brewRenderer = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer')[0];
const currentPos = brewRenderer.scrollTop;
const targetPos = window.frames['BrewRenderer'].contentDocument.getElementById(`p${targetPage}`).getBoundingClientRect().top;
@@ -376,9 +368,26 @@ const Editor = createClass({
const bounceDelay = 100;
const scrollDelay = 500;
- if(scrollingJump) {
- brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'instant', block: 'start' });
- } else {
+ if(Math.abs(targetPos) < 1)
+ return;
+
+ isJumping = true;
+
+ // Detect end of scroll event to avoid feedback loops
+ let scrollingTimeout;
+
+ const checkIfScrollComplete = () => {
+ clearTimeout(scrollingTimeout); // Reset the timer every time a scroll event occurs
+ scrollingTimeout = setTimeout(() => {
+ isJumping = false;
+ brewRenderer.removeEventListener('scroll', checkIfScrollComplete);
+ }, 150); // If 150 ms pass without a brewRenderer scroll event, assume scrolling is done
+ };
+
+ brewRenderer.addEventListener('scroll', checkIfScrollComplete);
+ console.log("added event listener")
+
+ if(smooth) {
if(!this.throttleBrewMove) {
this.throttleBrewMove = _.throttle((currentPos, interimPos, targetPos)=>{
brewRenderer.scrollTo({ top: currentPos + interimPos, behavior: 'smooth' });
@@ -388,35 +397,19 @@ const Editor = createClass({
}, scrollDelay, { leading: true, trailing: false });
};
this.throttleBrewMove(currentPos, interimPos, targetPos);
+ } else {
+ brewRenderer.scrollTo({ top: currentPos + targetPos, behavior: 'instant', block: 'start' });
}
- lockSourceJump = false;
- lockBrewJump = false;
-
- // const hashPage = (page != 1) ? `p${page}` : '';
- // window.location.hash = hashPage;
},
- sourceJump : function(targetLine=null){
- if(lockSourceJump) return;
+ sourceJump : function(targetLine=null, smooth=true){
+ if(isJumping) return;
if(this.isText()) {
if(targetLine == null) {
targetLine = 0;
- lockBrewJump = true;
- lockSourceJump = true;
-
- const pageCollection = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('page');
- const brewRendererHeight = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer').item(0).getBoundingClientRect().height;
-
- let currentPage = 1;
- for (const page of pageCollection) {
- if(page.getBoundingClientRect().bottom > (brewRendererHeight / 2)) {
- currentPage = parseInt(page.id.slice(1)) || 1;
- break;
- }
- }
const textSplit = this.props.renderer == 'V3' ? /^\\page$/gm : /\\page/;
- const textString = this.props.brew.text.split(textSplit).slice(0, currentPage-1).join(textSplit);
+ const textString = this.props.brew.text.split(textSplit).slice(0, this.props.currentBrewRendererPage-1).join(textSplit);
const textPosition = textString.length;
const lineCount = textString.match('\n') ? textString.slice(0, textPosition).split('\n').length : 0;
@@ -425,7 +418,25 @@ const Editor = createClass({
let currentY = this.codeEditor.current.codeMirror.getScrollInfo().top;
let targetY = this.codeEditor.current.codeMirror.heightAtLine(targetLine, 'local', true);
- if(!scrollingJump) {
+ if (Math.abs(targetY - currentY) < 1)
+ return;
+
+ isJumping = true;
+
+ // Detect end of scroll event to avoid feedback loops
+ let scrollingTimeout;
+
+ const checkIfScrollComplete = () => {
+ clearTimeout(scrollingTimeout); // Reset the timer every time a scroll event occurs
+ scrollingTimeout = setTimeout(() => {
+ isJumping = false;
+ this.codeEditor.current.codeMirror.off('scroll', checkIfScrollComplete);
+ }, 150); // If 150 ms pass without a scroll event, assume scrolling is done
+ };
+
+ this.codeEditor.current.codeMirror.on('scroll', checkIfScrollComplete);
+
+ if(smooth) {
//Scroll 1/10 of the way every 10ms until 1px off.
const incrementalScroll = setInterval(()=>{
currentY += (targetY - currentY) / 10;
@@ -441,16 +452,12 @@ const Editor = createClass({
this.codeEditor.current.setCursorPosition({ line: targetLine + 1, ch: 0 });
this.codeEditor.current.codeMirror.addLineClass(targetLine + 1, 'wrap', 'sourceMoveFlash');
clearInterval(incrementalScroll);
- lockBrewJump = false;
- lockSourceJump = false;
}
}, 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;
}
}
}
diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx
index 39a6d1931..e8afed322 100644
--- a/client/homebrew/pages/editPage/editPage.jsx
+++ b/client/homebrew/pages/editPage/editPage.jsx
@@ -41,22 +41,23 @@ const EditPage = createClass({
getInitialState : function() {
return {
- brew : this.props.brew,
- isSaving : false,
- isPending : false,
- alertTrashedGoogleBrew : this.props.brew.trashed,
- alertLoginToTransfer : false,
- saveGoogle : this.props.brew.googleId ? true : false,
- confirmGoogleTransfer : false,
- error : null,
- htmlErrors : Markdown.validate(this.props.brew.text),
- url : '',
- autoSave : true,
- autoSaveWarning : false,
- unsavedTime : new Date(),
- currentEditorPage : 0,
- displayLockMessage : this.props.brew.lock || false,
- themeBundle : {}
+ brew : this.props.brew,
+ isSaving : false,
+ isPending : false,
+ alertTrashedGoogleBrew : this.props.brew.trashed,
+ alertLoginToTransfer : false,
+ saveGoogle : this.props.brew.googleId ? true : false,
+ confirmGoogleTransfer : false,
+ error : null,
+ htmlErrors : Markdown.validate(this.props.brew.text),
+ url : '',
+ autoSave : true,
+ autoSaveWarning : false,
+ unsavedTime : new Date(),
+ currentEditorPage : 0,
+ currentBrewRendererPage : 0,
+ displayLockMessage : this.props.brew.lock || false,
+ themeBundle : {}
};
},
@@ -113,6 +114,10 @@ const EditPage = createClass({
this.editor.current.update();
},
+ handleBrewRendererPageChange : function(pageNumber){
+ this.setState(()=>({ currentBrewRendererPage : pageNumber }));
+ },
+
handleTextChange : function(text){
//If there are errors, run the validator on every change to give quick feedback
let htmlErrors = this.state.htmlErrors;
@@ -413,6 +418,7 @@ const EditPage = createClass({
renderer={this.state.brew.renderer}
userThemes={this.props.userThemes}
snippetBundle={this.state.themeBundle.snippets}
+ currentBrewRendererPage={this.state.currentBrewRendererPage}
/>
diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx
index 5b0f59c00..682c53654 100644
--- a/client/homebrew/pages/newPage/newPage.jsx
+++ b/client/homebrew/pages/newPage/newPage.jsx
@@ -39,13 +39,14 @@ const NewPage = createClass({
const brew = this.props.brew;
return {
- brew : brew,
- isSaving : false,
- saveGoogle : (global.account && global.account.googleId ? true : false),
- error : null,
- htmlErrors : Markdown.validate(brew.text),
- currentEditorPage : 0,
- themeBundle : {}
+ brew : brew,
+ isSaving : false,
+ saveGoogle : (global.account && global.account.googleId ? true : false),
+ error : null,
+ htmlErrors : Markdown.validate(brew.text),
+ currentEditorPage : 0,
+ currentBrewRendererPage : 0,
+ themeBundle : {}
};
},
@@ -108,6 +109,10 @@ const NewPage = createClass({
this.editor.current.update();
},
+ handleBrewRendererPageChange : function(pageNumber){
+ this.setState(()=>({ currentBrewRendererPage : pageNumber }));
+ },
+
handleTextChange : function(text){
//If there are errors, run the validator on every change to give quick feedback
let htmlErrors = this.state.htmlErrors;
@@ -221,6 +226,7 @@ const NewPage = createClass({
renderer={this.state.brew.renderer}
userThemes={this.props.userThemes}
snippetBundle={this.state.themeBundle.snippets}
+ currentBrewRendererPage={this.state.currentBrewRendererPage}
/>