diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 5f7772d55..d5565e748 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -1,7 +1,7 @@ /*eslint max-lines: ["warn", {"max": 300, "skipBlankLines": true, "skipComments": true}]*/ require('./brewRenderer.less'); const React = require('react'); -const { useState, useRef, useEffect } = React; +const { useState, useRef, useEffect, useCallback } = React; const _ = require('lodash'); const MarkdownLegacy = require('naturalcrit/markdownLegacy.js'); @@ -50,24 +50,25 @@ let rawPages = []; const BrewRenderer = (props)=>{ props = { - text : '', - style : '', - renderer : 'legacy', - theme : '5ePHB', - lang : '', - errors : [], - currentEditorPage : 0, - themeBundle : {}, - onPageChange : ()=>{}, + text : '', + style : '', + renderer : 'legacy', + theme : '5ePHB', + lang : '', + errors : [], + currentEditorCursorPageNum : 0, + currentEditorViewPageNum : 0, + currentBrewRendererPageNum : 0, + themeBundle : {}, + onPageChange : ()=>{}, ...props }; const [state, setState] = useState({ - height : PAGE_HEIGHT, - isMounted : false, - visibility : 'hidden', - zoom : 100, - currentPageNumber : 1, + height : PAGE_HEIGHT, + isMounted : false, + visibility : 'hidden', + zoom : 100 }); const mainRef = useRef(null); @@ -89,27 +90,22 @@ const BrewRenderer = (props)=>{ })); }; - const getCurrentPage = (e)=>{ + const updateCurrentPage = useCallback(_.throttle((e)=>{ const { scrollTop, clientHeight, scrollHeight } = e.target; const totalScrollableHeight = scrollHeight - clientHeight; - const currentPageNumber = Math.ceil((scrollTop / totalScrollableHeight) * rawPages.length); + const currentPageNumber = Math.ceil(((scrollTop + 1) / totalScrollableHeight) * rawPages.length); props.onPageChange(currentPageNumber); - - setState((prevState)=>({ - ...prevState, - currentPageNumber : currentPageNumber || 1 - })); - }; + }, 200), []); const isInView = (index)=>{ if(!state.isMounted) return false; - if(index == props.currentEditorPage) //Already rendered before this step + if(index == props.currentEditorCursorPageNum - 1) //Already rendered before this step return false; - if(Math.abs(index - state.currentPageNumber) <= 3) + if(Math.abs(index - props.currentBrewRendererPageNum - 1) <= 3) return true; return false; @@ -146,7 +142,7 @@ const BrewRenderer = (props)=>{ renderedPages.length = 0; // Render currently-edited page first so cross-page effects (variables, links) can propagate out first - renderedPages[props.currentEditorPage] = renderPage(rawPages[props.currentEditorPage], props.currentEditorPage); + renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1); _.forEach(rawPages, (page, index)=>{ if((isInView(index) || !renderedPages[index]) && typeof window !== 'undefined'){ @@ -196,7 +192,7 @@ const BrewRenderer = (props)=>{ <> {/*render dummy page while iFrame is mounting.*/} {!state.isMounted - ?
+ ?
{renderDummyPage(1)}
@@ -209,7 +205,7 @@ const BrewRenderer = (props)=>{
- + {/*render in iFrame so broken code doesn't crash the site.*/} { onClick={()=>{emitClick();}} >
diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 28dd6e6d7..461d43e23 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -49,9 +49,16 @@ const Editor = createClass({ onStyleChange : ()=>{}, onMetaChange : ()=>{}, reportError : ()=>{}, + + onCursorPageChange : ()=>{}, + onViewPageChange : ()=>{}, editorTheme : 'default', - renderer : 'legacy' + renderer : 'legacy', + + currentEditorCursorPageNum : 0, + currentEditorViewPageNum : 0, + currentBrewRendererPageNum : 0, }; }, getInitialState : function() { @@ -75,6 +82,9 @@ const Editor = createClass({ window.addEventListener('resize', this.updateEditorSize); document.getElementById('BrewRenderer').addEventListener('keydown', this.handleControlKeys); document.addEventListener('keydown', this.handleControlKeys); + + this.codeEditor.current.codeMirror.on('cursorActivity', (cm)=>{this.updateCurrentCursorPage(cm.getCursor())}); + this.codeEditor.current.codeMirror.on('scroll', _.throttle(()=>{this.updateCurrentViewPage(this.codeEditor.current.getTopVisibleLine())}, 200)); document.addEventListener('click', (e)=>{ if(isElementCodeMirror(e.target) && this.props.liveScroll ) { const curPage = this.getCurrentPage(); @@ -165,6 +175,20 @@ const Editor = createClass({ } }, + updateCurrentCursorPage : function(cursor) { + const lines = this.props.brew.text.split('\n').slice(0, cursor.line + 1); + const pageRegex = this.props.brew.renderer == 'V3' ? /^\\page$/ : /\\page/; + const currentPage = lines.reduce((count, line) => count + (pageRegex.test(line) ? 1 : 0), 1); + this.props.onCursorPageChange(currentPage); + }, + + updateCurrentViewPage : function(topScrollLine) { + const lines = this.props.brew.text.split('\n').slice(0, topScrollLine + 1); + const pageRegex = this.props.brew.renderer == 'V3' ? /^\\page$/ : /\\page/; + const currentPage = lines.reduce((count, line) => count + (pageRegex.test(line) ? 1 : 0), 1); + this.props.onViewPageChange(currentPage); + }, + handleInject : function(injectText){ this.codeEditor.current?.injectText(injectText, false); }, @@ -179,23 +203,6 @@ const Editor = createClass({ }); //TODO: not sure if updateeditorsize needed }, - getCurrentPage : function(atCursor = true){ - let lines = this.props.brew.text.split('\n'); - if (atCursor) - lines = lines.slice(0, this.codeEditor.current.getCursorPosition().line + 1); // get cursor page - else - lines = lines.slice(0, this.codeEditor.current.getTopVisibleLine() + 1); // get view page - - return _.reduce(lines, (r, line)=>{ - if( - (this.props.renderer == 'legacy' && line.indexOf('\\page') !== -1) - || - (this.props.renderer == 'V3' && line.match(/^\\page$/)) - ) r++; - return r; - }, 1); - }, - highlightCustomMarkdown : function(){ if(!this.codeEditor.current) return; if(this.state.view === 'text') { @@ -204,7 +211,7 @@ const Editor = createClass({ codeMirror.operation(()=>{ // Batch CodeMirror styling const foldLines = []; - + //reset custom text styles const customHighlights = codeMirror.getAllMarks().filter((mark)=>{ // Record details of folded sections @@ -356,10 +363,10 @@ const Editor = createClass({ } }, - brewJump : function(targetPage=this.getCurrentPage(), smooth=true){ + brewJump : function(targetPage=this.props.currentEditorCursorPageNum, smooth=true){ if(isJumping) return; if(!window) return; - + // Get current brewRenderer scroll position and calculate target position const brewRenderer = window.frames['BrewRenderer'].contentDocument.getElementsByClassName('brewRenderer')[0]; const currentPos = brewRenderer.scrollTop; const targetPos = window.frames['BrewRenderer'].contentDocument.getElementById(`p${targetPage}`).getBoundingClientRect().top; @@ -409,7 +416,7 @@ const Editor = createClass({ targetLine = 0; const textSplit = this.props.renderer == 'V3' ? /^\\page$/gm : /\\page/; - const textString = this.props.brew.text.split(textSplit).slice(0, this.props.currentBrewRendererPage-1).join(textSplit); + const textString = this.props.brew.text.split(textSplit).slice(0, this.props.currentBrewRendererPageNum-1).join(textSplit); const textPosition = textString.length; const lineCount = textString.match('\n') ? textString.slice(0, textPosition).split('\n').length : 0; @@ -489,7 +496,8 @@ const Editor = createClass({ view={this.state.view} value={this.props.brew.text} onChange={this.props.onTextChange} - onScroll={this.handleSourceScroll} + onCursorActivity={this.props.onCursorActivity} + onScroll={this.props.onPageChange} editorTheme={this.state.editorTheme} rerenderParent={this.rerenderParent} /> ; diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index e8afed322..e6a67e414 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -1,8 +1,9 @@ /* eslint-disable max-lines */ require('./editPage.less'); const React = require('react'); -const createClass = require('create-react-class'); const _ = require('lodash'); +const createClass = require('create-react-class'); + const request = require('../../utils/request-middleware.js'); const { Meta } = require('vitreum/headtags'); @@ -41,23 +42,24 @@ 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, - currentBrewRendererPage : 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(), + currentEditorViewPageNum : 0, + currentEditorCursorPageNum : 0, + currentBrewRendererPageNum : 0, + displayLockMessage : this.props.brew.lock || false, + themeBundle : {} }; }, @@ -114,20 +116,31 @@ const EditPage = createClass({ this.editor.current.update(); }, + handleEditorViewPageChange : function(pageNumber){ + console.log(`editor view : ${pageNumber}`); + this.setState({ currentEditorViewPageNum: pageNumber }); + }, + + handleEditorCursorPageChange : function(pageNumber){ + console.log(`editor cursor : ${pageNumber}`); + this.setState({ currentEditorCursorPageNum: pageNumber }); + }, + handleBrewRendererPageChange : function(pageNumber){ - this.setState(()=>({ currentBrewRendererPage : pageNumber })); + console.log(`brewRenderer view : ${pageNumber}`); + this.setState({ currentBrewRendererPageNum: pageNumber }); }, handleTextChange : function(text){ //If there are errors, run the validator on every change to give quick feedback + console.log('text change'); let htmlErrors = this.state.htmlErrors; if(htmlErrors.length) htmlErrors = Markdown.validate(text); this.setState((prevState)=>({ - brew : { ...prevState.brew, text: text }, - isPending : true, - htmlErrors : htmlErrors, - currentEditorPage : this.editor.current.getCurrentPage() - 1 //Offset index since Marked starts pages at 0 + brew : { ...prevState.brew, text: text }, + isPending : true, + htmlErrors : htmlErrors, }), ()=>{if(this.state.autoSave) this.trySave();}); }, @@ -418,7 +431,11 @@ const EditPage = createClass({ renderer={this.state.brew.renderer} userThemes={this.props.userThemes} snippetBundle={this.state.themeBundle.snippets} - currentBrewRendererPage={this.state.currentBrewRendererPage} + onCursorPageChange={this.handleEditorCursorPageChange} + onViewPageChange={this.handleEditorViewPageChange} + currentEditorViewPageNum={this.state.currentEditorViewPageNum} + currentEditorCursorPageNum={this.state.currentEditorCursorPageNum} + currentBrewRendererPageNum={this.state.currentBrewRendererPageNum} /> diff --git a/client/homebrew/pages/homePage/homePage.jsx b/client/homebrew/pages/homePage/homePage.jsx index d7efcaf14..6e11806bd 100644 --- a/client/homebrew/pages/homePage/homePage.jsx +++ b/client/homebrew/pages/homePage/homePage.jsx @@ -1,7 +1,6 @@ require('./homePage.less'); const React = require('react'); const createClass = require('create-react-class'); -const _ = require('lodash'); const cx = require('classnames'); const request = require('../../utils/request-middleware.js'); const { Meta } = require('vitreum/headtags'); @@ -32,11 +31,13 @@ const HomePage = createClass({ }, getInitialState : function() { return { - brew : this.props.brew, - welcomeText : this.props.brew.text, - error : undefined, - currentEditorPage : 0, - themeBundle : {} + brew : this.props.brew, + welcomeText : this.props.brew.text, + error : undefined, + currentEditorViewPageNum : 0, + currentEditorCursorPageNum : 0, + currentBrewRendererPageNum : 0, + themeBundle : {} }; }, @@ -61,10 +62,25 @@ const HomePage = createClass({ handleSplitMove : function(){ this.editor.current.update(); }, + + handleEditorViewPageChange : function(pageNumber){ + console.log(`editor view : ${pageNumber}`); + this.setState({ currentEditorViewPageNum: pageNumber }); + }, + + handleEditorCursorPageChange : function(pageNumber){ + console.log(`editor cursor : ${pageNumber}`); + this.setState({ currentEditorCursorPageNum: pageNumber }); + }, + + handleBrewRendererPageChange : function(pageNumber){ + console.log(`brewRenderer view : ${pageNumber}`); + this.setState({ currentBrewRendererPageNum: pageNumber }); + }, + handleTextChange : function(text){ this.setState((prevState)=>({ - brew : { ...prevState.brew, text: text }, - currentEditorPage : this.editor.current.getCurrentPage() - 1 //Offset index since Marked starts pages at 0 + brew : { ...prevState.brew, text: text }, })); }, renderNavbar : function(){ @@ -97,12 +113,20 @@ const HomePage = createClass({ renderer={this.state.brew.renderer} showEditButtons={false} snippetBundle={this.state.themeBundle.snippets} + onCursorPageChange={this.handleEditorCursorPageChange} + onViewPageChange={this.handleEditorViewPageChange} + currentEditorViewPageNum={this.state.currentEditorViewPageNum} + currentEditorCursorPageNum={this.state.currentEditorCursorPageNum} + currentBrewRendererPageNum={this.state.currentBrewRendererPageNum} /> diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 682c53654..115f4ea88 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -39,14 +39,15 @@ 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, - currentBrewRendererPage : 0, - themeBundle : {} + brew : brew, + isSaving : false, + saveGoogle : (global.account && global.account.googleId ? true : false), + error : null, + htmlErrors : Markdown.validate(brew.text), + currentEditorViewPageNum : 0, + currentEditorCursorPageNum : 0, + currentBrewRendererPageNum : 0, + themeBundle : {} }; }, @@ -109,8 +110,19 @@ const NewPage = createClass({ this.editor.current.update(); }, + handleEditorViewPageChange : function(pageNumber){ + console.log(`editor view : ${pageNumber}`); + this.setState({ currentEditorViewPageNum: pageNumber }); + }, + + handleEditorCursorPageChange : function(pageNumber){ + console.log(`editor cursor : ${pageNumber}`); + this.setState({ currentEditorCursorPageNum: pageNumber }); + }, + handleBrewRendererPageChange : function(pageNumber){ - this.setState(()=>({ currentBrewRendererPage : pageNumber })); + console.log(`brewRenderer view : ${pageNumber}`); + this.setState({ currentBrewRendererPageNum: pageNumber }); }, handleTextChange : function(text){ @@ -119,9 +131,8 @@ const NewPage = createClass({ if(htmlErrors.length) htmlErrors = Markdown.validate(text); this.setState((prevState)=>({ - brew : { ...prevState.brew, text: text }, - htmlErrors : htmlErrors, - currentEditorPage : this.editor.current.getCurrentPage() - 1 //Offset index since Marked starts pages at 0 + brew : { ...prevState.brew, text: text }, + htmlErrors : htmlErrors, })); localStorage.setItem(BREWKEY, text); }, @@ -226,7 +237,11 @@ const NewPage = createClass({ renderer={this.state.brew.renderer} userThemes={this.props.userThemes} snippetBundle={this.state.themeBundle.snippets} - currentBrewRendererPage={this.state.currentBrewRendererPage} + onCursorPageChange={this.handleEditorCursorPageChange} + onViewPageChange={this.handleEditorViewPageChange} + currentEditorViewPageNum={this.state.currentEditorViewPageNum} + currentEditorCursorPageNum={this.state.currentEditorCursorPageNum} + currentBrewRendererPageNum={this.state.currentBrewRendererPageNum} /> diff --git a/package-lock.json b/package-lock.json index aafcf1869..06c4350ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "dedent-tabs": "^0.10.3", "dompurify": "^3.1.6", "expr-eval": "^2.0.2", - "express": "^4.20.0", + "express": "^4.21.0", "express-async-handler": "^1.2.0", "express-static-gzip": "2.1.7", "fs-extra": "11.2.0", @@ -38,7 +38,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.6.1", + "mongoose": "^8.6.2", "nanoid": "3.3.4", "nconf": "^0.12.1", "react": "^18.3.1", @@ -53,7 +53,7 @@ "@stylistic/stylelint-plugin": "^3.0.1", "eslint": "^9.10.0", "eslint-plugin-jest": "^28.8.3", - "eslint-plugin-react": "^7.35.2", + "eslint-plugin-react": "^7.36.1", "globals": "^15.9.0", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", @@ -4177,20 +4177,6 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, - "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -5614,10 +5600,9 @@ "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } @@ -5928,9 +5913,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.35.2", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.35.2.tgz", - "integrity": "sha512-Rbj2R9zwP2GYNcIak4xoAMV57hrBh3hTaR0k7hVjwCQgryE/pw5px4b13EYjduOI0hfXyZhwBxaGpOTbWSGzKQ==", + "version": "7.36.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz", + "integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==", "dev": true, "dependencies": { "array-includes": "^3.1.8", @@ -6330,9 +6315,9 @@ "license": "MIT" }, "node_modules/express": { - "version": "4.20.0", - "resolved": "https://registry.npmjs.org/express/-/express-4.20.0.tgz", - "integrity": "sha512-pLdae7I6QqShF5PnNTCVn4hI91Dx0Grkn2+IAsMTgMIKuQVte2dN9PeGSSAME2FR8anOhVA62QDIUaWVfEXVLw==", + "version": "4.21.0", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.0.tgz", + "integrity": "sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -6346,7 +6331,7 @@ "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", "merge-descriptors": "1.0.3", @@ -6355,11 +6340,11 @@ "parseurl": "~1.3.3", "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", "send": "0.19.0", - "serve-static": "1.16.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -6403,56 +6388,12 @@ "ms": "2.0.0" } }, - "node_modules/express/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/express/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "license": "MIT" }, - "node_modules/express/node_modules/send": { - "version": "0.19.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", - "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/express/node_modules/send/node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -6642,13 +6583,12 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "license": "MIT", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -6663,7 +6603,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -6671,8 +6610,7 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-up": { "version": "5.0.0", @@ -10864,9 +10802,9 @@ } }, "node_modules/mongoose": { - "version": "8.6.1", - "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.1.tgz", - "integrity": "sha512-dppGcYqvsdg+VcnqXR5b467V4a+iNhmvkfYNpEPi6AjaUxnz6ioEDmrMLOi+sOWjvoHapuwPOigV4f2l7HC6ag==", + "version": "8.6.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.2.tgz", + "integrity": "sha512-ErbDVvuUzUfyQpXvJ6sXznmZDICD8r6wIsa0VKjJtB6/LZncqwUn5Um040G1BaNo6L3Jz+xItLSwT0wZmSmUaQ==", "dependencies": { "bson": "^6.7.0", "kareem": "2.6.3", @@ -12143,12 +12081,11 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "license": "BSD-3-Clause", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -12790,10 +12727,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "license": "MIT", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -12817,7 +12753,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -12825,24 +12760,30 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/serve-static": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.0.tgz", - "integrity": "sha512-pDLK8zwl2eKaYrs8mrPZBJua4hMplRWJ1tIFksVC3FtBEBnl8dxgeHtsaMS8DhS9i4fLObaon6ABoc4/hQGdPA==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -14684,21 +14625,6 @@ "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "license": "MIT" }, - "node_modules/url/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.0.6" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", diff --git a/package.json b/package.json index f05fb8f03..f760cc096 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "dedent-tabs": "^0.10.3", "dompurify": "^3.1.6", "expr-eval": "^2.0.2", - "express": "^4.20.0", + "express": "^4.21.0", "express-async-handler": "^1.2.0", "express-static-gzip": "2.1.7", "fs-extra": "11.2.0", @@ -113,7 +113,7 @@ "marked-smartypants-lite": "^1.0.2", "markedLegacy": "npm:marked@^0.3.19", "moment": "^2.30.1", - "mongoose": "^8.6.1", + "mongoose": "^8.6.2", "nanoid": "3.3.4", "nconf": "^0.12.1", "react": "^18.3.1", @@ -128,7 +128,7 @@ "@stylistic/stylelint-plugin": "^3.0.1", "eslint": "^9.10.0", "eslint-plugin-jest": "^28.8.3", - "eslint-plugin-react": "^7.35.2", + "eslint-plugin-react": "^7.36.1", "globals": "^15.9.0", "jest": "^29.7.0", "jest-expect-message": "^1.1.3", diff --git a/shared/naturalcrit/codeEditor/codeEditor.jsx b/shared/naturalcrit/codeEditor/codeEditor.jsx index ac930177a..06f6ba0c2 100644 --- a/shared/naturalcrit/codeEditor/codeEditor.jsx +++ b/shared/naturalcrit/codeEditor/codeEditor.jsx @@ -49,13 +49,12 @@ const CodeEditor = createClass({ displayName : 'CodeEditor', getDefaultProps : function() { return { - language : '', - value : '', - wrap : true, - onChange : ()=>{}, - onscroll : ()=>{}, - enableFolding : true, - editorTheme : 'default' + language : '', + value : '', + wrap : true, + onChange : ()=>{}, + enableFolding : true, + editorTheme : 'default' }; }, @@ -190,8 +189,7 @@ const CodeEditor = createClass({ autoCompleteEmoji.showAutocompleteEmoji(CodeMirror, this.codeMirror); // 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('scroll', _.throttle(this.props.onScroll, 200)); + this.codeMirror.on('change', (cm)=>{this.props.onChange(cm.getValue())}); this.updateSize(); }, @@ -401,7 +399,7 @@ const CodeEditor = createClass({ }, getTopVisibleLine : function(){ const rect = this.codeMirror.getWrapperElement().getBoundingClientRect(); - const topVisibleLine = this.codeMirror.lineAtHeight(rect.top, "window"); + const topVisibleLine = this.codeMirror.lineAtHeight(rect.top, "window"); return topVisibleLine; }, updateSize : function(){