diff --git a/client/homebrew/pages/basePages/editorPage/editorPage.jsx b/client/homebrew/pages/basePages/editorPage/editorPage.jsx deleted file mode 100644 index 99a5c2b52..000000000 --- a/client/homebrew/pages/basePages/editorPage/editorPage.jsx +++ /dev/null @@ -1,578 +0,0 @@ -/* eslint-disable max-lines */ -require('./editorPage.less'); -const React = require('react'); -const createClass = require('create-react-class'); -const _ = require('lodash'); -const request = require('superagent'); -const { Meta } = require('vitreum/headtags'); - -const Nav = require('naturalcrit/nav/nav.jsx'); -const Navbar = require('../../../navbar/navbar.jsx'); - -const NewBrew = require('../../../navbar/newbrew.navitem.jsx'); -const ReportIssue = require('../../../navbar/issue.navitem.jsx'); -const PrintLink = require('../../../navbar/print.navitem.jsx'); -const Account = require('../../../navbar/account.navitem.jsx'); -const RecentNavItem = require('../../../navbar/recent.navitem.jsx').both; - -const SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); -const Editor = require('../../../editor/editor.jsx'); -const BrewRenderer = require('../../../brewRenderer/brewRenderer.jsx'); - -const Markdown = require('naturalcrit/markdown.js'); - -const googleDriveActive = require('../../../googleDrive.png'); -const googleDriveInactive = require('../../../googleDriveMono.png'); - -const SAVE_TIMEOUT = 3000; - -const BREWKEY = 'homebrewery-new'; -const STYLEKEY = 'homebrewery-new-style'; -const METAKEY = 'homebrewery-new-meta'; - -const EditorPage = createClass({ - getDefaultProps : function() { - return { - brew : { - text : '', - style : '', - shareId : null, - editId : null, - createdAt : null, - updatedAt : null, - gDrive : false, - trashed : false, - - title : '', - description : '', - tags : '', - published : false, - authors : [], - systems : [], - renderer : 'legacy' - }, - pageType : 'edit', - googleDriveOptions : [ - 'DRIVE > HB', - 'HB > DRIVE' - ] - }; - }, - - 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, - errors : null, - htmlErrors : Markdown.validate(this.props.brew.text), - url : '' - }; - // return { - // brew : { - // text : brew.text || '', - // style : brew.style || undefined, - // gDrive : false, - // title : brew.title || '', - // description : brew.description || '', - // tags : brew.tags || '', - // published : false, - // authors : [], - // systems : brew.systems || [], - // renderer : brew.renderer || 'legacy' - // }, - - // isSaving : false, - // isPending : false, - // alertTrashedGoogleBrew : this.props.brew.trashed, - // alertLoginToTransfer : false, - // saveGoogle : (global.account && global.account.googleId ? true : false), - // confirmGoogleTransfer : false, - // errors : null, - // htmlErrors : Markdown.validate(brew.text), - // url : '' - // }; - }, - savedBrew : null, - - componentDidMount : function(){ - this.setState({ - url : window.location.href - }); - - this.savedBrew = JSON.parse(JSON.stringify(this.props.brew)); //Deep copy - - this.trySave(); - window.onbeforeunload = ()=>{ - if(this.state.isSaving || this.state.isPending){ - return 'You have unsaved changes!'; - } - }; - - this.setState((prevState)=>({ - htmlErrors : Markdown.validate(prevState.brew.text) - })); - - document.addEventListener('keydown', this.handleControlKeys); - }, - componentWillUnmount : function() { - window.onbeforeunload = function(){}; - document.removeEventListener('keydown', this.handleControlKeys); - }, - - handleControlKeys : function(e){ - if(!(e.ctrlKey || e.metaKey)) return; - const S_KEY = 83; - const P_KEY = 80; - if(e.keyCode == S_KEY) this.save(); - if(e.keyCode == P_KEY) window.open(`/print/${this.processShareId()}?dialog=true`, '_blank').focus(); - if(e.keyCode == P_KEY || e.keyCode == S_KEY){ - e.stopPropagation(); - e.preventDefault(); - } - }, - - isEdit : function(){ - return this.props.pageType == 'edit'; - }, - - isNew : function(){ - return this.props.pageType == 'new'; - }, - - handleSplitMove : function(){ - this.refs.editor.update(); - }, - - handleTextChange : function(text){ - //If there are errors, run the validator on every change to give quick feedback - let htmlErrors = this.state.htmlErrors; - if(htmlErrors.length) htmlErrors = Markdown.validate(text); - - this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, { text: text }), - isPending : true, - htmlErrors : htmlErrors - }), ()=>this.trySave()); - }, - - handleStyleChange : function(style){ - this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, { style: style }), - isPending : true - }), ()=>this.trySave()); - }, - - handleMetaChange : function(metadata){ - this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, metadata), - isPending : true, - }), ()=>this.trySave()); - - }, - - hasChanges : function(){ - return !_.isEqual(this.state.brew, this.savedBrew); - }, - - trySave : function(){ - if(!this.isEdit()) return; - if(!this.debounceSave) this.debounceSave = _.debounce(this.save, SAVE_TIMEOUT); - if(this.hasChanges()){ - this.debounceSave(); - } else { - this.debounceSave.cancel(); - } - }, - - handleGoogleClick : function(){ - if(!global.account?.googleId) { - this.setState({ - alertLoginToTransfer : true - }); - return; - } - this.setState((prevState)=>({ - confirmGoogleTransfer : !prevState.confirmGoogleTransfer - })); - this.clearErrors(); - }, - - closeAlerts : function(event){ - event.stopPropagation(); //Only handle click once so alert doesn't reopen - this.setState({ - alertTrashedGoogleBrew : false, - alertLoginToTransfer : false, - confirmGoogleTransfer : false - }); - }, - - toggleGoogleStorage : function(){ - this.setState((prevState)=>({ - saveGoogle : !prevState.saveGoogle, - isSaving : false, - errors : null - }), ()=>this.isEdit() && this.save()); - }, - - clearErrors : function(){ - this.setState({ - errors : null, - isSaving : false - - }); - }, - - save : async function(){ - this.setState((prevState)=>({ - isSaving : true, - errors : null, - htmlErrors : Markdown.validate(prevState.brew.text) - })); - - if(this.isEdit()){ - if(this.debounceSave && this.debounceSave.cancel) this.debounceSave.cancel(); - - const transfer = this.state.saveGoogle == _.isNil(this.state.brew.googleId); - - const brew = this.state.brew; - brew.pageCount = ((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1; - - if(this.state.saveGoogle) { - if(transfer) { - const res = await request - .post('/api/newGoogle/') - .send(brew) - .catch((err)=>{ - console.log(err.status === 401 - ? 'Not signed in!' - : 'Error Transferring to Google!'); - this.setState({ errors: err, saveGoogle: false }); - }); - - if(!res) { return; } - - console.log('Deleting Local Copy'); - await request.delete(`/api/${brew.editId}`) - .send() - .catch((err)=>{ - console.log('Error deleting Local Copy'); - }); - - this.savedBrew = res.body; - history.replaceState(null, null, `/edit/${this.savedBrew.googleId}${this.savedBrew.editId}`); //update URL to match doc ID - } else { - const res = await request - .put(`/api/updateGoogle/${brew.editId}`) - .send(brew) - .catch((err)=>{ - console.log(err.status === 401 - ? 'Not signed in!' - : 'Error Saving to Google!'); - this.setState({ errors: err }); - return; - }); - - this.savedBrew = res.body; - } - } else { - if(transfer) { - const res = await request.post('/api') - .send(brew) - .catch((err)=>{ - console.log('Error creating Local Copy'); - this.setState({ errors: err }); - return; - }); - - await request.get(`/api/removeGoogle/${brew.googleId}${brew.editId}`) - .send() - .catch((err)=>{ - console.log('Error Deleting Google Brew'); - }); - - this.savedBrew = res.body; - history.replaceState(null, null, `/edit/${this.savedBrew.editId}`); //update URL to match doc ID - } else { - const res = await request - .put(`/api/update/${brew.editId}`) - .send(brew) - .catch((err)=>{ - console.log('Error Updating Local Brew'); - this.setState({ errors: err }); - return; - }); - - this.savedBrew = res.body; - } - } - - this.setState((prevState)=>({ - brew : _.merge({}, prevState.brew, { - googleId : this.savedBrew.googleId ? this.savedBrew.googleId : null, - editId : this.savedBrew.editId, - shareId : this.savedBrew.shareId - }), - isPending : false, - isSaving : false, - })); - } - - if(this.isNew()){ - console.log('saving new brew'); - - let brew = this.state.brew; - // Split out CSS to Style if CSS codefence exists - if(brew.text.startsWith('```css') && brew.text.indexOf('```\n\n') > 0) { - const index = brew.text.indexOf('```\n\n'); - brew.style = `${brew.style ? `${brew.style}\n` : ''}${brew.text.slice(7, index - 1)}`; - brew.text = brew.text.slice(index + 5); - }; - - brew.pageCount=((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1; - - if(this.state.saveGoogle) { - const res = await request - .post('/api/newGoogle/') - .send(brew) - .catch((err)=>{ - console.log(err.status === 401 - ? 'Not signed in!' - : 'Error Creating New Google Brew!'); - this.setState({ isSaving: false, errors: err }); - return; - }); - - brew = res.body; - localStorage.removeItem(BREWKEY); - localStorage.removeItem(STYLEKEY); - localStorage.removeItem(METAKEY); - window.location = `/edit/${brew.googleId}${brew.editId}`; - } else { - request.post('/api') - .send(brew) - .end((err, res)=>{ - if(err){ - this.setState({ - isSaving : false - }); - return; - } - window.onbeforeunload = function(){}; - brew = res.body; - localStorage.removeItem(BREWKEY); - localStorage.removeItem(STYLEKEY); - localStorage.removeItem(METAKEY); - window.location = `/edit/${brew.editId}`; - }); - } - } - }, - - renderGoogleDriveIcon : function(){ - return - {this.state.saveGoogle - ? googleDriveActive - : googleDriveInactive - } - - {this.state.confirmGoogleTransfer && -
- { this.state.saveGoogle - ? this.props.googleDriveOptions[0] - : this.props.googleDriveOptions[1] - } -
-
- Yes -
-
- No -
-
- } - - {this.state.alertLoginToTransfer && -
- You must be signed in to a Google account to transfer - between the homebrewery and Google Drive! - -
- Sign In -
-
-
- Not Now -
-
- } -
; - }, - - renderSaveButton : function(){ - if(this.state.errors){ - let errMsg = ''; - try { - errMsg += `${this.state.errors.toString()}\n\n`; - errMsg += `\`\`\`\n${this.state.errors.stack}\n`; - errMsg += `${JSON.stringify(this.state.errors.response.error, null, ' ')}\n\`\`\``; - console.log(errMsg); - } catch (e){} - - if(this.state.errors.status == '401'){ - return - Oops! -
- You must be signed in to a Google account - to save this to
Google Drive!
- -
- Sign In -
-
-
- Not Now -
-
-
; - } - - if(this.state.errors.status == '403' && this.state.errors.response.body.errors[0].reason == 'insufficientPermissions'){ - return - Oops! -
- Looks like your Google credentials have - expired! Visit the log in page to sign out - and sign back in with Google - to save this to Google Drive! - -
- Sign In -
-
-
- Not Now -
-
-
; - } - - return - Oops! -
- Looks like there was a problem saving.
- Report the issue - here - . -
-
; - } - - if(this.state.isSaving){ - return saving...; - } - if(this.state.isPending && this.hasChanges()){ - return Save Now; - } - if(!this.state.isPending && !this.state.isSaving){ - return saved.; - } - }, - - processShareId : function() { - return this.state.brew.googleId ? - this.state.brew.googleId + this.state.brew.shareId : - this.state.brew.shareId; - }, - - getRedditLink : function(){ - - const shareLink = this.processShareId(); - const systems = this.props.brew.systems.length > 0 ? ` [${this.props.brew.systems.join(' - ')}]` : ''; - const title = `${this.props.brew.title} ${systems}`; - const text = `Hey guys! I've been working on this homebrew. I'd love your feedback. Check it out. - -**[Homebrewery Link](https://homebrewery.naturalcrit.com/share/${shareLink})**`; - - return `https://www.reddit.com/r/UnearthedArcana/submit?title=${encodeURIComponent(title)}&text=${encodeURIComponent(text)}`; - }, - - renderNavbar : function(){ - const shareLink = this.processShareId(); - - return - - {this.state.alertTrashedGoogleBrew && -
- This brew is currently in your Trash folder on Google Drive!
If you want to keep it, make sure to move it before it is deleted permanently!
-
- OK -
-
- } - - - {this.state.brew.title} - - - - {this.renderGoogleDriveIcon()} - {this.renderSaveButton()} - - - {this.isEdit() && <> - - - share - - - view - - {navigator.clipboard.writeText(`https://homebrewery.naturalcrit.com/share/${shareLink}`);}}> - copy url - - - post to reddit - - - - - } - - - - -
; - }, - - render : function(){ - return
- - {this.renderNavbar()} - -
- - - - -
-
; - } -}); - -module.exports = EditorPage; diff --git a/client/homebrew/pages/basePages/editorPage/editorPage.less b/client/homebrew/pages/basePages/editorPage/editorPage.less deleted file mode 100644 index 0cbfadcbd..000000000 --- a/client/homebrew/pages/basePages/editorPage/editorPage.less +++ /dev/null @@ -1,99 +0,0 @@ -@keyframes glideDown { - 0% {transform : translate(-50% + 3px, 0px); - opacity : 0;} - 100% {transform : translate(-50% + 3px, 10px); - opacity : 1;} -} -.editPage{ - .navItem.save{ - width : 106px; - text-align : center; - position : relative; - &.saved{ - cursor : initial; - color : #666; - } - &.error{ - position : relative; - background-color : @red; - } - } - .googleDriveStorage { - position : relative; - } - .googleDriveStorage img{ - height : 20px; - padding : 0px; - margin : -5px; - } - .errorContainer{ - animation-name: glideDown; - animation-duration: 0.4s; - position : absolute; - top : 100%; - left : 50%; - z-index : 100000; - width : 140px; - padding : 3px; - color : white; - background-color : #333; - border : 3px solid #444; - border-radius : 5px; - transform : translate(-50% + 3px, 10px); - text-align : center; - font-size : 10px; - font-weight : 800; - text-transform : uppercase; - a{ - color : @teal; - } - &:before { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #444; - left: 53px; - top: -23px; - } - &:after { - content: ""; - width: 0px; - height: 0px; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 10px solid transparent; - border-bottom: 10px solid #333; - left: 53px; - top: -19px; - } - .deny { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - border-left : 1px solid #666; - .animate(background-color); - &:hover{ - background-color : red; - } - } - .confirm { - width : 48%; - margin : 1px; - padding : 5px; - background-color : #333; - display : inline-block; - color : white; - .animate(background-color); - &:hover{ - background-color : teal; - } - } - } -} diff --git a/client/homebrew/pages/editPage/editPage.jsx b/client/homebrew/pages/editPage/editPage.jsx index 8e70cee32..ee4f41f5b 100644 --- a/client/homebrew/pages/editPage/editPage.jsx +++ b/client/homebrew/pages/editPage/editPage.jsx @@ -3,8 +3,28 @@ require('./editPage.less'); const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); +const request = require('superagent'); +const { Meta } = require('vitreum/headtags'); -const EditorPage = require('../basePages/editorPage/editorPage.jsx'); +const Nav = require('naturalcrit/nav/nav.jsx'); +const Navbar = require('../../navbar/navbar.jsx'); + +const NewBrew = require('../../navbar/newbrew.navitem.jsx'); +const ReportIssue = require('../../navbar/issue.navitem.jsx'); +const PrintLink = require('../../navbar/print.navitem.jsx'); +const Account = require('../../navbar/account.navitem.jsx'); +const RecentNavItem = require('../../navbar/recent.navitem.jsx').both; + +const SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); +const Editor = require('../../editor/editor.jsx'); +const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); + +const Markdown = require('naturalcrit/markdown.js'); + +const googleDriveActive = require('../../googleDrive.png'); +const googleDriveInactive = require('../../googleDriveMono.png'); + +const SAVE_TIMEOUT = 3000; const EditPage = createClass({ getDefaultProps : function() { @@ -30,17 +50,431 @@ const EditPage = createClass({ }; }, - render : function(){ - const googleDriveOptions = [ - 'Would you like to transfer this brew from your Google Drive storage back to the Homebrewery?', - 'Would you like to transfer this brew from the Homebrewery to your personal Google Drive storage?' - ]; + 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, + errors : null, + htmlErrors : Markdown.validate(this.props.brew.text), + url : '' + }; + }, + savedBrew : null, - return ; + componentDidMount : function(){ + this.setState({ + url : window.location.href + }); + + this.savedBrew = JSON.parse(JSON.stringify(this.props.brew)); //Deep copy + + this.trySave(); + window.onbeforeunload = ()=>{ + if(this.state.isSaving || this.state.isPending){ + return 'You have unsaved changes!'; + } + }; + + this.setState((prevState)=>({ + htmlErrors : Markdown.validate(prevState.brew.text) + })); + + document.addEventListener('keydown', this.handleControlKeys); + }, + componentWillUnmount : function() { + window.onbeforeunload = function(){}; + document.removeEventListener('keydown', this.handleControlKeys); + }, + + handleControlKeys : function(e){ + if(!(e.ctrlKey || e.metaKey)) return; + const S_KEY = 83; + const P_KEY = 80; + if(e.keyCode == S_KEY) this.save(); + if(e.keyCode == P_KEY) window.open(`/print/${this.processShareId()}?dialog=true`, '_blank').focus(); + if(e.keyCode == P_KEY || e.keyCode == S_KEY){ + e.stopPropagation(); + e.preventDefault(); + } + }, + + handleSplitMove : function(){ + this.refs.editor.update(); + }, + + handleTextChange : function(text){ + //If there are errors, run the validator on every change to give quick feedback + let htmlErrors = this.state.htmlErrors; + if(htmlErrors.length) htmlErrors = Markdown.validate(text); + + this.setState((prevState)=>({ + brew : _.merge({}, prevState.brew, { text: text }), + isPending : true, + htmlErrors : htmlErrors + }), ()=>this.trySave()); + }, + + handleStyleChange : function(style){ + this.setState((prevState)=>({ + brew : _.merge({}, prevState.brew, { style: style }), + isPending : true + }), ()=>this.trySave()); + }, + + handleMetaChange : function(metadata){ + this.setState((prevState)=>({ + brew : _.merge({}, prevState.brew, metadata), + isPending : true, + }), ()=>this.trySave()); + + }, + + hasChanges : function(){ + return !_.isEqual(this.state.brew, this.savedBrew); + }, + + trySave : function(){ + if(!this.debounceSave) this.debounceSave = _.debounce(this.save, SAVE_TIMEOUT); + if(this.hasChanges()){ + this.debounceSave(); + } else { + this.debounceSave.cancel(); + } + }, + + handleGoogleClick : function(){ + if(!global.account?.googleId) { + this.setState({ + alertLoginToTransfer : true + }); + return; + } + this.setState((prevState)=>({ + confirmGoogleTransfer : !prevState.confirmGoogleTransfer + })); + this.clearErrors(); + }, + + closeAlerts : function(event){ + event.stopPropagation(); //Only handle click once so alert doesn't reopen + this.setState({ + alertTrashedGoogleBrew : false, + alertLoginToTransfer : false, + confirmGoogleTransfer : false + }); + }, + + toggleGoogleStorage : function(){ + this.setState((prevState)=>({ + saveGoogle : !prevState.saveGoogle, + isSaving : false, + errors : null + }), ()=>this.save()); + }, + + clearErrors : function(){ + this.setState({ + errors : null, + isSaving : false + + }); + }, + + save : async function(){ + if(this.debounceSave && this.debounceSave.cancel) this.debounceSave.cancel(); + + this.setState((prevState)=>({ + isSaving : true, + errors : null, + htmlErrors : Markdown.validate(prevState.brew.text) + })); + + const transfer = this.state.saveGoogle == _.isNil(this.state.brew.googleId); + + const brew = this.state.brew; + brew.pageCount = ((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1; + + if(this.state.saveGoogle) { + if(transfer) { + const res = await request + .post('/api/newGoogle/') + .send(brew) + .catch((err)=>{ + console.log(err.status === 401 + ? 'Not signed in!' + : 'Error Transferring to Google!'); + this.setState({ errors: err, saveGoogle: false }); + }); + + if(!res) { return; } + + console.log('Deleting Local Copy'); + await request.delete(`/api/${brew.editId}`) + .send() + .catch((err)=>{ + console.log('Error deleting Local Copy'); + }); + + this.savedBrew = res.body; + history.replaceState(null, null, `/edit/${this.savedBrew.googleId}${this.savedBrew.editId}`); //update URL to match doc ID + } else { + const res = await request + .put(`/api/updateGoogle/${brew.editId}`) + .send(brew) + .catch((err)=>{ + console.log(err.status === 401 + ? 'Not signed in!' + : 'Error Saving to Google!'); + this.setState({ errors: err }); + return; + }); + + this.savedBrew = res.body; + } + } else { + if(transfer) { + const res = await request.post('/api') + .send(brew) + .catch((err)=>{ + console.log('Error creating Local Copy'); + this.setState({ errors: err }); + return; + }); + + await request.get(`/api/removeGoogle/${brew.googleId}${brew.editId}`) + .send() + .catch((err)=>{ + console.log('Error Deleting Google Brew'); + }); + + this.savedBrew = res.body; + history.replaceState(null, null, `/edit/${this.savedBrew.editId}`); //update URL to match doc ID + } else { + const res = await request + .put(`/api/update/${brew.editId}`) + .send(brew) + .catch((err)=>{ + console.log('Error Updating Local Brew'); + this.setState({ errors: err }); + return; + }); + + this.savedBrew = res.body; + } + } + + this.setState((prevState)=>({ + brew : _.merge({}, prevState.brew, { + googleId : this.savedBrew.googleId ? this.savedBrew.googleId : null, + editId : this.savedBrew.editId, + shareId : this.savedBrew.shareId + }), + isPending : false, + isSaving : false, + })); + }, + + renderGoogleDriveIcon : function(){ + return + {this.state.saveGoogle + ? googleDriveActive + : googleDriveInactive + } + + {this.state.confirmGoogleTransfer && +
+ { this.state.saveGoogle + ? `Would you like to transfer this brew from your Google Drive storage back to the Homebrewery?` + : `Would you like to transfer this brew from the Homebrewery to your personal Google Drive storage?` + } +
+
+ Yes +
+
+ No +
+
+ } + + {this.state.alertLoginToTransfer && +
+ You must be signed in to a Google account to transfer + between the homebrewery and Google Drive! + +
+ Sign In +
+
+
+ Not Now +
+
+ } +
; + }, + + renderSaveButton : function(){ + if(this.state.errors){ + let errMsg = ''; + try { + errMsg += `${this.state.errors.toString()}\n\n`; + errMsg += `\`\`\`\n${this.state.errors.stack}\n`; + errMsg += `${JSON.stringify(this.state.errors.response.error, null, ' ')}\n\`\`\``; + console.log(errMsg); + } catch (e){} + + if(this.state.errors.status == '401'){ + return + Oops! +
+ You must be signed in to a Google account + to save this to
Google Drive!
+ +
+ Sign In +
+
+
+ Not Now +
+
+
; + } + + if(this.state.errors.status == '403' && this.state.errors.response.body.errors[0].reason == 'insufficientPermissions'){ + return + Oops! +
+ Looks like your Google credentials have + expired! Visit the log in page to sign out + and sign back in with Google + to save this to Google Drive! + +
+ Sign In +
+
+
+ Not Now +
+
+
; + } + + return + Oops! +
+ Looks like there was a problem saving.
+ Report the issue + here + . +
+
; + } + + if(this.state.isSaving){ + return saving...; + } + if(this.state.isPending && this.hasChanges()){ + return Save Now; + } + if(!this.state.isPending && !this.state.isSaving){ + return saved.; + } + }, + + processShareId : function() { + return this.state.brew.googleId ? + this.state.brew.googleId + this.state.brew.shareId : + this.state.brew.shareId; + }, + + getRedditLink : function(){ + + const shareLink = this.processShareId(); + const systems = this.props.brew.systems.length > 0 ? ` [${this.props.brew.systems.join(' - ')}]` : ''; + const title = `${this.props.brew.title} ${systems}`; + const text = `Hey guys! I've been working on this homebrew. I'd love your feedback. Check it out. + +**[Homebrewery Link](https://homebrewery.naturalcrit.com/share/${shareLink})**`; + + return `https://www.reddit.com/r/UnearthedArcana/submit?title=${encodeURIComponent(title)}&text=${encodeURIComponent(text)}`; + }, + + renderNavbar : function(){ + const shareLink = this.processShareId(); + + return + + {this.state.alertTrashedGoogleBrew && +
+ This brew is currently in your Trash folder on Google Drive!
If you want to keep it, make sure to move it before it is deleted permanently!
+
+ OK +
+
+ } + + + {this.state.brew.title} + + + + {this.renderGoogleDriveIcon()} + {this.renderSaveButton()} + + + + + share + + + view + + {navigator.clipboard.writeText(`https://homebrewery.naturalcrit.com/share/${shareLink}`);}}> + copy url + + + post to reddit + + + + + + + +
; + }, + + render : function(){ + return
+ + {this.renderNavbar()} + +
+ + + + +
+
; } }); diff --git a/client/homebrew/pages/newPage/newPage.jsx b/client/homebrew/pages/newPage/newPage.jsx index 0e424a998..3f09cac4e 100644 --- a/client/homebrew/pages/newPage/newPage.jsx +++ b/client/homebrew/pages/newPage/newPage.jsx @@ -3,11 +3,20 @@ require('./newPage.less'); const React = require('react'); const createClass = require('create-react-class'); const _ = require('lodash'); - -const EditorPage = require('../basePages/editorPage/editorPage.jsx'); +const request = require('superagent'); const Markdown = require('naturalcrit/markdown.js'); +const Nav = require('naturalcrit/nav/nav.jsx'); +const Navbar = require('../../navbar/navbar.jsx'); +const AccountNavItem = require('../../navbar/account.navitem.jsx'); +const RecentNavItem = require('../../navbar/recent.navitem.jsx').both; +const IssueNavItem = require('../../navbar/issue.navitem.jsx'); + +const SplitPane = require('naturalcrit/splitPane/splitPane.jsx'); +const Editor = require('../../editor/editor.jsx'); +const BrewRenderer = require('../../brewRenderer/brewRenderer.jsx'); + const BREWKEY = 'homebrewery-new'; const STYLEKEY = 'homebrewery-new-style'; const METAKEY = 'homebrewery-new-meta'; @@ -73,13 +82,238 @@ const NewPage = createClass({ }; }, - render : function(){ - const googleDriveOptions = [ - 'Set save location to the Homebrewery?', - 'Set save location to your personal Google Drive storage?' - ]; + componentDidMount : function() { + document.addEventListener('keydown', this.handleControlKeys); + }, + componentWillUnmount : function() { + document.removeEventListener('keydown', this.handleControlKeys); + }, - return ; + handleControlKeys : function(e){ + if(!(e.ctrlKey || e.metaKey)) return; + const S_KEY = 83; + const P_KEY = 80; + if(e.keyCode == S_KEY) this.save(); + if(e.keyCode == P_KEY) this.print(); + if(e.keyCode == P_KEY || e.keyCode == S_KEY){ + e.stopPropagation(); + e.preventDefault(); + } + }, + + handleSplitMove : function(){ + this.refs.editor.update(); + }, + + handleTextChange : function(text){ + //If there are errors, run the validator on every change to give quick feedback + let htmlErrors = this.state.htmlErrors; + if(htmlErrors.length) htmlErrors = Markdown.validate(text); + + this.setState((prevState)=>({ + brew : _.merge({}, prevState.brew, { text: text }), + htmlErrors : htmlErrors + })); + localStorage.setItem(BREWKEY, text); + }, + + handleStyleChange : function(style){ + this.setState((prevState)=>({ + brew : _.merge({}, prevState.brew, { style: style }), + })); + localStorage.setItem(STYLEKEY, style); + }, + + handleMetaChange : function(metadata){ + this.setState((prevState)=>({ + brew : _.merge({}, prevState.brew, metadata), + })); + localStorage.setItem(METAKEY, JSON.stringify({ + // 'title' : this.state.brew.title, + // 'description' : this.state.brew.description, + 'renderer' : this.state.brew.renderer + })); + }, + + clearErrors : function(){ + this.setState({ + errors : null, + isSaving : false + + }); + }, + + save : async function(){ + this.setState({ + isSaving : true + }); + + console.log('saving new brew'); + + let brew = this.state.brew; + // Split out CSS to Style if CSS codefence exists + if(brew.text.startsWith('```css') && brew.text.indexOf('```\n\n') > 0) { + const index = brew.text.indexOf('```\n\n'); + brew.style = `${brew.style ? `${brew.style}\n` : ''}${brew.text.slice(7, index - 1)}`; + brew.text = brew.text.slice(index + 5); + }; + + brew.pageCount=((brew.renderer=='legacy' ? brew.text.match(/\\page/g) : brew.text.match(/^\\page$/gm)) || []).length + 1; + + if(this.state.saveGoogle) { + const res = await request + .post('/api/newGoogle/') + .send(brew) + .catch((err)=>{ + console.log(err.status === 401 + ? 'Not signed in!' + : 'Error Creating New Google Brew!'); + this.setState({ isSaving: false, errors: err }); + return; + }); + + brew = res.body; + localStorage.removeItem(BREWKEY); + localStorage.removeItem(STYLEKEY); + localStorage.removeItem(METAKEY); + window.location = `/edit/${brew.googleId}${brew.editId}`; + } else { + request.post('/api') + .send(brew) + .end((err, res)=>{ + if(err){ + this.setState({ + isSaving : false + }); + return; + } + window.onbeforeunload = function(){}; + brew = res.body; + localStorage.removeItem(BREWKEY); + localStorage.removeItem(STYLEKEY); + localStorage.removeItem(METAKEY); + window.location = `/edit/${brew.editId}`; + }); + } + }, + + renderSaveButton : function(){ + if(this.state.errors){ + let errMsg = ''; + try { + errMsg += `${this.state.errors.toString()}\n\n`; + errMsg += `\`\`\`\n${this.state.errors.stack}\n`; + errMsg += `${JSON.stringify(this.state.errors.response.error, null, ' ')}\n\`\`\``; + console.log(errMsg); + } catch (e){} + + if(this.state.errors.status == '401'){ + return + Oops! +
+ You must be signed in to a Google account + to save this to
Google Drive!
+ +
+ Sign In +
+
+
+ Not Now +
+
+
; + } + + if(this.state.errors.status == '403' && this.state.errors.response.body.errors[0].reason == 'insufficientPermissions'){ + return + Oops! +
+ Looks like your Google credentials have + expired! Visit the log in page to sign out + and sign back in with Google + to save this to Google Drive! + +
+ Sign In +
+
+
+ Not Now +
+
+
; + } + + return + Oops! +
+ Looks like there was a problem saving.
+ Report the issue + here + . +
+
; + } + + if(this.state.isSaving){ + return + save... + ; + } else { + return + save + ; + } + }, + + print : function(){ + window.open('/print?dialog=true&local=print', '_blank'); + }, + + renderLocalPrintButton : function(){ + return + get PDF + ; + }, + + renderNavbar : function(){ + return + + + {this.state.brew.title} + + + + {this.renderSaveButton()} + {this.renderLocalPrintButton()} + + + + + ; + }, + + render : function(){ + return
+ {this.renderNavbar()} +
+ + + + +
+
; } });